Introductie tot retrofit

1. Overzicht

Retrofit is een typeveilige HTTP-client voor Android en Java - ontwikkeld door Square (Dagger, Okhttp).

In dit artikel gaan we uitleggen hoe u Retrofit kunt gebruiken, met de nadruk op de meest interessante functies. Meer in het bijzonder bespreken we de synchrone en asynchrone API, hoe deze te gebruiken met authenticatie, logboekregistratie en enkele goede modelleringspraktijken.

2. Het voorbeeld opstellen

We beginnen met het toevoegen van de Retrofit-bibliotheek en de Gson-converter:

 com.squareup.retrofit2 retrofit 2.3.0 com.squareup.retrofit2 converter-gson 2.3.0 

Kijk voor de nieuwste versies bij Retrofit en converter-gson op de Maven Central-repository.

3. API-modellering

Pas modellen REST-eindpunten toe als Java-interfaces, waardoor ze heel eenvoudig te begrijpen en te gebruiken zijn.

We modelleren de gebruikers-API vanuit GitHub; dit heeft een KRIJGEN eindpunt dat dit retourneert in JSON-indeling:

{login: "mojombo", id: 1, url: "//api.github.com/users/mojombo", ...}

Retrofit werkt door te modelleren over een basis-URL en door interfaces de entiteiten van het REST-eindpunt te laten retourneren.

Voor de eenvoud gaan we een klein deel van de JSON gebruiken door onze Gebruiker klasse die de waarden gaat aannemen wanneer we ze hebben ontvangen:

openbare klasse Gebruiker {privé String-login; privé lange id; privé String url; // ... // standard getters an setters}

We kunnen zien dat we voor dit voorbeeld slechts een subset van eigenschappen gebruiken. Retrofit zal niet klagen over ontbrekende eigendommen - omdat het alleen in kaart brengt wat we nodig hebben, het zal niet eens klagen als we eigenschappen zouden toevoegen die niet in de JSON staan.

Nu kunnen we naar de interfacemodellering gaan en enkele van de Retrofit-annotaties uitleggen:

openbare interface UserService {@GET ("/ users") openbare oproep getUsers (@Query ("per_page") int per_page, @Query ("page") int-pagina); @GET ("/ gebruikers / {gebruikersnaam}") openbare oproep getUser (@Path ("gebruikersnaam") String gebruikersnaam); }

De metadata voorzien van annotaties is voldoende om de tool werkende implementaties te laten genereren.

De @KRIJGEN annotatie vertelt de client welke HTTP-methode moet worden gebruikt en op welke bron, dus door bijvoorbeeld de basis-URL "//api.github.com" op te geven, wordt het verzoek verzonden naar "//api.github.com/users" .

De leidende "/" op onze relatieve URL vertelt Retrofit dat het een absoluut pad op de host is.

Een ander ding om op te merken is dat we volledig optioneel gebruiken @Query parameters, die als null kunnen worden doorgegeven als we ze niet nodig hebben, zorgt de tool ervoor dat deze parameters worden genegeerd als ze geen waarden hebben.

Tenslotte, @Pad laten we een padparameter specificeren die zal worden geplaatst in plaats van de opmaak die we in het pad hebben gebruikt.

4. Synchrone / asynchrone API

Om een ​​HTTP-verzoekoproep te maken, moeten we eerst ons Retrofit-object bouwen:

OkHttpClient.Builder httpClient = nieuwe OkHttpClient.Builder (); Retrofit retrofit = nieuwe Retrofit.Builder () .baseUrl ("// api.github.com/") .addConverterFactory (GsonConverterFactory.create ()) .client (httpClient.build ()) .build ();

Retrofit biedt een handige bouwer voor het construeren van ons gewenste object. Het heeft de basis-URL nodig die wordt gebruikt voor elke serviceaanvraag en een converterfabriek - die zorgt voor het parseren van de gegevens die we verzenden en ook voor de reacties die we krijgen.

In dit voorbeeld gaan we de GsonConverterFactory, die onze JSON-gegevens gaat toewijzen aan het Gebruiker klasse die we eerder hebben gedefinieerd.

Het is belangrijk op te merken dat verschillende fabrieken verschillende doelen dienen, dus houd er rekening mee dat we ook fabrieken kunnen gebruiken voor XML, proto-buffers of er zelfs een kunnen maken voor een aangepast protocol. Voor een lijst van reeds geïmplementeerde fabrieken kunnen we hier kijken.

De laatste afhankelijkheid is OKHttpClient - dat is een HTTP & HTTP / 2-client voor Android- en Java-applicaties. Dit zorgt voor de verbinding met de server en het verzenden en ophalen van informatie. We kunnen ook headers en interceptors toevoegen voor elke oproep, die we gaan zien in onze authenticatiesectie.

Nu we ons Retrofit-object hebben, kunnen we onze servicecall opbouwen, laten we eens kijken hoe we dit op de synchrone manier kunnen doen:

UserService-service = retrofit.create (UserService.class); Bel callSync = service.getUser ("eugenp"); probeer {Response response = callSync.execute (); Gebruiker gebruiker = response.body (); } catch (uitzondering ex) {...}

Hier kunnen we zien hoe Retrofit zorgt voor de constructie van onze service-interface door de code te injecteren die nodig is om het verzoek te doen, op basis van onze eerdere annotaties.

Daarna krijgen we een Bel object dat wordt gebruikt voor het uitvoeren van het verzoek naar de GitHub API. De belangrijkste methode hier is uitvoeren, die wordt gebruikt om een ​​oproep synchroon uit te voeren en de huidige thread blokkeert tijdens het overdragen van de gegevens.

Nadat de aanroep met succes is uitgevoerd, kunnen we de hoofdtekst van het antwoord - al op een gebruikersobject - ophalen dankzij onze GsonConverterFactory.

Een synchroon gesprek voeren is heel eenvoudig, maar meestal gebruiken we een niet-blokkerend asynchroon verzoek:

UserService-service = retrofit.create (UserService.class); Bel callAsync = service.getUser ("eugenp"); callAsync.enqueue (nieuwe Callback () {@Override public void onResponse (Call call, Response response) {User user = response.body ();} @Override public void onFailure (Call call, Throwable throwable) {System.out.println (werpbaar);}});

Nu gebruiken we in plaats van de execute-methode de in de wachtrij plaatsen methode - waarvoor een Bel teruginterface als een parameter om het slagen of mislukken van het verzoek af te handelen. Merk op dat dit wordt uitgevoerd in een aparte thread.

Nadat het gesprek met succes is beëindigd, kunnen we het lichaam op dezelfde manier ophalen als voorheen.

5. Herbruikbaar maken ServiceGenerator Klasse

Nu we hebben gezien hoe we ons Retrofit-object moeten construeren en hoe we een API kunnen gebruiken, kunnen we zien dat we de builder niet steeds opnieuw willen schrijven.

Wat we willen is een herbruikbare klasse waarmee we dit object een keer kunnen maken en opnieuw kunnen gebruiken gedurende de levensduur van onze applicatie:

openbare klasse GitHubServiceGenerator {privé statische laatste String BASE_URL = "//api.github.com/"; privé statische Retrofit.Builder-builder = nieuwe Retrofit.Builder () .baseUrl (BASE_URL) .addConverterFactory (GsonConverterFactory.create ()); privé statische Retrofit retrofit = builder.build (); privé statische OkHttpClient.Builder httpClient = nieuwe OkHttpClient.Builder (); openbare statische S createService (Class serviceClass) {retrofit.create retourneren (serviceClass); }}

Alle logica voor het maken van het Retrofit-object is hier nu naartoe verplaatst GitHubServiceGenerator class, dit maakt het een duurzame client class die voorkomt dat de code zich herhaalt.

Hier is een eenvoudig voorbeeld van hoe u het kunt gebruiken:

UserService-service = GitHubServiceGenerator.createService (UserService.class);

Als we nu bijvoorbeeld een RepositoryService, we zouden deze klasse kunnen hergebruiken en de creatie kunnen vereenvoudigen.

In de volgende sectie, gaan we het uitbreiden en authenticatiemogelijkheden toevoegen.

6. Authenticatie

De meeste API's hebben enige authenticatie om de toegang ertoe te beveiligen.

Rekening houdend met onze vorige generatorklasse, gaan we een create-servicemethode toevoegen, die een JWT-token nodig heeft met de Autorisatie koptekst:

openbare statische S createService (Class serviceClass, laatste String-token) {if (token! = null) {httpClient.interceptors (). clear (); httpClient.addInterceptor (chain -> {Request original = chain.request (); Request request = original.newBuilder () .header ("Authorization", token) .build (); return chain.proceed (request);}); builder.client (httpClient.build ()); retrofit = builder.build (); } retrofit.create retourneren (serviceClass); }

Om een ​​header aan ons verzoek toe te voegen, moeten we de interceptormogelijkheden van OkHttp; we doen dit door onze eerder gedefinieerde builder te gebruiken en door het Retrofit-object te reconstrueren.

Merk op dat dit een eenvoudig auth-voorbeeld is, maar met het gebruik van interceptors kunnen we elke authenticatie gebruiken, zoals OAuth, gebruiker / wachtwoord, enz.

7. Logboekregistratie

In deze sectie gaan we onze GitHubServiceGenerator voor logging-mogelijkheden, die erg belangrijk zijn voor foutopsporingsdoeleinden in elk project.

We gaan onze eerdere kennis van interceptors gebruiken, maar we hebben een extra afhankelijkheid nodig, namelijk de HttpLoggingInterceptor van OkHttp, laten we het toevoegen aan ons pom.xml:

 com.squareup.okhttp3 logging-interceptor 3.9.0 

Laten we nu onze GitHubServiceGenerator klas:

openbare klasse GitHubServiceGenerator {privé statische laatste String BASE_URL = "//api.github.com/"; privé statische Retrofit.Builder-builder = nieuwe Retrofit.Builder () .baseUrl (BASE_URL) .addConverterFactory (GsonConverterFactory.create ()); privé statische Retrofit retrofit = builder.build (); privé statische OkHttpClient.Builder httpClient = nieuwe OkHttpClient.Builder (); privé statische HttpLoggingInterceptor logging = nieuwe HttpLoggingInterceptor () .setLevel (HttpLoggingInterceptor.Level.BASIC); openbare statische S createService (Class serviceClass) {if (! httpClient.interceptors (). bevat (logging)) {httpClient.addInterceptor (logging); builder.client (httpClient.build ()); retrofit = builder.build (); } retrofit.create retourneren (serviceClass); } openbare statische S createService (Class serviceClass, laatste String-token) {if (token! = null) {httpClient.interceptors (). clear (); httpClient.addInterceptor (chain -> {Request original = chain.request (); Request.Builder builder1 = original.newBuilder () .header ("Authorization", token); Request request = builder1.build (); return chain.proceed (verzoek); }); builder.client (httpClient.build ()); retrofit = builder.build (); } retrofit.create retourneren (serviceClass); }}

Dit is de laatste vorm van onze klas, we kunnen zien hoe we de HttpLoggingInterceptor, en we stellen het in voor basislogboekregistratie, wat de tijd die het kostte om het verzoek te doen, het eindpunt, de status voor elk verzoek, enz. gaat loggen.

Het is belangrijk om te kijken hoe we controleren of de interceptor bestaat, zodat we deze niet per ongeluk twee keer toevoegen.

8. Conclusie

In deze uitgebreide gids hebben we de uitstekende Retrofit-bibliotheek bekeken door ons te concentreren op de Sync / Async API, enkele best practices voor modellering, authenticatie en logboekregistratie.

De bibliotheek kan op zeer complexe en nuttige manieren worden gebruikt; Bekijk deze tutorial voor een gevorderde use case met RxJava.

En, zoals altijd, is de broncode te vinden op GitHub.