OpenFeign cliente REST declarativo

Intermedio
SpringBoot
SpringBoot
Actualizado: 09/10/2025

@FeignClient: definición básica

OpenFeign es un cliente HTTP declarativo que simplifica notablemente la comunicación entre microservicios. A diferencia de los clientes HTTP tradicionales donde necesitas configurar manualmente las peticiones, Feign permite definir la comunicación mediante interfaces Java anotadas.

La filosofía de Feign se basa en que escribir clientes HTTP no debería ser más complicado que definir un contrato de interfaz. Spring Cloud OpenFeign se integra perfectamente con el ecosistema Spring, proporcionando balanceado de carga automático y descubrimiento de servicios sin configuración adicional.

Dependencias y habilitación

Para utilizar OpenFeign en tu proyecto Spring Boot, necesitas incluir la dependencia correspondiente:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Una vez añadida la dependencia, debes habilitar los clientes Feign en tu aplicación principal usando la anotación @EnableFeignClients:

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

La anotación @EnableFeignClients instruye a Spring para que escanee automáticamente las interfaces anotadas con @FeignClient y cree los beans proxy correspondientes.

Creación de un cliente básico

Un cliente Feign se define como una interfaz Java anotada con @FeignClient. Esta interfaz especifica el contrato de comunicación con el servicio remoto:

@FeignClient(name = "usuario-service")
public interface UsuarioClient {
    
    @GetMapping("/usuarios/{id}")
    Usuario obtenerUsuario(@PathVariable("id") Long id);
    
    @GetMapping("/usuarios")
    List<Usuario> obtenerTodosLosUsuarios();
    
    @PostMapping("/usuarios")
    Usuario crearUsuario(@RequestBody Usuario usuario);
}

El atributo name de @FeignClient especifica el nombre del servicio tal como está registrado en Eureka. Spring Cloud LoadBalancer utilizará este nombre para resolver las instancias disponibles y aplicar balanceado de carga automáticamente.

Uso del cliente en componentes Spring

Una vez definido el cliente, puedes inyectarlo en cualquier componente Spring como si fuera un bean normal:

@RestController
public class UsuarioController {
    
    private final UsuarioClient usuarioClient;
    
    public UsuarioController(UsuarioClient usuarioClient) {
        this.usuarioClient = usuarioClient;
    }
    
    @GetMapping("/api/usuarios/{id}")
    public ResponseEntity<Usuario> obtenerDetalleUsuario(@PathVariable Long id) {
        Usuario usuario = usuarioClient.obtenerUsuario(id);
        return ResponseEntity.ok(usuario);
    }
}

En este ejemplo, cuando se invoca usuarioClient.obtenerUsuario(id), Feign automáticamente:

  • Resuelve la URL del servicio usando Eureka y LoadBalancer
  • Serializa los parámetros de entrada
  • Ejecuta la petición HTTP GET
  • Deserializa la respuesta JSON al objeto Usuario

Anotaciones Spring MVC compatibles

OpenFeign soporta las anotaciones estándar de Spring MVC, lo que hace que la definición de clientes sea familiar y consistente:

  • @GetMapping, @PostMapping, @PutMapping, @DeleteMapping: para especificar el método HTTP y la ruta
  • @PathVariable: para variables de ruta
  • @RequestParam: para parámetros de consulta
  • @RequestBody: para el cuerpo de la petición
  • @RequestHeader: para headers HTTP personalizados
@FeignClient(name = "producto-service")
public interface ProductoClient {
    
    @GetMapping("/productos")
    List<Producto> buscarProductos(
        @RequestParam("categoria") String categoria,
        @RequestParam("activo") boolean activo
    );
    
    @PutMapping("/productos/{id}")
    Producto actualizarProducto(
        @PathVariable("id") Long id,
        @RequestBody Producto producto,
        @RequestHeader("Authorization") String token
    );
}

Configuración de paquetes de escaneo

Por defecto, @EnableFeignClients escanea el paquete de la clase anotada y sus subpaquetes. Para mayor control sobre el escaneo, puedes especificar paquetes explícitos:

@SpringBootApplication
@EnableFeignClients(basePackages = "com.empresa.clientes")
public class MicroserviceApplication {
    // ...
}

También puedes listar clientes específicos si prefieres un control más granular:

@SpringBootApplication
@EnableFeignClients(clients = {UsuarioClient.class, ProductoClient.class})
public class MicroserviceApplication {
    // ...
}

Integración con el ecosistema Spring Cloud

Lo que hace especialmente valioso a OpenFeign es su integración transparente con otros componentes de Spring Cloud. Cuando defines un cliente con @FeignClient(name = "usuario-service"), automáticamente se beneficia de:

  • Descubrimiento de servicios a través de Eureka
  • Balanceado de carga client-side con Spring Cloud LoadBalancer
  • Configuración centralizada mediante Spring Cloud Config
  • Tolerancia a fallos cuando se combina con circuit breakers

Esta integración significa que puedes reemplazar llamadas RestTemplate complejas con interfaces Feign simples, manteniendo todas las capacidades de resiliencia y escalabilidad que necesitas en una arquitectura de microservicios.

Timeouts e interceptores en Feign

Una vez que tienes clientes Feign funcionando, es fundamental configurar timeouts apropiados y personalizar el comportamiento mediante interceptores. Estas configuraciones son esenciales para garantizar la resiliencia y el comportamiento adecuado en entornos de microservicios.

Configuración de timeouts

Los timeouts en Feign se configuran a través de propiedades en application.yml o application.properties. Puedes definir timeouts globales para todos los clientes o específicos para cada servicio:

Configuración global:

feign:
  client:
    config:
      default:
        connect-timeout: 5000    # 5 segundos para establecer conexión
        read-timeout: 10000      # 10 segundos para leer respuesta

Configuración específica por servicio:

feign:
  client:
    config:
      usuario-service:
        connect-timeout: 3000
        read-timeout: 8000
      producto-service:
        connect-timeout: 2000
        read-timeout: 15000

El connect-timeout define cuánto tiempo esperar para establecer la conexión TCP, mientras que el read-timeout especifica el tiempo máximo para recibir la respuesta completa del servidor.

Interceptores de petición

Los interceptores de petición (RequestInterceptor) permiten modificar todas las peticiones salientes antes de que sean enviadas. Son especialmente útiles para añadir headers de autenticación, logging o cualquier lógica transversal:

@Component
public class AuthenticationInterceptor implements RequestInterceptor {
    
    @Override
    public void apply(RequestTemplate template) {
        // Añadir token de autorización
        String token = obtenerTokenActual();
        template.header("Authorization", "Bearer " + token);
        
        // Añadir headers adicionales
        template.header("X-Request-ID", UUID.randomUUID().toString());
        template.header("Content-Type", "application/json");
    }
    
    private String obtenerTokenActual() {
        // Lógica para obtener el token actual
        return "jwt-token-ejemplo";
    }
}

Para registrar el interceptor globalmente para todos los clientes Feign:

@Configuration
public class FeignConfiguration {
    
    @Bean
    public RequestInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }
}

Interceptores específicos por cliente

También puedes aplicar interceptores solo a clientes específicos utilizando la configuración en @FeignClient:

@FeignClient(
    name = "usuario-service",
    configuration = UsuarioFeignConfiguration.class
)
public interface UsuarioClient {
    // métodos del cliente
}
@Configuration
public class UsuarioFeignConfiguration {
    
    @Bean
    public RequestInterceptor usuarioInterceptor() {
        return template -> {
            template.header("X-Service", "usuario-service");
            template.header("X-Version", "v2");
        };
    }
}

Interceptor de logging personalizado

Un caso común es implementar logging detallado de las peticiones para debugging y monitoreo:

@Component
@Slf4j
public class LoggingInterceptor implements RequestInterceptor {
    
    @Override
    public void apply(RequestTemplate template) {
        log.info("Feign Request: {} {} to {}", 
                template.method(), 
                template.path(), 
                template.feignTarget().name());
        
        // Log headers (sin información sensible)
        template.headers().forEach((name, values) -> {
            if (!esSensible(name)) {
                log.debug("Header: {} = {}", name, values);
            }
        });
        
        // Log body para peticiones POST/PUT
        if (template.body() != null) {
            log.debug("Request Body: {}", new String(template.body()));
        }
    }
    
    private boolean esSensible(String headerName) {
        return headerName.toLowerCase().contains("authorization") ||
               headerName.toLowerCase().contains("password");
    }
}

Configuración avanzada de timeouts por propiedades

Para mayor flexibilidad, puedes externalizar la configuración de timeouts usando propiedades personalizadas:

app:
  feign:
    timeouts:
      usuario-service:
        connect: 3000
        read: 8000
      producto-service:
        connect: 2000
        read: 12000
@Configuration
public class FeignTimeoutConfiguration {
    
    @Value("${app.feign.timeouts.usuario-service.connect:5000}")
    private int usuarioConnectTimeout;
    
    @Value("${app.feign.timeouts.usuario-service.read:10000}")
    private int usuarioReadTimeout;
    
    @Bean
    @ConditionalOnProperty(name = "app.feign.timeouts.usuario-service.connect")
    public Request.Options usuarioServiceOptions() {
        return new Request.Options(
            usuarioConnectTimeout, 
            TimeUnit.MILLISECONDS,
            usuarioReadTimeout, 
            TimeUnit.MILLISECONDS,
            true // followRedirects
        );
    }
}

Interceptor para manejo de errores

Puedes implementar interceptores que preprocesen respuestas de error para logging o transformación:

@Component
public class ErrorHandlingInterceptor implements RequestInterceptor {
    
    @Override
    public void apply(RequestTemplate template) {
        // Añadir metadata para tracking de errores
        template.header("X-Request-Timestamp", Instant.now().toString());
        template.header("X-Source-Service", obtenerNombreServicioActual());
    }
    
    private String obtenerNombreServicioActual() {
        return "${spring.application.name:unknown-service}";
    }
}

Configuración declarativa mediante application.yml

Spring Cloud OpenFeign también permite configurar interceptores directamente desde propiedades:

feign:
  client:
    config:
      default:
        request-interceptors:
          - com.empresa.interceptors.AuthenticationInterceptor
          - com.empresa.interceptors.LoggingInterceptor
      usuario-service:
        request-interceptors:
          - com.empresa.interceptors.UsuarioSpecificInterceptor

Mejores prácticas para timeouts

Al configurar timeouts, considera estas recomendaciones:

  • Connect-timeout: generalmente entre 2-5 segundos
  • Read-timeout: depende de la operación, pero típicamente 10-30 segundos
  • Servicios críticos: timeouts más cortos para fail-fast
  • Operaciones pesadas: timeouts más largos para procesos batch o reportes
feign:
  client:
    config:
      # Servicios críticos - timeouts agresivos
      auth-service:
        connect-timeout: 2000
        read-timeout: 5000
      
      # Servicios de consulta - timeouts moderados
      usuario-service:
        connect-timeout: 3000
        read-timeout: 10000
      
      # Servicios de procesamiento - timeouts permisivos
      report-service:
        connect-timeout: 5000
        read-timeout: 30000

La combinación de timeouts apropiados e interceptores bien diseñados garantiza que tus clientes Feign sean robustos, observables y mantenibles en arquitecturas de microservicios complejas.

Fuentes y referencias

Documentación oficial y recursos externos para profundizar en SpringBoot

Documentación oficial de SpringBoot
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, SpringBoot es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de SpringBoot

Explora más contenido relacionado con SpringBoot y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

  • Comprender la filosofía y ventajas de usar OpenFeign como cliente HTTP declarativo.
  • Aprender a definir clientes Feign mediante interfaces Java anotadas con @FeignClient.
  • Configurar timeouts y personalizar peticiones con interceptores en clientes Feign.
  • Integrar OpenFeign con el ecosistema Spring Cloud para balanceo de carga y descubrimiento de servicios.
  • Aplicar buenas prácticas en la configuración de timeouts e interceptores para mejorar la resiliencia y mantenimiento.

Cursos que incluyen esta lección

Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje