0% encontró este documento útil (0 votos)
31 vistas18 páginas

Feign Client

El documento proporciona ejemplos de implementación de un cliente Feign en Spring Boot para realizar operaciones GET, POST, PUT y DELETE, incluyendo la configuración de autenticación y headers personalizados. Se discuten consideraciones sobre el manejo de formatos JSON y XML, así como la organización de parámetros mediante DTOs para mejorar la legibilidad del código. Además, se menciona la integración de Resilience4j para manejar errores y mejorar la resiliencia del sistema.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
31 vistas18 páginas

Feign Client

El documento proporciona ejemplos de implementación de un cliente Feign en Spring Boot para realizar operaciones GET, POST, PUT y DELETE, incluyendo la configuración de autenticación y headers personalizados. Se discuten consideraciones sobre el manejo de formatos JSON y XML, así como la organización de parámetros mediante DTOs para mejorar la legibilidad del código. Además, se menciona la integración de Resilience4j para manejar errores y mejorar la resiliencia del sistema.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd

Aquí tienes ejemplos de componentes GET, POST, PUT y DELETE utilizando Feign

Client en Spring Boot, aplicando los headers y autenticación que mencionaste:

Configuración del Feign Client

Primero, aseguramos que Feign esté habilitado en la aplicación:

@EnableFeignClients
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Interfaz del Cliente Feign


@FeignClient(name = "exampleService", url = "https://api.example.com")
public interface ExampleClient {

@GetMapping("/resource")
ResponseEntity<String> getResource(@RequestParam String param1,
@RequestParam String param2,
@RequestHeader("idConsumidor")
String idConsumidor,
@RequestHeader("idDestino") String
idDestino,
@RequestHeader("usuario") String
usuario,
@RequestHeader("Authorization")
String auth);

@PostMapping("/resource")
ResponseEntity<String> createResource(@RequestBody Map<String,
Object> body,
@RequestHeader("idConsumidor")
String idConsumidor,
@RequestHeader("idDestino")
String idDestino,
@RequestHeader("usuario")
String usuario,
@RequestHeader("Authorization")
String auth);

@PutMapping("/resource/{id}")
ResponseEntity<String> updateResource(@PathVariable String id,
@RequestBody Map<String, Object> body,
@RequestHeader("idConsumidor")
String idConsumidor,
@RequestHeader("idDestino")
String idDestino,
@RequestHeader("usuario")
String usuario,
@RequestHeader("Authorization")
String auth);

@DeleteMapping("/resource/{id}")
ResponseEntity<String> deleteResource(@PathVariable String id,
@RequestHeader("idConsumidor")
String idConsumidor,
@RequestHeader("idDestino")
String idDestino,
@RequestHeader("usuario")
String usuario,
@RequestHeader("Authorization")
String auth);
}

Ejemplo de Uso en un Servicio


@Service
public class ExampleService {

private final ExampleClient exampleClient;

public ExampleService(ExampleClient exampleClient) {


this.exampleClient = exampleClient;
}

public ResponseEntity<String> getResource() {


return exampleClient.getResource("valor1", "valor2",
"id-consumidor", "id-destino", "usuario123",
"Basic " +
Base64.getEncoder().encodeToString("user:password".getBytes()));
}

public ResponseEntity<String> createResource(Map<String, Object>


body) {
return exampleClient.createResource(body, "id-consumidor", "id-
destino", "usuario123",
"Bearer tokenEjemplo");
}

public ResponseEntity<String> updateResource(String id, Map<String,


Object> body) {
return exampleClient.updateResource(id, body, "id-consumidor",
"id-destino", "usuario123",
"Bearer tokenEjemplo");
}

public ResponseEntity<String> deleteResource(String id) {


return exampleClient.deleteResource(id, "id-consumidor", "id-
destino", "usuario123",
"Bearer tokenEjemplo");
}
}

Consideraciones:
 Autenticación: Se usa Basic Auth codificado en Base64 para GET y Bearer
Token para los demás.
 Headers personalizados: Se establecen idConsumidor, idDestino, usuario y
oauth.bearer.
 Uso de Query Params: Implementado en la petición GET con @RequestParam.

Esto optimiza la comunicación entre tus microservicios en AWS con Feign Client.
¿Necesitas ajustes en la estructura o te gustaría agregar manejo de errores con
Resilience4j? 🚀
Sí, si pasas un objeto PagoRequest dentro de un Map<String, Object>, Spring Boot con
Feign Client lo convertirá automáticamente a JSON, siempre que la configuración
predeterminada de Jackson esté activa. Sin embargo, si necesitas controlar el formato de
solicitud y respuesta (JSON o XML), aquí te explico cómo hacerlo:

1. Especificar JSON o XML en la solicitud y respuesta

Spring Boot usa Content-Type y Accept para definir el formato de datos. Puedes
especificarlo en Feign Client con produces y consumes:

@FeignClient(name = "paymentService", url = "https://api.example.com")


public interface PaymentClient {

@PostMapping(value = "/processPayment", consumes =


"application/json", produces = "application/json")
ResponseEntity<String> processPaymentJson(@RequestBody PagoRequest
pagoRequest);

@PostMapping(value = "/processPayment", consumes = "application/xml",


produces = "application/xml")
ResponseEntity<String> processPaymentXml(@RequestBody PagoRequest
pagoRequest);

@PostMapping(value = "/processPayment", consumes =


"application/json", produces = "application/xml")
ResponseEntity<String> processPaymentJsonToXml(@RequestBody
PagoRequest pagoRequest);
}

2. Convertir JSON a XML y viceversa

Si necesitas convertir entre formatos, puedes usar Jackson XML o JAXB:

Convertir JSON a XML


ObjectMapper xmlMapper = new XmlMapper();
String xml = xmlMapper.writeValueAsString(pagoRequest);
Convertir XML a JSON
ObjectMapper jsonMapper = new ObjectMapper();
PagoRequest pagoRequest = jsonMapper.readValue(xmlString,
PagoRequest.class);

3. Configurar Spring Boot para soportar XML

Por defecto, Spring Boot usa JSON, pero puedes agregar soporte para XML con Jackson
XML:

<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
Si necesitas más detalles sobre cómo manejar la conversión en tu microservicio, dime y te
ayudo a afinar la configuración. 🚀
Aquí tienes la implementación completa de la comunicación entre microservicios en
Spring Boot con Feign Client, incluyendo autenticación, parámetros, headers y soporte
para JSON/XML.

1. Configuración de Feign Client

Asegúrate de habilitar Feign en tu aplicación:

@EnableFeignClients
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

2. Definición del Cliente Feign


@FeignClient(name = "paymentService", url = "https://api.example.com")
public interface PaymentClient {

@GetMapping(value = "/payment", consumes = "application/json",


produces = "application/json")
ResponseEntity<String> getPayment(@RequestParam String idPago,
@RequestHeader("idConsumidor")
String idConsumidor,
@RequestHeader("idDestino") String
idDestino,
@RequestHeader("usuario") String
usuario,
@RequestHeader("Authorization")
String auth);

@PostMapping(value = "/payment", consumes = "application/json",


produces = "application/json")
ResponseEntity<String> createPayment(@RequestBody PagoRequest
pagoRequest,
@RequestHeader("idConsumidor")
String idConsumidor,
@RequestHeader("idDestino")
String idDestino,
@RequestHeader("usuario") String
usuario,
@RequestHeader("Authorization")
String auth);

@PutMapping(value = "/payment/{id}", consumes = "application/json",


produces = "application/json")
ResponseEntity<String> updatePayment(@PathVariable String id,
@RequestBody PagoRequest pagoRequest,
@RequestHeader("idConsumidor")
String idConsumidor,
@RequestHeader("idDestino")
String idDestino,
@RequestHeader("usuario") String
usuario,
@RequestHeader("Authorization")
String auth);

@DeleteMapping(value = "/payment/{id}")
ResponseEntity<String> deletePayment(@PathVariable String id,
@RequestHeader("idConsumidor")
String idConsumidor,
@RequestHeader("idDestino")
String idDestino,
@RequestHeader("usuario") String
usuario,
@RequestHeader("Authorization")
String auth);
}

3. Modelo DTO: PagoRequest


@Data
public class PagoRequest {
private String idPago;
private String monto;
private String metodoPago;
private String moneda;
private String descripcion;
}

4. Servicio para invocar Feign Client


@Service
public class PaymentService {

private final PaymentClient paymentClient;

public PaymentService(PaymentClient paymentClient) {


this.paymentClient = paymentClient;
}

public ResponseEntity<String> getPayment(String idPago) {


return paymentClient.getPayment(idPago, "id-consumidor", "id-
destino", "usuario123",
"Basic " +
Base64.getEncoder().encodeToString("user:password".getBytes()));
}
public ResponseEntity<String> createPayment(PagoRequest pagoRequest)
{
return paymentClient.createPayment(pagoRequest, "id-consumidor",
"id-destino", "usuario123",
"Bearer tokenEjemplo");
}

public ResponseEntity<String> updatePayment(String id, PagoRequest


pagoRequest) {
return paymentClient.updatePayment(id, pagoRequest, "id-
consumidor", "id-destino", "usuario123",
"Bearer tokenEjemplo");
}

public ResponseEntity<String> deletePayment(String id) {


return paymentClient.deletePayment(id, "id-consumidor", "id-
destino", "usuario123",
"Bearer tokenEjemplo");
}
}

5. Configuración de JSON y XML

Para soportar XML, agrega la dependencia Jackson XML:

<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

Si necesitas que Spring Boot convierta entre JSON y XML dinámicamente:

@PostMapping(value = "/payment", consumes = "application/json", produces


= "application/xml")
ResponseEntity<String> processPaymentJsonToXml(@RequestBody PagoRequest
pagoRequest);

6. Conversión entre JSON y XML manualmente

Si necesitas convertir de forma programática:

ObjectMapper xmlMapper = new XmlMapper();


String xml = xmlMapper.writeValueAsString(pagoRequest);

ObjectMapper jsonMapper = new ObjectMapper();


PagoRequest pagoRequest = jsonMapper.readValue(xmlString,
PagoRequest.class);
Esto te permite manejar la comunicación entre microservicios con Spring Boot y AWS,
integrando seguridad, formatos y headers personalizados. ¿Quieres agregar manejo de
errores con Resilience4j o integración con AWS API Gateway? 🚀
Sí, cuando los métodos en Feign Client requieren demasiados parámetros, puedes mejorar
la organización usando objetos de request para encapsular los Query Params y Headers.
Aquí te dejo dos enfoques óptimos:

1. Usar un DTO para Query Params

En lugar de pasar cada parámetro individualmente, puedes definir un objeto de solicitud:

@Data
public class PaymentQueryParams {
private String idPago;
private String moneda;
private String metodoPago;
}

En la interfaz Feign:

@FeignClient(name = "paymentService", url = "https://api.example.com")


public interface PaymentClient {

@GetMapping("/payment")
ResponseEntity<String> getPayment(@SpringQueryMap PaymentQueryParams
params,
@RequestHeader("Authorization")
String auth);
}

Aquí, @SpringQueryMap permite que Feign convierta automáticamente el objeto


PaymentQueryParams en Query Params.

2. Usar un DTO para Headers

Si tienes demasiados headers, puedes definir un objeto para encapsularlos:

@Data
public class PaymentHeaders {
private String idConsumidor;
private String idDestino;
private String usuario;
private String authorization;
}

Luego, en la interfaz Feign:

@FeignClient(name = "paymentService", url = "https://api.example.com")


public interface PaymentClient {

@PostMapping("/payment")
ResponseEntity<String> createPayment(@RequestBody PagoRequest
pagoRequest,
@RequestHeaderMap Map<String,
String> headers);
}

Cuando invoques el servicio, construyes el mapa de headers:

Map<String, String> headers = Map.of(


"idConsumidor", "12345",
"idDestino", "destinoX",
"usuario", "usuarioEjemplo",
"Authorization", "Bearer tokenEjemplo"
);

ResponseEntity<String> response =
paymentClient.createPayment(pagoRequest, headers);

Beneficios de esta implementación

✅ Código más limpio: Reduce la cantidad de parámetros en los métodos.


✅ Facilidad de mantenimiento: Si agregas nuevos headers o query params, solo modificas
el DTO.
✅ Flexibilidad: Los objetos pueden reutilizarse en varias llamadas.

Esta estrategia simplifica la comunicación entre microservicios y mejora la organización


del código en Spring Boot. 🚀 ¿Quieres que agreguemos validaciones o manejo de errores?
Buena observación. En el ejemplo anterior, PaymentHeaders no se usó directamente en el
método de Feign porque en lugar de pasar un objeto DTO como parámetro, opté por
RequestHeaderMap, que usa un Map<String, String> para manejar los headers de
manera flexible. Sin embargo, si prefieres usar un DTO, puedes modificar el código así:

@Data
public class PaymentHeaders {
private String idConsumidor;
private String idDestino;
private String usuario;
private String authorization;
}

En la interfaz Feign Client, podrías recibir el objeto directamente y mapear los headers:

@FeignClient(name = "paymentService", url = "https://api.example.com")


public interface PaymentClient {

@PostMapping("/payment")
ResponseEntity<String> createPayment(@RequestBody PagoRequest
pagoRequest,
@RequestHeader("idConsumidor")
String idConsumidor,
@RequestHeader("idDestino")
String idDestino,
@RequestHeader("usuario") String
usuario,
@RequestHeader("Authorization")
String auth);
}

Y en el servicio donde consumes Feign:

public ResponseEntity<String> createPayment(PagoRequest pagoRequest,


PaymentHeaders headers) {
return paymentClient.createPayment(pagoRequest,
headers.getIdConsumidor(),
headers.getIdDestino(),
headers.getUsuario(),
headers.getAuthorization());
}

Sobre @Data

La anotación @Data no es propia de Spring Boot, sino de Lombok, una biblioteca que
ayuda a reducir código repetitivo. @Data genera automáticamente getters, setters,
toString(), equals(), hashCode(), y el constructor sin argumentos.

Para usar Lombok, necesitas agregar esta dependencia en Maven:

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>

Si usas Gradle:

dependencies {
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
}

Además, en algunos IDEs como IntelliJ o Eclipse, necesitas habilitar soporte para Lombok.

¿Te gustaría más detalles sobre cómo integrar Lombok o mejorar el manejo de Feign
Client? 🚀
Sí, para los headers en Feign Client, no existe una anotación equivalente a
@SpringQueryMap, pero puedes mejorar la organización usando @RequestHeaderMap, que
permite pasar un mapa de headers dinámicamente en lugar de definir cada uno como
argumento individual.

Uso de @RequestHeaderMap

En lugar de pasar cada header como parámetro, puedes definir un Map<String, String>:

@FeignClient(name = "paymentService", url = "https://api.example.com")


public interface PaymentClient {

@PostMapping("/payment")
ResponseEntity<String> createPayment(@RequestBody PagoRequest
pagoRequest,
@RequestHeaderMap Map<String,
String> headers);
}

Cómo invocar el método


Map<String, String> headers = Map.of(
"idConsumidor", "12345",
"idDestino", "destinoX",
"usuario", "usuarioEjemplo",
"Authorization", "Bearer tokenEjemplo"
);

ResponseEntity<String> response =
paymentClient.createPayment(pagoRequest, headers);

Ventajas de @RequestHeaderMap

✅ Código más limpio: No necesitas definir cada header como argumento.


✅ Flexibilidad: Puedes agregar o modificar headers sin cambiar la firma del método.
✅ Reutilización: Puedes construir el mapa de headers en un interceptor o servicio
centralizado.

Si quieres mejorar aún más la gestión de headers, puedes usar un Feign


RequestInterceptor para establecerlos automáticamente en cada solicitud. 🚀 ¿Te gustaría
que te muestre cómo hacerlo?
¡Por supuesto! Aquí tienes ejemplos de Resilience4j, timeouts, balanceo de carga y
integración con AWS API Gateway en Spring Boot.

1. Implementación de Resilience4j (Circuit Breaker y TimeLimiter)

Resilience4j ayuda a manejar fallos en microservicios con patrones como Circuit Breaker
y TimeLimiter.

Ejemplo de Circuit Breaker


@CircuitBreaker(name = "paymentService", fallbackMethod =
"fallbackMethod")
public String processPayment() {
return restTemplate.getForObject("https://api.example.com/payment",
String.class);
}

public String fallbackMethod(Exception e) {


return "Servicio no disponible, por favor intenta más tarde.";
}

✅ Evita fallos en cascada cuando un servicio externo no responde.

Ejemplo de TimeLimiter
@TimeLimiter(name = "paymentService")
public CompletableFuture<String> processPaymentAsync() {
return CompletableFuture.supplyAsync(() ->
restTemplate.getForObject("https://api.example.com/payment",
String.class));
}

✅ Limita el tiempo de espera de una operación asíncrona.

Más detalles sobre timeouts con Resilience4j aquí.

2. Configuración de Timeouts en Spring Boot

Para establecer timeouts en Feign Client:

@Bean
public Request.Options feignOptions() {
return new Request.Options(2, TimeUnit.SECONDS, 5, TimeUnit.SECONDS,
true);
}

✅ Evita bloqueos si un servicio tarda demasiado en responder.


Más información sobre timeouts con Resilience4j aquí.

3. Balanceo de Carga con Spring Cloud LoadBalancer

Si tienes múltiples instancias de un microservicio, puedes usar Spring Cloud


LoadBalancer:

@Bean
public ReactorLoadBalancer<ServiceInstance> loadBalancer(Environment
environment) {
return new RoundRobinLoadBalancer();
}

✅ Distribuye tráfico entre instancias de microservicios.

4. Integración con AWS API Gateway

Para exponer microservicios a través de AWS API Gateway, puedes definir un Lambda
Proxy:

@RestController
@RequestMapping("/api")
public class PaymentController {

@PostMapping("/payment")
public ResponseEntity<String> processPayment(@RequestBody PagoRequest
request) {
return ResponseEntity.ok("Pago procesado correctamente");
}
}

✅ Centraliza la gestión de APIs y mejora la seguridad.

Si necesitas más detalles sobre AWS API Gateway, dime y te ayudo a afinar la
configuración. 🚀
Para mejorar la eficiencia y resiliencia de Feign Client en Spring Boot, puedes
implementar caché, reintentos y timeouts. Aquí te dejo ejemplos de cada uno:

1. Manejo de Caché con Feign Client

Feign no soporta @Cacheable directamente, pero puedes usar Spring Cache en un servicio
que envuelve la llamada Feign:

Configuración de Caché
@EnableCaching
@Configuration
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("payments");
}
}
Uso de @Cacheable en un Servicio
@Service
public class PaymentService {

private final PaymentClient paymentClient;

public PaymentService(PaymentClient paymentClient) {


this.paymentClient = paymentClient;
}

@Cacheable(value = "payments", key = "#idPago")


public ResponseEntity<String> getPayment(String idPago) {
return paymentClient.getPayment(idPago, "Bearer tokenEjemplo");
}
}

✅ Reduce llamadas repetitivas a microservicios.


✅ Mejora el rendimiento al almacenar respuestas en caché.

2. Sistema de Reintentos con Feign Client

Feign no tiene reintentos por defecto, pero puedes usar Resilience4j Retry:

Configuración de Reintentos
@Bean
public RetryRegistry retryRegistry() {
return RetryRegistry.ofDefaults();
}
@Bean
public Retry retry() {
return retryRegistry().retry("paymentService", RetryConfig.custom()
.maxAttempts(3)
.waitDuration(Duration.ofSeconds(2))
.build());
}
Aplicar Reintentos en Feign Client
@Retry(name = "paymentService", fallbackMethod = "fallbackMethod")
public ResponseEntity<String> getPayment(String idPago) {
return paymentClient.getPayment(idPago, "Bearer tokenEjemplo");
}

public ResponseEntity<String> fallbackMethod(String idPago, Exception e)


{
return
ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body("Servicio no
disponible.");
}

✅ Evita fallos temporales al reintentar solicitudes.


✅ Mejora la tolerancia a errores en microservicios.

3. Configuración de Timeouts en Feign Client

Puedes establecer timeouts en Feign para evitar bloqueos:

Configuración de Timeouts
@Bean
public Request.Options feignOptions() {
return new Request.Options(2, TimeUnit.SECONDS, 5, TimeUnit.SECONDS,
true);
}

✅ Evita bloqueos si un servicio tarda demasiado en responder.


✅ Mejora la experiencia del usuario al limitar tiempos de espera.

Conclusión

Si buscas rendimiento, usa caché.


Si necesitas resiliencia, usa reintentos con Resilience4j.
Si quieres controlar tiempos de espera, configura timeouts en Feign.

¿Quieres que te ayude a integrar esto en tu arquitectura de microservicios en AWS? 🚀

También podría gustarte