iPub 리빗은 매우 간단한 방식으로 휴식 서비스를 소비하여 하나의 인터페이스 만 선언하고 iPub 팀에 의해 만들어지는 라이브러리입니다.
문자열 조작, URL 인코딩, JSON 조작, 클라이언트 설정을 처리 할 필요가 없습니다. 이 라이브러리는 모두 자동으로 수행되므로 소비 될 API REST의 헤더를 선언하면됩니다.
이 프로젝트는 .NET의 기존 리빗을 기반으로 / 영감을 얻었으며 REST API를 라이브 인터페이스로 바꿉니다.
TUser = record
name : string;
location: string;
id: Integer;
end ;
[BaseUrl( ' https://api.github.com ' )]
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
[Get( ' /users/{aUser} ' )]
function GetUser ( const AUser: string): TUser;
[Get( ' /users/{aUser} ' )]
function GetUserJson ( const AUser: string): string;
end ;Grestservice 인스턴스는 내부적으로 tnethttpclient를 사용하여 호출하는 Igithubapi의 구현을 생성합니다.
var
LGithubApi: IGithubApi;
LUser: TUser;
begin
LGithubApi := GRestService.& For <IGithubApi>;
LUser := LGithubApi.GetUser( ' viniciusfbb ' );
Showmessage(LGithubApi.GetUserJson( ' viniciusfbb ' ));나머지 API 인터페이스를 선언하려면 두 가지 의무가 있습니다.
나머지 API 인터페이스의 메소드는 문자열, 레코드, 클래스, 동적 레코드 배열 또는 동적 클래스 배열을 반환하는 프로 시저 또는 함수 일 수 있습니다. 메소드 이름은 중요하지 않습니다. 메소드 종류 및 상대 URL을 알리는 속성을 선언하려면 메소드 종류의 인터페이스 메소드와 상대 URL을 선언해야합니다.
[Get( ' /users/{AUser} ' )]
function GetUserJson ( const AUser: string): string;
[Post( ' /users/{AUser}?message={AMessage} ' )]
function GetUserJson ( const AUser, AMessage: string): string;모든 표준 방법은 지원됩니다 (Get, Post, Delete, Put 및 Patch).
상대 URL에는 인수 나 속성을 삽입 할 수있는 위치를 표시하기 위해 어디서나 마스크 {argument_name/property_name}가 마스크를 가질 수 있으며 반복 할 수 있습니다. 다음 주제에 대한 자세한 내용.
REST API 인터페이스에서 메소드의 인수 이름은 상대 URL에서 마스크 {argument_name/property_name}을 대체하는 데 사용됩니다. 이 단계에서는 델파이 언어로 일반적으로 사용되는 인수 이름의 첫 글자 A가없는 경우 사례의 무감각 이름과 이름을 허용합니다. 따라서이 경우는 동일한 결과를 얻을 수 있습니다.
[Get( ' /users/{AUser} ' )]
function GetUser ( const AUser: string): TUser;
[Get( ' /users/{aUser} ' )]
function GetUser ( const AUser: string): TUser;
[Get( ' /users/{User} ' )]
function GetUser ( const AUser: string): TUser;
[Get( ' /users/{user} ' )]
function GetUser ( const AUser: string): TUser; 인수 이름이 Body , ABody , BodyContent , ABodyContent , Content 또는 AContent 인 경우, 인수는 요청의 본문으로 사용됩니다. 이 인수에서 다른 이름을 선언하고 속성 [본문]을 사용할 수 있습니다. 인수가 신체이면 인수 유형에 관계없이 문자열에 캐스팅됩니다. 레코드 또는 클래스 인 경우 자동으로 JSON으로 직렬화합니다. 상대 URL의 마스크 {argument_name/property_name}은 내부 쿼리를 포함하여 어디서나있을 수 있으며 반복 할 수 있습니다. 또한 자동으로 인코딩되므로 인수는 예를 들어 공백이있는 문자열이 될 수 있습니다.
인수의 유형은 중요하지 않으며 자동으로 문자열로 캐스트합니다. 예를 들어 정수 매개 변수를 사용할 수 있습니다.
[Get( ' /users/{AUserId} ' )]
function GetUser ( const AUserId: Integer): string;인터페이스 전에 속성 [baseUrl ( 'xxx')]을 사용하여 기본 URL을 선택적으로 선언 할 수 있습니다.
[BaseUrl( ' https://api.github.com ' )]
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
end ;또는 REST 서비스가 새로운 REST API 인터페이스를 생성 할 때 직접 설정할 수 있습니다. 서비스에서 고려할 첫 번째 기본 URL입니다.
LGithubApi := GRestService.& For <IGithubApi>( ' https://api.github.com ' );API 인터페이스 및 메소드에서 필요한 헤더를 선언 할 수 있습니다. 모든 API 호출에 사용될 선언 헤더의 경우 인터페이스 위에 선언하십시오.
[Headers( ' User-Agent ' , ' Awesome Octocat App ' )]
[Headers( ' Header-A ' , ' 1 ' )]
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
end ;하나의 API 메소드에 사용될 선언 헤더에 다음과 같은 방법을 선언하십시오.
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
[Headers( ' Header-A ' , ' 1 ' )]
[Get( ' /users/{AUser} ' )]
function GetUserJson ( const AUser: string): string;
end ;참고 : 하나의 메소드 또는 하나의 REST API 인터페이스에서 많은 [헤더] 속성을 선언 할 수 있습니다.
그러나 동적 헤더, 즉 인수 또는 속성에 따라 헤더 값에서 {argument_name/property_name} 마스크를 사용할 수도 있습니다. 그러나 인수를 직접 사용하여 헤더를 선언하는 또 다른 독점 옵션도 있습니다. 이 마지막 경우 매개 변수 선언에서 [헤더] 속성을 선언해야합니다.
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
[Post( ' /users/{AUser} ' )]
function GetUserJson ( const AUser: string; [Header( ' Authorization ' )] const AAuthToken: string): string;
end ;REST API 인터페이스에서는 읽기 및 쓰기에 대한 한 모든 종류의 속성을 선언 할 수 있으며 미리 "get"및 "set"을 추가하여 속성과 동일한 이름을 가진 Getter and Setter가 있습니다. 예:
[BaseUrl( ' https://maps.googleapis.com ' )]
IipGoogleGeocoding = interface (IipRestApi)
[ ' {668C5505-F90D-43C0-9545-038A86472666} ' ]
[Get( ' /maps/api/geocode/json?address={AAddress}&key={ApiKey} ' )]
function AddressToGeolocation ( const AAddress: string): string;
[Get( ' /maps/api/geocode/json?latlng={ALatitude},{ALongitude}&key={ApiKey} ' )]
function GeolocationToAddress ( const ALatitude, ALongitude: Double): string;
function GetApiKey : string;
procedure SetApiKey ( const AValue: string);
property ApiKey: string read GetApiKey write SetApiKey;
end ;
procedure TForm1.FormCreate (Sender: TObject);
var
LGoogleGeocodingApi: IipGoogleGeocoding;
LGeolocationResponse: string;
LAddressResponse: string;
begin
LGoogleGeocodingApi := GRestService.& For <IipGoogleGeocoding>;
LGoogleGeocodingApi.ApiKey := ' XXXXXXX ' ;
LGeolocationResponse := LGoogleGeocodingApi.AddressToGeolocation( ' Rua Alexandre Dumas, 1562, Chácara Santo Antônio, São Paulo - SP, Brasil ' );
LAddressResponse := LGoogleGeocodingApi.GeolocationToAddress(- 23.6312393 , - 46.7058503 );
end ;OAUTH1 또는 OAUTH2와 같은 일종의 인증자가 필요한 경우 Delphi의 기본 구성 요소를 Touth2authenticator를 사용할 수 있습니다. 이 경우 자체적 으로이 인증기를 작성하고 구성하여 REST API 인터페이스의 속성 인증 자에 설정해야합니다 (IIPRESTAPI, 부모 인터페이스에서 선언 됨).
var
LOAuth2: TOAuth2Authenticator;
LGithubApi: IGithubApi;
begin
LOAuth2 := TOAuth2Authenticator.Create( nil );
try
// Configure the LOAuth2
...
LGithubApi := GRestService.& For <IGithubApi>;
LGithubApi.Authenticator := LOAuth2;
Showmessage(LGithubApi.GetUserJson( ' viniciusfbb ' ));
finally
LOAuth2.Free;
end ;
end ;참고 : 당신은 그것을 사용한 후에 자신의 인증자를 스스로 파괴해야하며, 나머지 서비스는 내부적으로 수행하지 않습니다.
uses
iPub.Rtl.Refit;
type
TUser = record
Name : string;
Location: string;
Id: Integer;
end ;
TRepository = record
Name : string;
Full_Name: string;
Fork: Boolean;
Description: string;
end ;
TIssue = record
public
type
TUser = record
Login: string;
Id: Integer;
end ;
TLabel = record
Name : string;
Color: string;
end ;
public
Url: string;
Title: string;
User: TIssue.TUser;
Labels: TArray<TIssue.TLabel>;
State: string;
Body: string;
end ;
[BaseUrl( ' https://api.github.com ' )]
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
[Get( ' /users/{user} ' )]
function GetUser ( const AUser: string): TUser;
[Get( ' /users/{user}/repos ' )]
function GetUserRepos ( const AUser: string): TArray<TRepository>;
[Get( ' /repos/{repositoryOwner}/{repositoryName}/issues?page={page} ' )]
function GetRepositoryIssues ( const ARepositoryOwner, ARepositoryName: string; APage: Integer = 1 ): TArray<TIssue>;
[Get( ' /repos/{repositoryOwner}/{repositoryName}/issues?page={page}&state=open ' )]
function GetRepositoryIssuesOpen ( const ARepositoryOwner, ARepositoryName: string; APage: Integer = 1 ): TArray<TIssue>;
end ;
procedure TForm1.FormCreate (Sender: TObject);
var
LGithubApi: IGithubApi;
LUser: TUser;
LRepos: TArray<TRepository>;
LIssues: TArray<TIssue>;
begin
LGithubApi := GRestService.& For <IGithubApi>;
LUser := LGithubApi.GetUser( ' viniciusfbb ' );
LRepos := LGithubApi.GetUserRepos( ' viniciusfbb ' );
LIssues := LGithubApi.GetRepositoryIssues( ' rails ' , ' rails ' );
LIssues := LGithubApi.GetRepositoryIssuesOpen( ' rails ' , ' rails ' , 2 );
end ;인터페이스에 사용 된 유형은 JSON 속성을 정상적으로 사용할 수 있습니다. 단위 System.json.serializers의 모든 속성이 허용됩니다. 예:
uses
iPub.Rtl.Refit, System.JSON.Serializers;
type
TRepository = record
Name : string;
[JsonName( ' full_name ' )] FullName: string;
Fork: Boolean;
Description: string;
end ;
[BaseUrl( ' https://api.github.com ' )]
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
[Get( ' /users/{user}/repos ' )]
function GetUserRepos ( const AUser: string): TArray<TRepository>;
end ;
procedure TForm1.FormCreate (Sender: TObject);
var
LGithubApi: IGithubApi;
LRepos: TArray<TRepository>;
begin
LGithubApi := GRestService.& For <IGithubApi>;
LRepos := LGithubApi.GetUserRepos( ' viniciusfbb ' );
end ;사용자 정의 변환이 필요한 특수 유형이있는 경우 System.json.serializers에서 TJSONCONVERTER의 JSON 변환기 후손을 만들어 미국 라이브러리에 등록 할 수 있습니다.
GRestService.RegisterConverters([TNullableStringConverter]);초기화시 한 번만 등록합니다.
이 라이브러리는 인터넷에 여러 가지 구현이 있기 때문에 무효 유형을 구현하지 않습니다. 여러 라이브러리에는 이미 고유 한 유형이 있습니다. 그러나 사용자 정의 JSON 변환기를 등록 할 수 있으므로이 라이브러리와 함께 사용할 수있는 모든 유형의 무효가 될 수 있습니다. JSON 변환기가있는 하나의 무효 유형의 한 예 :
unit ExampleOfNullables;
interface
uses
System.Rtti, System.TypInfo, System.JSON.Serializers, System.JSON.Readers,
System.JSON.Writers, System.JSON.Types, iPub.Rtl.Refit;
type
TNullable<T> = record
strict private
FIsNotNull: Boolean;
function GetIsNull : Boolean;
procedure SetIsNull (AValue: Boolean);
public
Value : T;
property IsNull: Boolean read GetIsNull write SetIsNull;
end ;
implementation
type
TNullableConverter<T> = class (TJsonConverter)
public
procedure WriteJson ( const AWriter: TJsonWriter; const AValue: TValue; const ASerializer: TJsonSerializer); override;
function ReadJson ( const AReader: TJsonReader; ATypeInf: PTypeInfo; const AExistingValue: TValue;
const ASerializer: TJsonSerializer): TValue; override;
function CanConvert (ATypeInf: PTypeInfo): Boolean; override;
end ;
{ TNullable<T> }
function TNullable <T>.GetIsNull: Boolean;
begin
Result := not FIsNotNull;
end ;
procedure TNullable <T>.SetIsNull(AValue: Boolean);
begin
FIsNotNull := not AValue;
end ;
{ TNullableConverter<T> }
function TNullableConverter <T>.CanConvert(ATypeInf: PTypeInfo): Boolean;
begin
Result := ATypeInf = TypeInfo(TNullable<T>);
end ;
function TNullableConverter <T>.ReadJson( const AReader: TJsonReader;
ATypeInf: PTypeInfo; const AExistingValue: TValue;
const ASerializer: TJsonSerializer): TValue;
var
LNullable: TNullable<T>;
begin
if AReader.TokenType = TJsonToken.Null then
begin
LNullable.IsNull := True;
LNullable. Value := Default(T);
end
else
begin
LNullable.IsNull := False;
LNullable. Value := AReader. Value .AsType<T>;
end ;
TValue.Make(@LNullable, TypeInfo(TNullable<T>), Result);
end ;
procedure TNullableConverter <T>.WriteJson( const AWriter: TJsonWriter;
const AValue: TValue; const ASerializer: TJsonSerializer);
var
LNullable: TNullable<T>;
LValue: TValue;
begin
LNullable := AValue.AsType<TNullable<T>>;
if LNullable.IsNull then
AWriter.WriteNull
else
begin
TValue.Make(@LNullable. Value , TypeInfo(T), LValue);
AWriter.WriteValue(LValue);
end ;
end ;
initialization
GRestService.RegisterConverters([TNullableConverter<string>,
TNullableConverter<Byte>, TNullableConverter<Word>,
TNullableConverter<Integer>, TNullableConverter<Cardinal>,
TNullableConverter<Single>, TNullableConverter<Double>,
TNullableConverter<Int64>, TNullableConverter<UInt64>,
TNullableConverter<TDateTime>, TNullableConverter<Boolean>,
TNullableConverter<Char>]);
end .이제이 라이브러리와 같은 Nullable을 사용할 수 있습니다.
uses
iPub.Rtl.Refit, ExampleOfNullables;
type
TUser = record
Name : TNullable<string>;
Location: string;
Id: Integer;
Email: TNullable<string>;
end ;
[BaseUrl( ' https://api.github.com ' )]
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
[Get( ' /users/{user} ' )]
function GetUser ( const AUser: string): TUser;
end ;
// ...
var
LGithubApi: IGithubApi;
LUser: TUser;
begin
LGithubApi := GRestService.& For <IGithubApi>;
LUser := LGithubApi.GetUser( ' viniciusfbb ' );
// Now you will see that LUser.Name.IsNull = False but the LUser.Email.IsNull = True 총 실행을 기다리는 데는 몇 초가 걸리고 프로그램 마감을 지연시킬 수 있기 때문에 특히 프로그램을 폐쇄하기 전에 작성중인 요청을 취소 할 수 있어야합니다. 이를 위해 API Base Class (IIPRESTAPI)에서 CancelRequest 메소드를 작성한 다음 전화를 걸었습니다.
LGithubApi.CancelRequest;그러나 이것은 진행중인 요청에 대한 예외를 제기 할 것입니다 (eiprestservicecanceled). 다음 주제에 대한 추가 정보.
서비스를 사용할 때 고려해야 할 5 가지 예외가 있습니다.
"침묵"하는 것은 다음 주제를 예외로합니다.
"침묵"하려면 일부 예외는 REST API 인터페이스에서 "기능 시도"를 선언 할 수 있습니다. 매우 간단합니다. "시도"이름과 반환 부울로 시작하는 기능을 선언합니다. 메소드에 결과가있는 경우 "Out"플래그를 사용하여 매개 변수로 선언 할 수도 있습니다. "시도 시도"유무에 관계없이 선언 된 동일한 두 가지 방법을 참조하십시오.
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
[Get( ' /users/{user} ' )]
function GetUser ( const AUser: string): TUser;
[Get( ' /users/{user} ' )]
function TryGetUser ( const AUser: string; out AResult: TUser): Boolean;
end ;이제 TryGetUser는 EIPRESTSERVICECANCELED, EIPRESTSERVICEFAILED, EIPRESTSERVICEJSON 및 EIPRESTSERVICESTATUSCODE의 예외를 "침묵"할 것입니다.
Grestservice 및 REST API 인터페이스는 스레드 안전합니다.
연결이 동기식이므로 이상은 백그라운드에서 API 기능을 호출하는 것입니다. 여러 스레드가있는 경우 동일한 API에 대한 여러 REST API 인터페이스를 만들 수도 있습니다. 각 스레드는 서로 다른 연결을 가질 수 있습니다.
이 라이브러리는 전체 크로스 플랫폼으로 델파이 시드니 10.4에서 만들어지고 테스트되었지만 이전 버전, 아마도 델파이 10.2 도쿄 또는 새로운 버전에서 작동 할 가능성이 높습니다.
iPub refit은 MIT에 따라 라이센스가 부여되며 라이센스 파일은이 폴더에 포함되어 있습니다.