MicroProfile REST Client

Faisant partie de la spécification parapluie MicroProfile, la spécification MicroProfile REST Client fournit une approche typée pour appeler des services RESTful sur HTTP, en se basant sur des interfaces Java.
L'objectif ici est de fournir un style de code beaucoup plus naturel, l’implémentation sous-jacente prenant en charge la communication entre le client et le service.
Ainsi, pour invoquer un service distant, on utilise une approche déclarative par la définition d'une interface, avec des méthodes annotées représentant les chemins et opérations du service cible.

Définition de l'interface d'appel

A titre d'exemple, voyons comment invoquer l'API Star Wars qui expose les données du monde Star Wars sous forme de ressources au format JSON par défaut, et en particulier, intéressons-nous aux personnages.
Pour commencer, nous définissons une interface Java, nommée SwapiService, qui permettra l'accès aux ressources people :

1
2
3
4
5
6
7
8
9
10
11
@RegisterRestClient  
@Produces(MediaType.APPLICATION_JSON)
public interface SwapiService {  
    @GET  
    @Path("/people/{id}")  
    JsonObject getCharacter(@PathParam("id") String id);  
  
    @GET  
    @Path("/people")  
    JsonObject getPeople();  
}

Sans préciser l'URL de base du service distant, c'est par l'utilisation des annotations connues de JAX-RS servant à implémenter une ressource, que nous pouvons indiquer comment atteindre les ressources souhaitées : telle qu'elle est annotée, la méthode getChanacter (nom laissé à notre choix) cible la ressource people de chemin /people/id au moyen d'une commande HTTP GET, avec une réponse que l'on souhaite récupérer sous forme d'objet JSON, de type JsonObject ; idem pour la méthode getPeople qui elle, permet d'obtenir l'ensemble des personnages, également sous la forme d'un objet JSON.

De manière alternative, le type de retour de ces méthodes pourrait être String, auquel cas, nous recevrions des réponses JSON sous la forme de chaînes de caractères.
Nous pourrions également définir une classe People avec des propriétés correspondant aux propriétés de l'objet JSON qui nous intéresse, et qui serait le type du retour de la méthode getCharacter, auquel cas, une conversion vers cette classe serait opérée automatiquement.
Si l'on souhaitait examiner la réponse complète, le type Response de JAX-RS pourrait être utilisé comme type de retour (à partir duquel on peut lire l'entité HTTP, accéder aux entêtes ou au statut de la réponse, etc.).

Enfin, si le type de retour d'une méthode est CompletionStage (par exemple CompletionStage<JsonObject>), cette méthode est marquée comme devant être appelée de manière asynchrone.

L'annotation RegisterRestClient sur l'interface SwapiService, indique quant à elle, qu'une implémentation de cette interface sous la forme d'un bean CDI (injectable donc) devra être disponible à l'exécution.
Un tel bean peut être injecté, par exemple, dans le champ d'une classe annotée avec les annotations Inject et RestClient :

1
2
3
@Inject  
@RestClient  
private SwapiService swapiService;

Dès lors, vous pourrez invoquer les méthodes de l'interface SwapiServiceAsync et réaliser ainsi des appels vers le service distant.
L'URL de ce dernier est spécifiée dans le fichier de configuration microprofile-config.properties, comme par exemple :

com.odelia.mp.restclient.client.SwapiService/mp-rest/url=https://swapi.dev/api

où l'on retrouve le nom qualifiée de l'interface SwapiService suivie de /mp-rest/url, comme nom de clé.
D'autres paramètres de configuration peuvent être aussi définis à ce niveau, comme le délai de connexion au service distant, ou encore le délai d'attente de la réponse à ce service.

Si on voulait lire le nom de la ressource people, d'identifiant 1 (correspondant à Luke Skywalker), disponible à l'adresse https://swapi.dev/api/people/1, on appellerait la méthode getCharacter comme ceci :

1
2
JsonObject character = swapiService.getCharacter("1");
String name = character.getString("name");
Carte conceptuelle

Voici une carte conceptuelle rappelant où se placent les principales annotations et l'interaction entre les parties prenantes :

Client REST programmatique

En plus de l'utilisation de l'injection pour obtenir le bean implémentant l'interface d'appel du service distant, MicroProfile REST Client met aussi à disposition une API de type builder pour le faire de manière programmatique ; cela offre plus de contrôle sur les différents paramètres du client REST.
En voici un simple exemple dans lequel, grâce à la classe RestClientBuilder, nous pouvons obtenir une instance de type SwapiService :

1
2
3
4
5
6
SwapiService swapiService =  
        RestClientBuilder.newBuilder()  
                .baseUrl(new URL("https://swapi.dev/api"))  
                .build(SwapiService.class);  
  
JsonObject character = swapiService.getCharacter(id);

Cependant, dans ce cas, l'interface SwapiService ne doit pas être annotée avec @RegisterRestClient.

Notes

Retrouver sur Bitbuket, le projet faisant la démonstration de ce qui a été exposé dans cet article, avec une application MicroProfile 5.0, utilisant Open Liberty.

Il est à noter que le framework Micronaut avec son client HTTP (injecté lors de la phase de build), ainsi que le projet Spring Cloud OpenFeign proposent tous deux une appoche déclarative similaire à celle de MicroProfile REST Client.