IPUB REVIT adalah perpustakaan untuk mengkonsumsi layanan istirahat dengan cara yang sangat sederhana, hanya menyatakan satu antarmuka dan dibuat oleh tim IPUB.
Anda tidak harus berurusan dengan manipulasi string, pengkodean URL, manipulasi JSON, pengaturan klien. Ini semua dilakukan secara otomatis oleh perpustakaan ini, Anda hanya perlu mendeklarasikan header API REST yang akan dikonsumsi.
Proyek ini menginspirasi / berdasarkan reparasi yang ada di .net, dan mengubah API istirahat Anda menjadi antarmuka langsung:
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 ;Contoh GRESTSERVICE menghasilkan implementasi Igithubapi yang secara internal menggunakan TNETHTTPClient untuk melakukan panggilannya:
var
LGithubApi: IGithubApi;
LUser: TUser;
begin
LGithubApi := GRestService.& For <IGithubApi>;
LUser := LGithubApi.GetUser( ' viniciusfbb ' );
Showmessage(LGithubApi.GetUserJson( ' viniciusfbb ' ));Untuk mendeklarasikan antarmuka API REST, ada dua kewajiban:
Metode antarmuka API REST dapat berupa prosedur atau fungsi yang mengembalikan string, catatan, kelas, array dinamis dari catatan atau array kelas dinamis. Nama metode tidak masalah. Untuk menyatakan Anda harus mendeklarasikan atribut yang menginformasikan jenis metode dan URL relatif Anda harus menyatakan metode jenis metode antarmuka dan URL relatif
[Get( ' /users/{AUser} ' )]
function GetUserJson ( const AUser: string): string;
[Post( ' /users/{AUser}?message={AMessage} ' )]
function GetUserJson ( const AUser, AMessage: string): string;Semua metode standar didukung (dapatkan, posting, hapus, put dan tambalan).
URL relatif dapat memiliki topeng {argument_name/propertie_name}, di mana saja dan dapat mengulangi, untuk menandai di mana argumen atau properti dapat dimasukkan. Rincian lebih lanjut dalam topik berikutnya.
Dalam antarmuka API REST Anda, nama argumen metode akan digunakan untuk mengganti masker {argument_name/propertie_name} dalam url relatif. Pada langkah ini kami mengizinkan nama dan nama yang tidak sensitif tanpa huruf pertama dari nama argumen yang digunakan secara umum dalam bahasa Delphi. Jadi, kasus ini akan memiliki hasil yang sama:
[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; Jika nama argumennya adalah Body , ABody , BodyContent , ABodyContent , Content atau AContent , argumen akan digunakan sebagai tubuh permintaan. Anda juga dapat mendeklarasikan nama lain dan menggunakan atribut [tubuh] dalam argumen ini. Ketika sebuah argumen adalah badan, tidak peduli jenis argumennya, itu akan dilemparkan ke string. Jika itu adalah catatan atau kelas, kami akan membuat serialisasi ke JSON secara otomatis. Ingatlah bahwa mask {argument_name/propertie_name} dalam url relatif, dapat berada di mana saja, termasuk pertanyaan di dalam, dan dapat diulang. Selain itu akan dikodekan secara otomatis, sehingga argumen Anda dapat berupa string dengan spasi, misalnya.
Jenis argumen tidak masalah, kami akan melakukan string secara otomatis. Jadi Anda dapat menggunakan, misalnya, parameter integer:
[Get( ' /users/{AUserId} ' )]
function GetUser ( const AUserId: Integer): string;Anda dapat mendeklarasikan secara opsional URL dasar menggunakan atribut [baseUrl ('xxx')] sebelum antarmuka:
[BaseUrl( ' https://api.github.com ' )]
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
end ;Atau Anda dapat mengatur langsung ketika layanan REST menghasilkan antarmuka API REST baru, ini adalah URL basis pertama yang akan dipertimbangkan layanan:
LGithubApi := GRestService.& For <IGithubApi>( ' https://api.github.com ' );Anda dapat mendeklarasikan header yang diperlukan dalam antarmuka dan metode API. Ke header Deklarasi yang akan digunakan di semua panggilan API, cukup nyatakan di atas antarmuka:
[Headers( ' User-Agent ' , ' Awesome Octocat App ' )]
[Headers( ' Header-A ' , ' 1 ' )]
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
end ;Ke header Deklarasi yang akan digunakan dalam satu metode API, cukup nyatakan di atas metode:
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
[Headers( ' Header-A ' , ' 1 ' )]
[Get( ' /users/{AUser} ' )]
function GetUserJson ( const AUser: string): string;
end ;Catatan: Anda dapat mendeklarasikan banyak atribut [header] dalam satu metode atau dalam satu antarmuka API REST.
Tetapi untuk mendeklarasikan header dinamis, yaitu, tergantung pada argumen atau properti, Anda juga dapat menggunakan topeng {argument_name/propertie_name} pada nilai header. Tetapi ada juga opsi eksklusif lain untuk mendeklarasikan header menggunakan argumen secara langsung. Dalam kasus terakhir ini, Anda perlu mendeklarasikan atribut [header] dalam deklarasi parameter:
IGithubApi = interface (IipRestApi)
[ ' {4C3B546F-216D-46D9-8E7D-0009C0771064} ' ]
[Post( ' /users/{AUser} ' )]
function GetUserJson ( const AUser: string; [Header( ' Authorization ' )] const AAuthToken: string): string;
end ;Dalam antarmuka API REST Anda, Anda juga dapat mendeklarasikan segala jenis properti, asalkan untuk membaca dan menulis dan memiliki Getter dan Setter dengan nama yang sama dengan properti hanya dengan menambahkan "dapatkan" dan "set" sebelumnya. Contoh:
[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 ;Ketika Anda membutuhkan semacam authenticator seperti OAuth1 atau OAuth2, Anda dapat menggunakan komponen asli Delphi seperti ToAuth2Authenticator. Dalam hal ini Anda perlu membuat dan mengkonfigurasi authenticator ini sendiri dan mengaturnya di Authenticator Properti dari Antarmuka API REST Anda (telah dinyatakan dalam antarmuka induk, 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 ;Catatan: Anda perlu menghancurkan authenticator sendiri setelah menggunakannya, layanan REST tidak akan melakukannya secara internal.
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 ;Jenis yang digunakan dalam antarmuka Anda dapat menggunakan atribut JSON secara normal. Semua atribut dari unit system.json.serializers diizinkan. Contoh:
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 ;Jika Anda memiliki tipe khusus, yang perlu dikonversi khusus, Anda dapat membuat penurunan konverter JSON Anda sendiri dari TJSONConverter di System.json.serializers dan mendaftarkannya di Perpustakaan AS:
GRestService.RegisterConverters([TNullableStringConverter]);Anda akan mendaftar hanya satu kali, lebih disukai saat inisialisasi.
Perpustakaan ini tidak mengimplementasikan tipe nullable karena ada beberapa implementasi yang berbeda di Internet, beberapa perpustakaan sudah memiliki tipe nullable sendiri. Tetapi dengan kemungkinan mendaftarkan konverter JSON khusus, mudah untuk mengimplementasikan semua jenis nullable dalam kode untuk digunakan bersama dengan perpustakaan ini. Di sini salah satu contoh dari satu tipe nullable dengan konverter 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 .Sekarang, Anda dapat menggunakan nullable dengan perpustakaan ini seperti:
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 Penting untuk dapat membatalkan permintaan apa pun yang sedang dibuat, terutama sebelum menutup program, karena menunggu total eksekusi dapat memakan waktu beberapa detik dan dengan demikian menunda penutupan program. Untuk itu, kami membuat metode CancelRequest di kelas dasar API (IIPRESTAPI), lalu hubungi:
LGithubApi.CancelRequest;Tetapi ini akan meningkatkan pengecualian untuk permintaan yang sedang berlangsung (eiprestserviceCanceled). Info lebih lanjut dalam topik berikutnya.
Kami memiliki lima pengecualian yang perlu dipertimbangkan saat menggunakan layanan ini
Untuk "membungkam" pengecualian melihat topik berikutnya.
Untuk "membungkam" beberapa pengecualian yang dapat Anda nyatakan "mencoba fungsi" di antarmuka API istirahat Anda. Sangat sederhana, cukup nyatakan fungsi yang dimulai dengan nama "coba" dan kembalikan Boolean. Jika metode ini memiliki hasil, Anda juga dapat mendeklarasikannya dalam parameter dengan bendera "Out". Lihat dua metode yang sama dinyatakan dengan dan tanpa "coba fungsi":
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 ;Sekarang, trygetUser akan "membungkam" pengecualian eiprestserviceCanceled, eiprestservicefailed, eiprestservicejson dan eiprestservicestatuscode.
Antarmuka GRESTSERVICE dan REST API yang dibuat olehnya adalah utas aman.
Karena koneksi sinkron, yang ideal adalah memanggil fungsi API di latar belakang. Jika Anda memiliki beberapa utas, Anda juga dapat membuat beberapa antarmuka API REST untuk API yang sama, masing -masing akan memiliki koneksi yang berbeda.
Perpustakaan ini cross-platform penuh dan dibuat dan diuji pada Delphi Sydney 10.4, tetapi kemungkinan akan bekerja pada versi sebelumnya, mungkin di Delphi 10.2 Tokyo atau yang lebih baru.
IPUB REVIT dilisensikan di bawah MIT, dan file lisensi termasuk dalam folder ini.