Declarative Clients with OpenFeign
Declarative Clients with OpenFeign
In the previous lesson you built service-to-service calls with WebClient. It works, but it requires you to assemble URLs by hand, manage headers explicitly, and write imperative reactive chains. As your microservice landscape grows, that boilerplate compounds quickly. Spring Cloud OpenFeign solves this by letting you define an HTTP client as a plain Java interface — the same mental model you already use for Spring Data repositories — and letting the framework generate the implementation for you at startup.
What OpenFeign Is and How It Works
OpenFeign (originally Netflix Feign, now owned by the OpenFeign community) is a declarative HTTP client. You annotate an interface with @FeignClient and standard Spring MVC annotations (@GetMapping, @PostMapping, path variables, request params, request bodies). At startup, Spring Cloud scans for those interfaces and creates JDK dynamic proxies that translate every method call into a real HTTP request.
WebClient you write the how (build a request, add headers, subscribe). With Feign you write the what (call getOrder(id)), and the framework handles the rest. The result is dramatically less code and a much easier audit surface.
Adding the Dependency
Add the Spring Cloud OpenFeign starter to your service's pom.xml. You also need the Spring Cloud BOM in your dependency management block:
Enabling Feign in Your Application
Annotate your main class (or any @Configuration class) with @EnableFeignClients. Without this, Spring will never scan for @FeignClient interfaces.
Declaring Your First Feign Client
Suppose the Order Service needs to look up products from the Inventory Service. The Inventory Service exposes a GET /products/{id} endpoint. Here is the complete Feign client declaration:
A few things to notice:
nameis a logical name used for metrics and (when combined with a service registry) for load-balanced lookup.urlis the base URL, read here fromapplication.yml. In a service-discovery environment (Eureka, Consul) you can omiturland Feign will resolve it from the registry byname.- The method signatures mirror the controller methods in the target service — same annotations, same types.
Injecting and Using the Client
Spring registers the generated proxy as a bean with the interface type. Inject it exactly as you would any other Spring bean:
client package and co-locate its DTO classes there too. This draws a clear boundary: the client package owns everything the external service contract requires, making it easy to swap out or version later.
Sending a Request Body
POST and PUT requests work just as naturally. Annotate the body parameter with @RequestBody:
Customising Request Headers
You often need to propagate headers — correlation IDs, authorization tokens, tenant identifiers — to downstream services. Feign provides two mechanisms:
1. Per-method header annotation — for fixed or caller-supplied header values:
2. Request interceptor — for headers you want added to every call made by a specific client (or globally):
Because this bean is a @Component it is applied globally — every Feign client in the application will forward the correlation ID. To scope it to a single client, declare it inside a @Configuration class and reference it via @FeignClient(configuration = MyConfig.class).
Authorization header from incoming requests. If service A receives a user JWT and forwards it unchanged to service B, you have created a security hole: service B now accepts user-level tokens for what should be an internal, service-to-service call. Use a separate mechanism — a shared secret, mTLS, or a dedicated service account token — for internal communication, and never let user credentials leak between services.
Error Handling with ErrorDecoder
By default, any 4xx or 5xx response from the downstream service throws a generic FeignException. You can map HTTP error codes to domain exceptions with a custom ErrorDecoder:
Register it in a Feign configuration class and reference it from the client annotation to scope it, or declare it as a @Component for global application.
Timeouts and Connection Settings
Feign's timeout defaults are dangerously high in some versions. Set explicit values in application.yml:
OpenFeign vs. WebClient — Choosing the Right Tool
- Use OpenFeign when you want concise, readable, synchronous-style client code and the calling thread can afford to block. It integrates seamlessly with Spring MVC (servlet-stack) applications and is the default choice for most microservice teams.
- Use WebClient when your application is reactive (Spring WebFlux, non-blocking I/O) or when you need fine-grained control over streaming, partial responses, or back-pressure.
- Mixing blocking Feign calls inside a reactive pipeline will stall event-loop threads and degrade the entire application — pick one model and stick to it per service.
Summary
OpenFeign turns inter-service HTTP calls into plain Java interface method invocations. You declare the contract, annotate the methods, inject the bean, and call it. Request interceptors handle cross-cutting header propagation; ErrorDecoder translates HTTP error codes into domain exceptions; YAML properties control timeouts. Combined, these pieces give you a clean, type-safe, auditable communication layer that scales gracefully as the number of services grows. In the next lesson you will add resilience patterns — retries, circuit breakers, and fallbacks — to protect these calls from downstream failures.