Request Customization

About

OpenFeign supports extensive request customization without cluttering our service code. It allows setting custom headers, request parameters, query/path variables, cookies, interceptors, encoders, and more all declaratively or through configuration.

This is essential in enterprise environments where calls may require authentication tokens, dynamic headers, correlation IDs, or different content types per endpoint.

HTTP Methods

OpenFeign supports standard HTTP methods through annotated Java interfaces. Each method maps to a specific REST operation and can be configured with URI templates, query parameters, headers, and request bodies.

Supported HTTP Methods

Method
Feign Annotation
Typical Use Case
Supports Body
Example Signature

GET

@GetMapping / @RequestMapping(method = GET)

Read-only operations (e.g., fetch user, list items)

No

@GetMapping("/users/{id}") UserDto getUser(@PathVariable("id") String id);

POST

@PostMapping

Create resources, form submissions

Yes

@PostMapping("/payments") PaymentResponse create(@RequestBody PaymentRequest r);

PUT

@PutMapping

Full update of existing resource

Yes

@PutMapping("/accounts/{id}") AccountDto update(@PathVariable String id, @RequestBody AccountDto dto);

PATCH

@PatchMapping

Partial updates

Yes

@PatchMapping("/orders/{id}") OrderDto patch(@PathVariable String id, @RequestBody OrderPatch patch);

DELETE

@DeleteMapping

Delete a resource

No (usually)

@DeleteMapping("/users/{id}") void deleteUser(@PathVariable("id") String id);

HEAD

@RequestMapping(method = HEAD)

Retrieve headers or metadata only

No

@RequestMapping(value = "/files/{id}", method = RequestMethod.HEAD) ResponseEntity<?> checkFile(@PathVariable String id);

OPTIONS

@RequestMapping(method = OPTIONS)

Discover allowed methods on resource

No

@RequestMapping(value = "/files", method = RequestMethod.OPTIONS) ResponseEntity<?> options();

Example: Using All Methods in One Interface

@FeignClient(name = "user-service")
public interface UserClient {

    @GetMapping("/users/{id}")
    UserDto getUser(@PathVariable("id") String id);

    @PostMapping("/users")
    UserDto createUser(@RequestBody CreateUserRequest request);

    @PutMapping("/users/{id}")
    UserDto updateUser(@PathVariable("id") String id, @RequestBody UpdateUserRequest request);

    @PatchMapping("/users/{id}")
    UserDto patchUser(@PathVariable("id") String id, @RequestBody PatchUserRequest patch);

    @DeleteMapping("/users/{id}")
    void deleteUser(@PathVariable("id") String id);

    @RequestMapping(value = "/users/{id}", method = RequestMethod.HEAD)
    ResponseEntity<Void> checkUserExists(@PathVariable("id") String id);

    @RequestMapping(value = "/users", method = RequestMethod.OPTIONS)
    ResponseEntity<?> getUserOptions();
}

Setting Multiple Query Parameters

OpenFeign makes it straightforward to define multiple query parameters in method signatures. These parameters are automatically appended to the URL at runtime when the request is constructed.

This is commonly needed in search/filter/list endpoints where multiple filtering criteria, sorting options, pagination details, etc., are passed in the request.

Ways to Set Multiple Query Parameters

1. Using @RequestParam for Each Parameter

Best for fixed number of parameters.

Resulting URL

2. Using a Map for Dynamic Query Parameters

Useful when the number or names of query parameters vary at runtime.

Usage in Service Layer

Resulting URL

3. Combining Fixed and Dynamic Parameters

We can use both fixed and dynamic parameters together in the same method.

URL Example

Setting Multiple Path Variables

In REST APIs, path variables represent dynamic segments in the URI — typically used for identifying specific resources (e.g., /users/{userId}/orders/{orderId}). OpenFeign supports this through method-level @GetMapping or other HTTP method annotations with @PathVariable parameters.

This is especially useful when we need to build RESTful clients that interact with resources based on hierarchical identifiers.

Defining Multiple Path Variables

1. Using Named Placeholders with @PathVariable

We must ensure

  • The path in @GetMapping matches exactly with the placeholders in the method arguments.

  • Each @PathVariable has a matching name (explicitly or implicitly).

Resulting URL

2. Omitting Parameter Names (if method parameter names are preserved)

If our build tool preserves parameter names (e.g., via -parameters flag in the compiler), we can omit explicit names:

This approach works only if our build config includes:

3. Combining Path and Query Parameters

We can also combine path variables and query parameters easily:

Resulting URL

Setting Request Body

In OpenFeign, we can send a request body for methods like POST, PUT, or PATCH by using the @RequestBody annotation. The body is usually a serialized object (e.g., JSON) representing complex data such as forms, DTOs, or domain objects.

This is typically used for:

  • Creating new resources

  • Updating existing resources

  • Passing structured payloads

Example: POST Request with JSON Body

Calling the Client

This will serialize the UserRequest object into a JSON body:

Setting Headers

Headers are a critical part of HTTP requests, conveying metadata such as:

  • Authentication tokens

  • Content types

  • Custom app-level flags (e.g., correlation IDs)

OpenFeign offers multiple ways to set headers for requests:

  1. Statically via annotations

  2. Dynamically via request interceptors

  3. Using @RequestHeader parameters in method signatures

1. Static Headers with @Headers

We can define static headers directly on the method using @Headers from feign.Headers.

Note: Static headers are hardcoded and not suitable for dynamic tokens (e.g., JWTs).

2. Dynamic Headers with @RequestHeader

We can pass headers at runtime using method parameters.

This is useful for:

  • Passing authentication headers per request

  • Setting correlation IDs, tenant IDs, etc.

3. Custom Header Injection via Request Interceptor

For consistent headers across all requests (like JWTs or trace IDs), define a custom RequestInterceptor.

Then attach it to our client:

4. Multiple Headers Example

Invocation

Adding Cookies

Cookies are often used for session management, authentication, or passing stateful information between services. While headers are more commonly used for API tokens, some systems still rely on cookies especially legacy systems or when integrating with frontend-based session handling.

In OpenFeign, cookies can be sent as part of the Cookie HTTP header.

We can add cookies manually by passing them in the Cookie header like any other header.

Calling Code

This is ideal when all Feign clients or specific ones need to send cookies for every request (e.g., for session stickiness or CSRF protection).

Custom Interceptor Example

Attach it to the client

3. Supporting Multiple Cookies

We can pass multiple cookies by separating them with semicolons (;) in a single Cookie header:

4. When we Might Need This ?

Use Case
Example

Integrating with legacy systems

Older systems relying on session cookies instead of token headers

Load-balanced sticky sessions

Routing based on JSESSIONID

Web apps requiring XSRF-TOKEN via cookie

CSRF protection using Spring Security frontend integration

Stateless APIs behind reverse proxies

Proxies managing cookies for routing/authentication

Change content type / accept type

In OpenFeign, we can control the format of requests of send (via Content-Type) and the format of responses we expect (via Accept) using:

  • @RequestHeader annotations

  • Default Feign behavior (via spring-cloud-starter-openfeign)

  • Custom configuration/interceptors for global overrides

These headers are essential for ensuring correct serialization and deserialization of payloads.

1. Content-Type

Specifies the media type of the request body. Common values:

  • application/json

  • application/xml

  • application/x-www-form-urlencoded

  • multipart/form-data

Set Content-Type with @RequestMapping

Explanation:

  • consumes = "application/json" tells Feign and Spring to serialize the request as JSON.

2. Accept

Specifies the expected format of the response. Common values:

  • application/json

  • application/xml

  • text/plain

Set Accept with produces Attribute

Explanation:

  • produces = "application/json" tells the server we expect a JSON response.

3. Set Dynamically via @RequestHeader

Sometimes header values need to be dynamic or client-controlled.

4. Set Globally via RequestInterceptor

To apply consistent content negotiation across all clients:

Use this in a shared config and link it in each @FeignClient(configuration = ...).

Last updated