O componente Feign, integrado ao ecossistema .NET através do framework SummerBoot, oferece uma abordagem declarativa para o consumo de serviços HTTP. Em vez de escrever manualmente o código para requisições HTTP, os desenvolvedores podem definir interfaces de serviço com anotações simples, permitindo que o Feign gere automaticamente as implementações de cliente. Isso simplifica o acesso a APIs remotas, fazendo com que chamadas a serviços externos se assemelhem a invocações de métodos locais.
A base do Feign é construída sobre clientes HTTP, abstraindo a complexidade das operações de rede e serialização/desserialização de dados. Além de sua funcionalidade principal, o Feign no SummerBoot disponibiliza recursos avançados:
- Intercepção Personalizada: Permite a injeção de lógica customizada antes ou depois das requisições, ideal para logs, autenticação ou manipulação de cabeçalhos.
- Encapsulamento de Chamadas: Reduz a verbosidade do código, concentrando a lógica de requisição HTTP dentro das interfaces de serviço.
- Integração com Nacos: Facilita a descoberta e registro de serviços em ambientes de microsserviços.
- Tratamento de Resiliência: Capacidade de integração com bibliotecas como Polly para implementar padrões de resiliência, como retries e circuit breakers.
- Segurança: Suporte para integração com tokens JWT para autorização e autenticação.
As anotações para mapeamento de métodos HTTP são intuitivas:
| Método HTTP | Anotação Feign |
|---|---|
| GET | [GetMapping] |
| PUT | [PutMapping] |
| DELETE | [DeleteMapping] |
| POST | [PostMapping] |
Exemplo de Uso Simplificado do Feign
Para demonstrar o uso do Feign, vamos configurar três projetos:
ServicoApiUsuarios: Um projeto ASP.NET Core que expõe endpoints HTTP.InterfacesFeign: Uma biblioteca de classes que define as interfaces de cliente Feign.ClienteConsumidor: Um projeto ASP.NET Core que consome oServicoApiUsuariosatravés das interfaces Feign.
1. Projeto ServicoApiUsuarios (Provedor de API)
Este projeto oferece uma API RESTful para gerenciamento de usuários. Expondo endpoints GET e POST.
Modelo de Dados:
public class DadosUsuario
{
public int Id { get; set; }
public string NomeExibicao { get; set; }
}
Controller (GerenciadorUsuariosController.cs):
[ApiController]
[Route("[controller]/[action]")]
public class GerenciadorUsuariosController : ControllerBase
{
[HttpGet]
public List<DadosUsuario> ObterListaUsuarios()
{
List<DadosUsuario> usuarios = new()
{
new(){Id = 1, NomeExibicao = "João Silva"},
new(){Id = 2, NomeExibicao = "Maria Oliveira"}
};
return usuarios;
}
[HttpPost]
public DadosUsuario CriarNovoUsuario([FromBody] DadosUsuario usuario)
{
// Lógica para salvar o usuário, aqui apenas o retornamos
return usuario;
}
}
2. Projeto InterfacesFeign (Definição do Cliente Feign)
Neste projeto, definimos as interfaces que o Feign usará para gerar os clientes. Primeiramente, configure os serviços no Program.cs ou Startup.cs:
builder.Services.AddSummerBoot();
builder.Services.AddSummerBootFeign();
A interface IServicoExternoUsuarios é onde declaramos os métodos para consumir a API. A anotação [FeignClient] especifica a URL base do serviço externo, e as anotações nos métodos mapeiam para os endpoints específicos.
using SummerBoot.Feign;
using SummerBoot.Feign.Attributes;
using System.Collections.Generic;
using System.Threading.Tasks;
// Suponha que DadosUsuario esteja definido em uma biblioteca compartilhada
// ou seja recriado neste projeto.
public class DadosUsuario
{
public int Id { get; set; }
public string NomeExibicao { get; set; }
}
[FeignClient(Url = "http://192.168.10.13:5152")] // URL do ServicoApiUsuarios
public interface IServicoExternoUsuarios
{
[GetMapping("/GerenciadorUsuarios/ObterListaUsuarios")]
Task<List<DadosUsuario>> RecuperarTodosUsuarios();
[PostMapping("/GerenciadorUsuarios/CriarNovoUsuario")]
Task<DadosUsuario> RegistrarUsuario([Body] DadosUsuario usuario);
}
É importante notar que os métodos da interface Feign devem retornar Task<>, indicando que são operações assíncronas. O Feign gera uma implementação de proxy para essa interface, lidando com a execução da requisição HTTP subjacente.
A anotação [FeignClient] permite diversas configurações, como:
Url: A URL base do serviço.IsIgnoreHttpsCertificateValidate: Define se a validação de certificado HTTPS deve ser ignorada (útil em ambientes de desenvolvimento).InterceptorType: Epsecifica um tipo de interceptador personalizado para a requisição.Timeout: Define o tempo limite da requissição em segundos.
A anotação [Body] indica que o parâmetro do método deve ser enviado no corpo da requisição. Por padrão, o Feign serializa o objeto para JSON, mas também suporta submissão via formulário.
3. Projeto ClienteConsumidor (Consumidor da API)
Este projeto integra a interface Feign e a utiliza para chamar o serviço remoto. Primeiro, configure os serviços:
builder.Services.AddSummerBoot();
builder.Services.AddSummerBootFeign();
Em um Controller, injetamos a interface Feign e invocamos seus métodos como se fossem locais:
[ApiController]
[Route("[controller]/[action]")]
public class ConsumidorApiUsuariosController : ControllerBase
{
private readonly IServicoExternoUsuarios _servicoUsuariosExterno;
public ConsumidorApiUsuariosController(IServicoExternoUsuarios servicoUsuariosExterno)
{
_servicoUsuariosExterno = servicoUsuariosExterno;
}
[HttpGet]
public async Task<List<DadosUsuario>> BuscarUsuariosRemotos()
{
return await _servicoUsuariosExterno.RecuperarTodosUsuarios();
}
[HttpPost]
public async Task<DadosUsuario> EnviarDadosUsuario(DadosUsuario usuario)
{
return await _servicoUsuariosExterno.RegistrarUsuario(usuario);
}
}
Configuração Dinâmica de URLs
Para maior flexibilidade, as URLs e paths podem ser lidos de arquiovs de configuração (como appsettings.json) usando a sintaxe ${}. Por exemplo:
appsettings.json:
{
"ConfiguracaoServicos": {
"UrlApiUsuarios": "http://localhost:5152",
"CaminhoUsuarios": "/GerenciadorUsuarios/ObterListaUsuarios"
}
}
Uso na interface Feign:
[FeignClient(Url = "${ConfiguracaoServicos:UrlApiUsuarios}")]
public interface IServicoExternoUsuarios
{
[GetMapping("${ConfiguracaoServicos:CaminhoUsuarios}")]
Task<List<DadosUsuario>> RecuperarTodosUsuarios();
// ...
}