Introduction à la modernisation

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 aborderons l'API synchrone et asynchrone, comment l'utiliser avec l'authentification, la journalisation et quelques bonnes pratiques de modélisation.

2. Mise en place 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 etconverter-gson sur le référentiel Maven Central.

3. Modélisation d'API

Retrofit modélise les points de terminaison REST sous forme d'interfaces Java, ce qui les rend très simples à comprendre et à consommer.

Nous modéliserons lesuser API de GitHub; ceci a un point de terminaisonGET qui renvoie ceci au format JSON:

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

La mise à niveau fonctionne en modélisant 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 classeUser qui prendra 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. Retrofit won’t complain about missing properties – since it only maps what we need, il ne se plaindra même pas si nous ajoutions des propriétés qui ne sont pas dans le JSON.

Nous pouvons maintenant passer à la modélisation d’interface et expliquer certaines des annotations 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 «https://api.github.com», il enverra la requête à «https: //api.github.com/users ».

Le premier «/» de notre URL relativetells Retrofit that it is an absolute path on the host.

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 permet de spécifier un paramètre de chemin qui sera placé à la place du balisage que nous avons utilisé dans le chemin.

4. Synchronous/Asynchronous API

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("https://api.github.com/")
  .addConverterFactory(GsonConverterFactory.create())
  .client(httpClient.build())
  .build();

Retrofit fournit un constructeur pratique pour la construction de notre objet requis. It needs the base URL which is going to be used for every service call and a converter factory - qui s'occupe de l'analyse des données que nous envoyons ainsi que des réponses que nous obtenons.

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

Il est important de noter que différentes usines servent 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à implémentées, nous pouvons jeter un œil àhere.

La dernière dépendance estOKHttpClient - qui est un client HTTP et HTTP / 2 pour les applications Android et Java. Cela va s'occuper de la connexion au serveur et de l'envoi et de 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 effectuer la demande, sur la base de nos annotations précédentes.

Après cela, nous obtenons un objetCall<User> qui est celui utilisé pour exécuter la requête vers l'API GitHub. The most important method here is execute, qui est utilisé 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 à nosGsonConverterFactory.

Passer un appel synchrone est très facile, mais nous utilisons généralement 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éthodeenqueue - qui prend une interfaceCallback<User>comme paramètre pour gérer le succès ou l'échec de la requête. Notez que cela sera exécuté 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'avions fait précédemment.

5. Créer une classeServiceGenerator réutilisable

Maintenant que nous avons vu comment construire notre objet Retrofit et comment utiliser une API, nous pouvons voir que nous ne voulons pas continuer à écrire le générateur 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 pendant la durée de vie de notre application:

public class GitHubServiceGenerator {

    private static final String BASE_URL = "https://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 classeGitHubServiceGenerator, 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 unRepositoryService,, nous pourrions réutiliser cette classe et simplifier la création.

In the next section, nous allons l'étendre et ajouter des fonctionnalités d'authentification.

6. Authentification

La plupart des API ont une authentification pour sécuriser leur 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êteAuthorization:

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 deOkHttp; 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 toute authentification telle que OAuth, utilisateur / mot de passe, etc.

7. Enregistrement

Dans cette section, nous allons étendre davantage nosGitHubServiceGenerator 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 leHttpLoggingInterceptor d'OkHttp, ajoutons-le à nospom.xml:


    com.squareup.okhttp3
    logging-interceptor
    3.9.0

Maintenant, étendons notre classeGitHubServiceGenerator:

public class GitHubServiceGenerator {

    private static final String BASE_URL = "https://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);
    }
}

Ceci est la forme finale de notre classe, nous pouvons voir comment nous avons ajouté lesHttpLoggingInterceptor, et nous le définissons pour la journalisation de base, qui va enregistrer le temps nécessaire pour faire la requête, le point de terminaison, l'état pour chaque demande, 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 détaillé, nous avons examiné l'excellente bibliothèque Retrofit en nous concentrant sur son API Sync / Async, sur les meilleures pratiques en matière 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 jeter un œil àthis tutorial.

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