Intro to Feign

Intro à Feign

1. Vue d'ensemble

Dans ce tutoriel, nous allons présenter et expliquerFeign, un client déclaratifHTTP développé par Netflix.

Feign vise à simplifier les clients deHTTP API. En termes simples, le développeur n'a besoin que de déclarer et d'annoter une interface alors que l'implémentation réelle sera provisionnée au moment de l'exécution.

2. Exemple

Nous allons présenter un exemple de service de librairieREST API, qui est interrogé et testé sur la base du clientFeignHTTP.

Avant de créer un exemple de clientFeign, nous allons ajouter les dépendances nécessaires et démarrer le serviceREST.

L'exemple de service de librairie peut être cloné à partir dehere.

Après avoir téléchargé l'application de service, nous l'exécuterons avec:

$> mvn install spring-boot:run

3. Installer

Tout d'abord, nous allons créer un nouveau projetMaven et inclure ces dépendances:


    io.github.openfeign
    feign-okhttp
    9.3.1


    io.github.openfeign
    feign-gson
    9.3.1


    io.github.openfeign
    feign-slf4j
    9.3.1

Outre la dépendancefeign-core (qui est également extraite), nous utiliserons quelques plugins, en particulier:feign-okhttp pour utiliser en interne le clientSquare’s OkHttp pour faire des requêtes,feign-gson pour en utilisantGoogle’s GSON comme processeurJSON etfeign-slf4j pour utiliser lesSimple Logging Facade pour consigner les requêtes.

Pour obtenir une sortie de journal, vous aurez besoin de votre implémentation de journalisation préférée, prise en charge parSLF4J sur votre chemin de classe.

Avant de continuer à créer notre interface client, nous allons configurer un modèleBook pour conserver nos données:

public class Book {
    private String isbn;
    private String author;
    private String title;
    private String synopsis;
    private String language;

    // standard constructor, getters and setters
}

NOTE: Au moins un «constructeur sans arguments» est requis par un processeurJSON.

En fait, notre fournisseurREST est unhypermedia-driven API, donc nous aurons besoin d'une simple classe wrapper:

public class BookResource {
    private Book book;

    // standard constructor, getters and setters
}

Note: Nousgarderons lesBookResource simples car notre exemple de clientFeign ne bénéficie pas des fonctionnalités hypermédia!

4. Du côté serveur

Pour comprendre comment définir un clientFeign, nous allons d'abord examiner certaines des méthodes et réponses prises en charge par notre fournisseurREST.

Essayons-le avec une simple commande shellcurl pour lister tous les livres. N'oubliez pas de préfixer vos appels avec‘/api', qui est leservlet-context défini dans lesapplication.properties:

$> curl http://localhost:8081/api/books

nous obtiendrons un référentiel de livres complet représenté parJSON:

[
  {
    "book": {
      "isbn": "1447264533",
      "author": "Margaret Mitchell",
      "title": "Gone with the Wind",
      "synopsis": null,
      "language": null
    },
    "links": [
      {
        "rel": "self",
        "href": "http://localhost:8081/api/books/1447264533"
      }
    ]
  },

  ...

  {
    "book": {
      "isbn": "0451524934",
      "author": "George Orwell",
      "title": "1984",
      "synopsis": null,
      "language": null
    },
    "links": [
      {
        "rel": "self",
        "href": "http://localhost:8081/api/books/0451524934"
      }
    ]
  }
]

Nous pouvons également interroger la ressourceBook individuelle, en ajoutant lesISBN à une requête get:

$> curl http://localhost:8081/api/books/1447264533

5. Feindre le client

Nous allons maintenant définir notre clientFeign.

Nous utiliserons l'annotation@RequestLine pour spécifier leHTTP verb et une partie de chemin comme argument, et les paramètres seront modélisés en utilisant l'annotation@Param:

public interface BookClient {
    @RequestLine("GET /{isbn}")
    BookResource findByIsbn(@Param("isbn") String isbn);

    @RequestLine("GET")
    List findAll();

    @RequestLine("POST")
    @Headers("Content-Type: application/json")
    void create(Book book);
}

NOTE: Les clients Feign peuvent être utilisés pour consommer uniquement des API HTTP textuelles, ce qui signifie qu'ils ne peuvent pas gérer les données binaires, par exemple téléchargement de fichiers ou téléchargements.

That’s all! Nous allons maintenant utiliser lesFeign.builder() pour configurer notre client basé sur l'interface. L'implémentation réelle sera fournie à l'exécution:

BookClient bookClient = Feign.builder()
  .client(new OkHttpClient())
  .encoder(new GsonEncoder())
  .decoder(new GsonDecoder())
  .logger(new Slf4jLogger(BookClient.class))
  .logLevel(Logger.Level.FULL)
  .target(BookClient.class, "http://localhost:8081/api/books");

Feign prend en charge divers plugins tels que les encodeurs et décodeursJSON /XML ou un client sous-jacentHTTP pour effectuer les requêtes.

6. Test de l'unité

Créons une classe de test unitaire, contenant trois méthodes@Test, pour tester notre client. Le test utilisera les importations statiques des packagesorg.hamcrest.CoreMatchers.* etorg.junit.Assert.*:

@Test
public void givenBookClient_shouldRunSuccessfully() throws Exception {
   List books = bookClient.findAll().stream()
     .map(BookResource::getBook)
     .collect(Collectors.toList());

   assertTrue(books.size() > 2);
}

@Test
public void givenBookClient_shouldFindOneBook() throws Exception {
    Book book = bookClient.findByIsbn("0151072558").getBook();
    assertThat(book.getAuthor(), containsString("Orwell"));
}

@Test
public void givenBookClient_shouldPostBook() throws Exception {
    String isbn = UUID.randomUUID().toString();
    Book book = new Book(isbn, "Me", "It's me!", null, null);
    bookClient.create(book);
    book = bookClient.findByIsbn(isbn).getBook();

    assertThat(book.getAuthor(), is("Me"));
}

Ces tests sont assez explicites. Pour l'exécuter, exécutez simplement l'objectif de Maventest:

$> mvn test

7. Lectures complémentaires

Si vous avez besoin d'une sorte de solution de secours, en cas d'indisponibilité de service, vous pouvez ajouterHystrixFeign à vosclasspath et construire votre client avec lesHystrixFeign.builder() à la place.

Pour en savoir plus surHystrix, veuillez suivrethis dedicated tutorial series.

Si vous souhaitez intégrerSpring Cloud Netflix Hystrix avecFeign, vous pouvez en savoir plus sur cehere.

Il est également possible d'ajouter un équilibrage de charge côté client et / ou une découverte de service à votre client.

Le premier est fait en ajoutantRibbon à votre chemin de classe et en appelant le constructeur comme ceci:

BookClient bookClient = Feign.builder()
  .client(RibbonClient.create())
  .target(BookClient.class, "http://localhost:8081/api/books");

Pour la découverte de service, vous devez créer votre service avecSpring Cloud Netflix Eureka activé. Ensuite, intégrez simplement avecSpring Cloud Netflix Feign et vous obtenez gratuitement l'équilibrage de charge deRibbon. Pour en savoir plus, consultezhere.

8. Conclusion

Cet article explique comment créer un clientHTTP déclaratif à l'aide deFeign pour consommer desAPI basés sur du texte.

Comme d'habitude, vous trouverez les sourceson GitHub.