Devoxx 2017 : Retour sur « Soyez une ‘feign’asse quand vous écrivez un client REST Java »

J'ai eu l'opportunité de me rendre à la Devoxx 2017, durant laquelle j'ai pu participer à la conférence "Soyez une 'feign'asse quand vous écrivez un client REST Java" présentée par Alexandre NAVARRO, lead dev à la Société Générale.

L'objectif de cette présentation était de faire une démonstration de la librairie Feign, développée par Netflix. Cette librairie permet de simplifier grandement le développement d'un client REST en Java, afin de récupérer des données venant de services externes.

Si l'on utilise les librairies standard Java (Java.net.URL), développer son client REST prend à la fois beaucoup de temps et de lignes de code :

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class NetClientGet {
	// http://localhost:8080/RESTfulExample/json/product/get
	public static void main(String[] args) {
	  try {
		URL url = new URL("http://localhost:8080/RESTfulExample/json/product/get");
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setRequestMethod("GET");
		conn.setRequestProperty("Accept", "application/json");
		if (conn.getResponseCode() != 200) {
			throw new RuntimeException("Failed : HTTP error code : "
					+ conn.getResponseCode());
		}
		BufferedReader br = new BufferedReader(new InputStreamReader(
			(conn.getInputStream())));
		String output;
		System.out.println("Output from Server .... \n");
		while ((output = br.readLine()) != null) {
			System.out.println(output);
		}
		conn.disconnect();
	  } catch (MalformedURLException e) {
		e.printStackTrace();
	  } catch (IOException e) {
		e.printStackTrace();
	  }
	}
}
Exemple d'appel GET vers un service REST externe. Source : https://www.mkyong.com/webservices/jax-rs/restfull-java-client-with-java-net-url/

Et une fois les données JSON récupérées, il faut encore les parser avec une librairie comme Jackson ou Gson afin d'obtenir un objet Java. Feign propose de glisser toute cette partie sous le manteau pour se concentrer sur l'essentiel : appeler les URL et obtenir directement l'objet Java correspondant en sortie.

Exemple basique

Pour créer un client REST avec Feign, il y a 3 étapes :

  1. Créer une interface avec des annotations et des POJO en type de retour
  2. Instancier son interface pour que Feign crée l'implémentation
  3. Utiliser l'interface créée pour récupérer les données

Créer son interface Feign

L'exemple suivant est donné dans la présentation :

public interface GithubWithFeignResource{
	
	@RequestLine("GET /repos/{owner}/{repo}/contributors")
	List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
	
}
Exemple d'interface Feign

Cette interface permet de récupérer les listes des contributeurs sur un repository Github. On considère que le POJO Contributor est déjà créé. Les annotations Feign sont les suivantes :

  • @RequestLine qui permet de définir la route à contacter, ainsi que la méthode d'appel (GET, POST, DELETE...) et les paramètres à binder entre accolades.
  • @Param qui permet de faire le lien entre les paramètres de la méthode et ceux de la route.

Instancier l'interface

Une fois l'interface créée, on appelle le Feign Builder pour créer l'implémentation automatiquement.

GithubWithFeignResource githubWithFeignResource = Feign.builder()
	.decoder(new JacksonDecoder())
	.target(GithubWithFeignResource.class, "https://api.github.com");

C'est ici que l'implémentation est définie :

  • Dans la méthode decoder() on définit le décodeur à utiliser. On peut utiliser celui qui a notre préférence, comme Jackson, Gson ou d'autres.
  • Dans la méthode target() on définit la classe à implémenter, et la racine de l'API à contacter (ici https://api.github.com)

Utiliser l'interface instanciée

Il ne reste plus qu'à utiliser la méthode créée dans l'interface pour récupérer sa liste d'objets :

List<Contributor> contributors = githubWithFeignResource.contributors("OpenFeign", "feign");

Customisation

Il existe différentes possibilités de customisation des requêtes pour des cas moins standard. Parmi ces possibilités on trouve :

  • L'ajout de paramètres à la requête avec les annotations @Body (pour les requêtes POST) ou @Header pour rajouter des headers spécifiques;
  • Utiliser un autre client HTTP (OkHttp, Ribbon...) que celui par défaut avec la méthode client() du Builder;
  • Utiliser un intercepteur de requêtes pour faire du monitoring avec la méthode requestInterceptor() du Builder;

Il existe encore bien d'autres choses qui sont disponibles sur la documentation de la librairie

Couplage avec Spring Boot

Il est possible de coupler Feign avec Spring Boot pour avoir encore moins de code à produire : avec quelques annotations supplémentaires il n'est même plus nécessaire d'instancier l'interface manuellement.

On commence par ajouter la librairie spring-cloud-starter-feign à notre projet :

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.3.1.RELEASE</version>
</dependency>

Cette dépendance met à disposition les annotations @EnableFeignClients et @FeignClient qu'il faut rajouter respectivement dans la classe de configuration de l'application, et sur les interfaces Feign. Par ailleurs, il devient possible d'utiliser les annotations standard de Spring MVC telles que @RequestMapping et @PathVariable au lieu de @RequestLine et @Param

Pour reprendre l'exemple précédent, l'interface devient ainsi :

@FeignClient(url = "https://api.github.com", name="github")
public interface GithubWithFeignResource{
	
	@RequestMapping(method = RequestMethod.GET, value = "/repos/{owner}/{repo}/contributors")
	List<Contributor> contributors(@PathVariable("owner") String owner, @PathVariable("repo") String repo);
	
}

Conclusion

Feign est une librairie puissante pour créer des clients REST en Java. Elle a été inspirée par d'autres modèles tels que Retrofit ou JAX-RS, mais a poussé le vice plus loin pour que les développeurs puissent gagner en performance lors des phases de développement.

Vous pouvez retrouver la conférence complète à cette adresse : https://www.youtube.com/watch?v=VXVpVnJ_f7c

Un commentaire

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.