Introduction à la modernisation

1. Vue d'ensemble

Retrofit est un client HTTP de type sécurisé pour Android et Java - développé par Square (Dagger, Okhttp).

Dans cet article, nous allons vous expliquer comment utiliser Retrofit, en mettant l'accent sur ses fonctionnalités les plus intéressantes. Plus particulièrement, nous discuterons de l'API synchrone et asynchrone, comment l'utiliser avec l'authentification, la journalisation et quelques bonnes pratiques de modélisation.

2. Configuration de l'exemple

Nous allons commencer par ajouter la bibliothèque Retrofit et le convertisseur Gson:

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

Pour les dernières versions, jetez un œil à Retrofit et Converter-gson sur le référentiel Maven Central.

3. Modélisation API

La modernisation modélise les points de terminaison REST comme des interfaces Java, ce qui les rend très simples à comprendre et à utiliser.

Nous modéliserons l'API utilisateur à partir de GitHub; cela a un point de terminaison GET qui renvoie ceci au format JSON:

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

La modernisation fonctionne en modélisant sur une URL de base et en faisant en sorte que les interfaces renvoient les entités à partir du point de terminaison REST.

Pour des raisons de simplicité, nous allons prendre une petite partie du JSON en modélisant notre classe User qui va prendre les valeurs lorsque nous les aurons reçues:

public class User { private String login; private long id; private String url; // ... // standard getters an setters }

Nous pouvons voir que nous ne prenons qu'un sous-ensemble de propriétés pour cet exemple. La modernisation ne se plaindra pas des propriétés manquantes - puisqu'elle ne correspond que ce dont nous avons besoin , elle ne se plaindra même pas si nous devions ajouter des propriétés qui ne sont pas dans le JSON.

Nous pouvons maintenant passer à la modélisation de l'interface et expliquer certaines des annotations de retrofit:

public interface UserService { @GET("/users") public Call
    
      getUsers( @Query("per_page") int per_page, @Query("page") int page); @GET("/users/{username}") public Call getUser(@Path("username") String username); }
    

Les métadonnées fournies avec les annotations suffisent à l'outil pour générer des implémentations fonctionnelles.

L' annotation @GET indique au client quelle méthode HTTP utiliser et sur quelle ressource, par exemple, en fournissant une URL de base de «//api.github.com», il enverra la requête à «//api.github.com /utilisateurs".

Le premier «/» sur notre URL relative indique à Retrofit qu'il s'agit d'un chemin absolu sur l'hôte.

Une autre chose à noter est que nous utilisons des paramètres @Query complètement optionnels , qui peuvent être passés comme null si nous n'en avons pas besoin, l'outil se chargera d'ignorer ces paramètres s'ils n'ont pas de valeurs.

Enfin, @Path nous permet de spécifier un paramètre de chemin qui sera placé à la place du balisage que nous avons utilisé dans le chemin.

4. API synchrone / asynchrone

Pour construire un appel de requête HTTP, nous devons d'abord créer notre objet Retrofit:

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

Retrofit fournit un constructeur pratique pour construire notre objet requis. Il a besoin de l'URL de base qui sera utilisée pour chaque appel de service et d'une usine de conversion - qui s'occupe de l'analyse des données que nous envoyons et des réponses que nous obtenons.

Dans cet exemple, nous allons utiliser GsonConverterFactory , qui va mapper nos données JSON à la classe User que nous avons définie précédemment.

Il est important de noter que différentes usines ont des objectifs différents, alors gardez à l'esprit que nous pouvons également utiliser des usines pour XML, des proto-tampons ou même en créer une pour un protocole personnalisé. Pour une liste des usines déjà implantées, nous pouvons jeter un œil ici.

La dernière dépendance est OKHttpClient - qui est un client HTTP et HTTP / 2 pour les applications Android et Java. Cela va prendre en charge la connexion au serveur et l'envoi et la récupération des informations. Nous pourrions également ajouter des en-têtes et des intercepteurs pour chaque appel, ce que nous allons voir dans notre section d'authentification.

Maintenant que nous avons notre objet Retrofit, nous pouvons construire notre appel de service, voyons comment procéder de manière synchrone:

UserService service = retrofit.create(UserService.class); Call callSync = service.getUser("eugenp"); try { Response response = callSync.execute(); User user = response.body(); } catch (Exception ex) { ... }

Ici, nous pouvons voir comment Retrofit prend en charge la construction de notre interface de service en injectant le code nécessaire pour faire la demande, sur la base de nos annotations précédentes.

Après cela, nous obtenons un objet Call qui est celui utilisé pour exécuter la requête à l'API GitHub. La méthode la plus importante ici est execute , qui est utilisée pour exécuter un appel de manière synchrone et bloquera le thread en cours lors du transfert des données.

Une fois l'appel exécuté avec succès, nous pouvons récupérer le corps de la réponse - déjà sur un objet utilisateur - grâce à notre GsonConverterFactory .

Faire un appel synchrone est très simple, mais généralement, nous utilisons une requête asynchrone non bloquante:

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

Maintenant, au lieu de la méthode execute, nous utilisons la méthode enqueue - qui prend une interface de rappel comme paramètre pour gérer le succès ou l'échec de la demande. Notez que cela s'exécutera dans un thread séparé.

Une fois l'appel terminé, nous pouvons récupérer le corps de la même manière que nous l'avons fait précédemment.

5. Créer une classe ServiceGenerator réutilisable

Maintenant que nous avons vu comment construire notre objet Retrofit et comment consommer une API, nous pouvons voir que nous ne voulons pas continuer à écrire le constructeur encore et encore.

Ce que nous voulons, c'est une classe réutilisable qui nous permet de créer cet objet une fois et de le réutiliser pour la durée de vie de notre application:

public class GitHubServiceGenerator { private static final String BASE_URL = "//api.github.com/"; private static Retrofit.Builder builder = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()); private static Retrofit retrofit = builder.build(); private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); public static  S createService(Class serviceClass) { return retrofit.create(serviceClass); } }

Toute la logique de création de l'objet Retrofit est maintenant déplacée vers cette classe GitHubServiceGenerator , cela en fait une classe client durable qui empêche le code de se répéter.

Voici un exemple simple de son utilisation:

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

Maintenant, si nous devions, par exemple, créer un RepositoryService, nous pourrions réutiliser cette classe et simplifier la création.

Dans la section suivante , nous allons l'étendre et ajouter des capacités d'authentification.

6. Authentification

La plupart des API disposent d'une authentification pour en sécuriser l'accès.

En tenant compte de notre classe de générateur précédente, nous allons ajouter une méthode de création de service, qui prend un jeton JWT avec l'en- tête Authorization :

public static  S createService(Class serviceClass, final 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(); } return retrofit.create(serviceClass); }

Pour ajouter un en-tête à notre requête, nous devons utiliser les capacités d'intercepteur d' OkHttp ; nous faisons cela en utilisant notre générateur précédemment défini et en reconstruisant l'objet Retrofit.

Notez qu'il s'agit d'un exemple d'authentification simple, mais avec l'utilisation d'intercepteurs, nous pouvons utiliser n'importe quelle authentification telle que OAuth, utilisateur / mot de passe, etc.

7. Journalisation

Dans cette section, nous allons étendre davantage notre GitHubServiceGenerator pour les capacités de journalisation, qui sont très importantes à des fins de débogage dans chaque projet.

Nous allons utiliser nos connaissances antérieures sur les intercepteurs, mais nous avons besoin d'une dépendance supplémentaire, qui est le HttpLoggingInterceptor d'OkHttp, ajoutons-le à notre pom.xml :

 com.squareup.okhttp3 logging-interceptor 3.9.0 

Maintenant, étendons notre classe GitHubServiceGenerator :

public class GitHubServiceGenerator { private static final String BASE_URL = "//api.github.com/"; private static Retrofit.Builder builder = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()); private static Retrofit retrofit = builder.build(); private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); private static HttpLoggingInterceptor logging = new HttpLoggingInterceptor() .setLevel(HttpLoggingInterceptor.Level.BASIC); public static  S createService(Class serviceClass) { if (!httpClient.interceptors().contains(logging)) { httpClient.addInterceptor(logging); builder.client(httpClient.build()); retrofit = builder.build(); } return retrofit.create(serviceClass); } public static  S createService(Class serviceClass, final 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(request); }); builder.client(httpClient.build()); retrofit = builder.build(); } return retrofit.create(serviceClass); } }

C'est la forme finale de notre classe, nous pouvons voir comment nous avons ajouté le HttpLoggingInterceptor , et nous le définissons pour la journalisation de base, qui va consigner le temps nécessaire pour faire la requête, le point de terminaison, l'état de chaque requête, etc.

Il est important de regarder comment nous vérifions si l'intercepteur existe, afin de ne pas l'ajouter accidentellement deux fois.

8. Conclusion

Dans ce guide complet, nous avons examiné l'excellente bibliothèque Retrofit en nous concentrant sur son API Sync / Async, quelques bonnes pratiques de modélisation, d'authentification et de journalisation.

La bibliothèque peut être utilisée de manière très complexe et utile; pour un cas d'utilisation avancé avec RxJava, veuillez consulter ce tutoriel.

Et, comme toujours, le code source peut être trouvé sur GitHub.