Introdução ao Feign

Introdução ao Feign

1. Visão geral

Neste tutorial, iremos apresentar e explicarFeign, um cliente declarativoHTTP desenvolvido pela Netflix.

Feign visa simplificar os clientesHTTP API. Simplificando, o desenvolvedor precisa apenas declarar e anotar uma interface enquanto a implementação real será provisionada em tempo de execução.

2. Exemplo

Apresentaremos um exemplo de serviço de livrariaREST API, que é consultado e testado com base no clienteFeignHTTP.

Antes de construirmos um clienteFeign de amostra, vamos adicionar as dependências necessárias e iniciar o serviçoREST.

O exemplo de serviço de livraria pode ser clonado dehere.

Depois de baixar o aplicativo de serviço, vamos executá-lo com:

$> mvn install spring-boot:run

3. Configuração

Primeiro, criaremos um novo projetoMaven e incluiremos estas dependências:


    io.github.openfeign
    feign-okhttp
    9.3.1


    io.github.openfeign
    feign-gson
    9.3.1


    io.github.openfeign
    feign-slf4j
    9.3.1

Além da dependênciafeign-core (que também é puxada), usaremos alguns plug-ins, especialmente:feign-okhttp para usar internamente o clienteSquare’s OkHttp para fazer solicitações,feign-gson para usandoGoogle’s GSON como processadorJSON efeign-slf4j para usarSimple Logging Facade para registrar solicitações.

Para realmente obter alguma saída de log, você precisará de sua implementação de logger suportada porSLF4J favorita em seu classpath.

Antes de continuarmos a criar nossa interface de cliente, vamos configurar um modeloBook para armazenar nossos dados:

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

    // standard constructor, getters and setters
}

NOTE: Pelo menos um “construtor sem argumentos” é necessário para um processadorJSON.

Na verdade, nosso provedorREST é umhypermedia-driven API,, então precisaremos de uma classe de wrapper simples:

public class BookResource {
    private Book book;

    // standard constructor, getters and setters
}

Note: Nós manteremosBookResource simples porque nosso clienteFeign de amostra não se beneficia dos recursos de hipermídia!

4. Lado do servidor

Para entender como definir um clienteFeign, primeiro veremos alguns dos métodos e respostas com suporte de nosso provedorREST.

Vamos experimentar com um comando shellcurl simples para listar todos os livros. Não se esqueça de prefixar suas chamadas com‘/api', que é oservlet-context definido emapplication.properties:

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

obteremos um repositório de livros completo representado comoJSON:

[
  {
    "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"
      }
    ]
  }
]

Também podemos consultar o recursoBook individual, anexandoISBN a uma solicitação get:

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

5. Cliente fingir

Agora vamos definir nosso clienteFeign.

Usaremos a anotação@RequestLine para especificarHTTP verb e uma parte do caminho como argumento, e os parâmetros serão modelados usando a anotação@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: Clientes Feign podem ser usados ​​para consumir APIs HTTP baseadas em texto apenas, o que significa que eles não podem lidar com dados binários, por exemplo, uploads ou downloads de arquivos.

That’s all! Agora vamos usarFeign.builder() para configurar nosso cliente baseado em interface. A implementação real será provisionada no tempo de execução:

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 suporta vários plug-ins, como codificadores e decodificadoresJSON /XML ou um clienteHTTP subjacente para fazer as solicitações.

6. Teste de unidade

Vamos criar uma classe de teste de unidade, contendo três métodos@Test, para testar nosso cliente. O teste usará importações estáticas dos pacotesorg.hamcrest.CoreMatchers.*eorg.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"));
}

Esses testes são bastante auto-explicativos. Para executá-lo, basta executar a metatest do Maven:

$> mvn test

7. Leitura adicional

Se precisar de algum tipo de fallback, no caso de indisponibilidade do serviço, você pode adicionarHystrixFeign ao seuclasspathe construir seu cliente comHystrixFeign.builder().

Para saber mais sobreHystrix, sigathis dedicated tutorial series.

Se você deseja integrarSpring Cloud Netflix Hystrix comFeign, você pode ler mais sobre estehere.

Também é possível adicionar balanceamento de carga do lado do cliente e / ou descoberta de serviço ao seu cliente.

O primeiro é feito adicionandoRibbon ao seu classpath e chamando o construtor assim:

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

Para descoberta de serviço, você deve construir seu serviço comSpring Cloud Netflix Eureka habilitado. Em seguida, basta integrar comSpring Cloud Netflix Feigne você obterá o balanceamento de carga deRibbon gratuitamente. Mais sobre isso pode ser encontradohere.

8. Conclusão

Este artigo explicou como construir um cliente declarativoHTTP usandoFeign para consumirAPIs baseado em texto.

Como de costume, você encontrará as fonteson GitHub.