1. Información general
En este tutorial, describiremos Spring Cloud OpenFeign, un cliente REST declarativo para aplicaciones Spring Boot.
Feign facilita la escritura de clientes de servicios web con soporte de anotaciones conectable, que incluye anotaciones Feign y anotaciones JAX-RS.
Además, Spring Cloud agrega soporte para las anotaciones Spring MVC y para usar los mismos HttpMessageConverters que se usan en Spring Web.
Una gran ventaja de usar Feign es que no tenemos que escribir ningún código para llamar al servicio, más que una definición de interfaz.
2. Dependencias
Primero, comenzaremos creando un proyecto web Spring Boot y agregando la dependencia spring-cloud-starter-openfeign a nuestro archivo pom.xml :
org.springframework.cloud spring-cloud-starter-openfeign
Además, necesitaremos agregar las dependencias de spring-cloud :
org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import
Podemos encontrar las últimas versiones de spring-cloud-starter-openfeign y spring-cloud-dependencies en Maven Central.
3. Cliente fingido
A continuación, debemos agregar @EnableFeignClients a nuestra clase principal:
@SpringBootApplication @EnableFeignClients public class ExampleApplication { public static void main(String[] args) { SpringApplication.run(ExampleApplication.class, args); } }
Con esta anotación, habilitamos el análisis de componentes para las interfaces que declaran que son clientes de Feign.
Luego, declaramos un cliente de Feign usando la anotación @FeignClient :
@FeignClient(value = "jplaceholder", url = "//jsonplaceholder.typicode.com/") public interface JSONPlaceHolderClient { @RequestMapping(method = RequestMethod.GET, value = "/posts") List getPosts(); @RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json") Post getPostById(@PathVariable("postId") Long postId); }
En este ejemplo, configuramos un cliente para leer de las API JSONPlaceHolder.
El argumento de valor pasado en la anotación @FeignClient es un nombre de cliente arbitrario y obligatorio, mientras que con el argumento url , especificamos la URL base de la API.
Además, dado que esta interfaz es un cliente de Feign, podemos usar las anotaciones de Spring Web para declarar las API a las que queremos llegar.
4. Configuración
Ahora bien, es muy importante comprender que cada cliente de Feign está compuesto por un conjunto de componentes personalizables.
Spring Cloud crea un nuevo conjunto predeterminado a pedido para cada cliente nombrado utilizando la clase FeignClientsConfiguration que podemos personalizar como se explica en la siguiente sección.
La clase anterior contiene estos frijoles:
- Decoder - ResponseEntityDecoder , que envuelve SpringDecoder, usado para decodificar la Respuesta
- Codificador: SpringEncoder , utilizado para codificar RequestBody
- Registrador: Slf4jLogger es el registrador predeterminado utilizado por Feign
- Contract - SpringMvcContract , que proporciona procesamiento de anotaciones
- Feign-Builder: HystrixFeign.Builder utilizado para construir los componentes
- Cliente: LoadBalancerFeignClient o cliente Feign predeterminado
4.1. Configuración personalizada de beans
Si queremos personalizar uno o más de estos beans, podemos anularlos usando una clase @Configuration , que luego agregamos a la anotación FeignClient :
@FeignClient(value = "jplaceholder", url = "//jsonplaceholder.typicode.com/", configuration = MyClientConfiguration.class)
@Configuration public class MyClientConfiguration { @Bean public OkHttpClient client() { return new OkHttpClient(); } }
En este ejemplo, le decimos a Feign que use OkHttpClient en lugar del predeterminado para admitir HTTP / 2.
Feign admite varios clientes para diferentes casos de uso, incluido ApacheHttpClient , que envía más encabezados con la solicitud, por ejemplo, Content-Length, que esperan algunos servidores.
Para usar estos clientes, no olvidemos agregar las dependencias requeridas a nuestro archivo pom.xml , por ejemplo:
io.github.openfeign feign-okhttp io.github.openfeign feign-httpclient
Podemos encontrar las últimas versiones de feign-okhttp y feign-httpclient en Maven Central.
4.2. Configuración mediante propiedades
En lugar de usar una clase @Configuration , podemos usar las propiedades de la aplicación para configurar los clientes Feign , como se muestra en este ejemplo de application.yaml :
feign: client: config: default: connectTimeout: 5000 readTimeout: 5000 loggerLevel: basic
Con esta configuración, establecemos los tiempos de espera en 5 segundos y el nivel del registrador en básico para cada cliente declarado en la aplicación.
Finalmente, podemos crear la configuración con el nombre de cliente predeterminado para configurar todos los objetos @FeignClient , o podemos declarar el nombre de cliente fingido para una configuración:
feign: client: config: jplaceholder:
Si tenemos el bean @Configuration y las propiedades de configuración, las propiedades de configuración anularán los valores de @Configuration .
5. Interceptores
Agregar interceptores es otra característica útil proporcionada por Feign.
Los interceptores pueden realizar una variedad de tareas implícitas, desde la autenticación hasta el registro, para cada solicitud / respuesta HTTP.
En esta sección, implementaremos nuestro propio interceptor, así como también usaremos el provisto por Spring Cloud OpenFeign listo para usar. Ambos agregarán un encabezado de autenticación básico a cada solicitud .
5.1. Implementación de RequestInterceptor
Entonces, en el fragmento a continuación, implementemos nuestro interceptor de solicitudes personalizado:
@Bean public RequestInterceptor requestInterceptor() { return requestTemplate -> { requestTemplate.header("user", username); requestTemplate.header("password", password); requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType()); }; }
Also, to add the interceptor to the request chain, we just need to add this bean to our @Configuration class, or as we saw previously, declare it in the properties file:
feign: client: config: default: requestInterceptors: com.baeldung.cloud.openfeign.JSONPlaceHolderInterceptor
5.2. Using BasicAuthRequestInterceptor
Alternatively, we can use the BasicAuthRequestInterceptor class that the Spring Cloud OpenFeign provides:
@Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("username", "password"); }
It's simple as that! Now all the requests will contain the basic authentication header.
6. Hystrix Support
Feign supports Hystrix, so if we have enabled it, we can implement the fallback pattern.
With the fallback pattern, when a remote service call fails, rather than generating an exception, the service consumer will execute an alternative code path to try to carry out the action through another means.
To achieve the goal, we need to enable Hystrix adding feign.hystrix.enabled=true in the properties file.
This allows us to implement fallback methods that are called when the service fails:
@Component public class JSONPlaceHolderFallback implements JSONPlaceHolderClient { @Override public List getPosts() { return Collections.emptyList(); } @Override public Post getPostById(Long postId) { return null; } }
To let Feign know that fallback methods have been provided, we also need to set our fallback class in the @FeignClient annotation:
@FeignClient(value = "jplaceholder", url = "//jsonplaceholder.typicode.com/", fallback = JSONPlaceHolderFallback.class) public interface JSONPlaceHolderClient { // APIs }
7. Logging
For each Feign client, a logger is created by default.
To enable logging, we should declare it in the application.properties file using the package name of the client interfaces:
logging.level.com.baeldung.cloud.openfeign.client: DEBUG
Or, if we want to enable logging only for one particular client in a package, we can use the full class name:
logging.level.com.baeldung.cloud.openfeign.client.JSONPlaceHolderClient: DEBUG
Note that Feign logging responds only to the DEBUG level.
The Logger.Level that we may configure per client indicates how much to log:
@Configuration public class ClientConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.BASIC; } }
There are four logging levels to choose from:
- NONE – no logging, which is the default
- BASIC – log only the request method, URL, and response status
- HEADERS – log the basic information together with request and response headers
- FULL – log the body, headers, and metadata for both request and response
8. Error Handling
Feign's default error handler, ErrorDecoder.default, always throws a FeignException.
Now, this behavior isn't always the most useful. So, to customize the Exception thrown, we can use a CustomErrorDecoder:
public class CustomErrorDecoder implements ErrorDecoder { @Override public Exception decode(String methodKey, Response response) { switch (response.status()){ case 400: return new BadRequestException(); case 404: return new NotFoundException(); default: return new Exception("Generic error"); } } }
Luego, como hemos hecho anteriormente, tenemos que reemplazar el ErrorDecoder predeterminado agregando un bean a la clase @Configuration :
@Configuration public class ClientConfiguration { @Bean public ErrorDecoder errorDecoder() { return new CustomErrorDecoder(); } }
9. Conclusión
En este artículo, discutimos Spring Cloud OpenFeign y su implementación en una aplicación de muestra simple.
Además, hemos visto cómo configurar un cliente, cómo agregar interceptores a nuestras solicitudes y cómo manejar errores usando Hystrix y ErrorDecoder.
Como de costumbre, todos los ejemplos de código que se muestran en este tutorial están disponibles en GitHub.