skip to content

OpenFeign Declarative Clients

@FeignClient turns an annotated interface into an HTTP client, with pluggable encoders, decoders, error decoders and interceptors. Interviewers ask what an ErrorDecoder is for, since silently mapping a 500 to null is how bad data spreads.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is Spring Cloud OpenFeign, and how do you declare and enable a Feign client?

level: juniorimportance: must knowfreq 78%

answer

  1. interface + @FeignClient = proxy
  2. @EnableFeignClients scans & registers
  3. name = service id, url = fixed host
  4. MVC annotations on methods
  5. spring-cloud-starter-openfeign

basics

~10 s

OpenFeign lets you call another HTTP service by declaring a Java interface annotated with @FeignClient. You add @EnableFeignClients to a config class, and Spring generates a proxy that turns method calls into HTTP requests.

solid answer

~40 s

Spring Cloud OpenFeign is a declarative REST client: instead of hand-writing HTTP calls with RestTemplate or WebClient, you define an interface, annotate it with @FeignClient(name = "..."), and put MVC-style annotations (@GetMapping, @PathVariable, etc.) on its methods. Spring creates a runtime proxy implementing the interface; each method call is translated into a real HTTP request, sent, and the response is deserialized into the return type. You activate scanning with @EnableFeignClients on a @Configuration/@SpringBootApplication class. The `name` (or `value`) identifies the client and, when using a service registry/load balancer, resolves to instances; a literal `url` bypasses discovery and targets a fixed host. You inject the interface anywhere like any other Spring bean.

code

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

@FeignClient(name = "catalog", url = "${catalog.url}")
public interface CatalogClient {

    @GetMapping("/products/{id}")
    Product getProduct(@PathVariable("id") Long id);

    @PostMapping("/products")
    Product create(@RequestBody NewProduct body);
}

@Service
public class ProductService {
    private final CatalogClient catalog;
    ProductService(CatalogClient catalog) { this.catalog = catalog; }
    Product find(Long id) { return catalog.getProduct(id); }
}

go deeper

for a junior

Know that you declare an interface, annotate with @FeignClient, and enable scanning with @EnableFeignClients.

for a middle

Understand name-vs-url, the proxy mechanism, and required starter dependencies.

for a senior

Explain discovery/load-balancing resolution of name, contextId, and blocking nature vs WebClient.

for a principal

Weigh Feign vs WebClient/RestClient at architecture level, discovery integration, and lifecycle of generated proxies.

## What OpenFeign is **Feign** is a declarative HTTP client library originally from Netflix. **Spring Cloud OpenFeign** integrates it into the Spring ecosystem so you can call remote HTTP APIs by writing only an *interface* — no client boilerplate. At startup Spring generates a dynamic **proxy** that implements the interface; when you call a method, Feign builds an HTTP request from the method's annotations/arguments, executes it, and converts the HTTP response back into the declared return type. ## The two core annotations - **`@EnableFeignClients`** — placed on a `@Configuration` or `@SpringBootApplication` class. It triggers a classpath scan for interfaces annotated with `@FeignClient` and registers a proxy bean for each. Without it, your `@FeignClient` interfaces are never turned into beans. You can narrow the scan with `basePackages` / `clients`. - **`@FeignClient`** — placed on the interface. Key attributes: - `name` / `value` — a logical client name. With a load balancer (Spring Cloud LoadBalancer) this is treated as a **service id** resolved via discovery. - `url` — a hardcoded absolute base URL (e.g. `https://api.example.com`). When present, discovery/load-balancing is bypassed and requests go straight to that host. Useful for third-party APIs. - `path` — a prefix prepended to every method mapping. - `configuration` — a per-client config class supplying custom beans (Encoder, Decoder, etc.). - `contextId` — disambiguates when two clients share the same `name`. - `fallback` / `fallbackFactory` — circuit-breaker fallbacks (require a CircuitBreaker on the classpath and enabled). ## Minimal example flow ``` @FeignClient(name = "catalog", url = "https://catalog.example.com") interface CatalogClient { @GetMapping("/products/{id}") Product getProduct(@PathVariable Long id); } ``` Calling `catalogClient.getProduct(42L)` issues `GET https://catalog.example.com/products/42`, then deserializes the JSON body into a `Product`. ## Dependencies You need `spring-cloud-starter-openfeign` on the classpath, and a Spring Cloud BOM to align versions. For load-balanced (`name`-only) clients you also need `spring-cloud-starter-loadbalancer` plus a discovery client. ## When to use it Great for internal service-to-service calls in a Spring Cloud microservice mesh, and for wrapping third-party REST APIs behind a typed interface. For reactive/streaming or high-concurrency non-blocking needs, prefer `WebClient` (Feign is blocking by default) — though a reactive `spring-cloud-openfeign` variant exists as a community project. ## Common gotchas - Forgetting `@EnableFeignClients` → the interface isn't a bean, injection fails. - Using plain JAX-RS annotations expecting them to work — the default Spring contract expects Spring MVC annotations. - Assuming Feign is non-blocking — the default synchronous client blocks the calling thread.

  • What is the difference between the `name` and `url` attributes of @FeignClient?
    `name` is a logical client id; with a load balancer it resolves to service instances via discovery. `url` hardcodes an absolute base URL and bypasses discovery/load-balancing. You can supply both — `url` wins for the target host while `name`/`contextId` still identify the client's configuration context.
  • Is a default Feign client blocking or non-blocking?
    Blocking. The default synchronous Feign client executes the HTTP call on the calling thread and waits for the response. For non-blocking I/O you'd use WebClient instead.

saying these in an interview costs you the question

  • Thinking @FeignClient alone works without @EnableFeignClients somewhere
  • Believing Feign is reactive/non-blocking by default
  • Assuming you must write an implementation class for the interface
  • Confusing `url` and `name` — thinking `name` is just a label with no discovery meaning

context

open as a page

How do ErrorDecoder and RequestInterceptor work in Feign, and when would you customize each?

level: seniorimportance: must knowfreq 62%

basics

~20 s

A RequestInterceptor mutates every outgoing request (e.g. add an auth header) before it is sent. An ErrorDecoder converts a non-2xx HTTP response into an exception you choose, letting you map status codes to domain exceptions or trigger retries.

open as a page

What roles do the Encoder and Decoder play in a Feign client, and how do you customize them?

level: middleimportance: should knowfreq 48%

basics

~20 s

The Encoder serializes a method argument (like a @RequestBody object) into the HTTP request body; the Decoder deserializes the HTTP response body into the method's return type. By default Spring Cloud OpenFeign uses Spring's HttpMessageConverters (Jackson JSON).

open as a page

How do MVC-style annotations work on a Feign client, and what is the Contract responsible for?

level: middleimportance: should knowfreq 58%

basics

~10 s

Spring Cloud OpenFeign uses a SpringMvcContract so you can annotate Feign methods with @GetMapping, @PathVariable, @RequestParam, @RequestBody, @RequestHeader — the same annotations as MVC controllers. The Contract parses these into a request template.

open as a page

How does Feign client configuration scoping work, and what pitfalls arise with default-config, contextId, and shared interfaces?

level: principalimportance: should knowfreq 40%

basics

~20 s

Each Feign client gets its own child application context holding its Encoder, Decoder, Contract, interceptors, etc. Beans in @FeignClients(defaultConfiguration=...) or the client's own configuration apply per-client; a @Configuration under component scan applies globally. Properties in application.yml can override code config.

open as a page