Recently I wrote an article how to explicitly pass headers via Feign clients. Now I’ll show you how to customize each request sent via Feign clients, like adding headers to all of them without the need to explicitly define them using Feign interceptors.
Let’s see the previous example, a translator and a test application.
The client calls the test-app and then it calls to the translator and the translator does the job according to the original Accept-Language header sent by the client.
Let’s see the translator application’s code, it has a single controller:
@RestController("/message") public class TranslationController { @RequestMapping public MessageResponse message(@RequestHeader(value = "Accept-Language") String language) { String message = "english"; if (Locale.GERMANY.equals(Locale.forLanguageTag(language))) { message = "german"; } return new MessageResponse(message); } } class MessageResponse { private String message; // getters/setters/constructor omitted }
Simple. Okay let’s see the test-app’s code. The controller which the client can trigger:
@RestController("/test") public class TestController { @Autowired private TranslationClient client; @RequestMapping public TestResponse get() { MessageResponse messageResponse = client.message(); String message = messageResponse.getMessage(); return new TestResponse(message); } } class TestResponse { private String value; // getters/setters/constructor omitted }
TranslationClient is the Feign client:
@FeignClient(name = "translation", url = "http://localhost:9001") public interface TranslationClient { @RequestMapping("/message") MessageResponse message(); }
As you can see there is no RequestHeader parameter defined for the method so how can we pass the header information?
Feign has a so called RequestInterceptor which will be applied for all the requests sent by Feign clients. The only thing that’s necessary is to define a custom RequestInterceptor class and register it as a Spring bean. Let’s see how it looks:
@Component public class LanguageRequestInterceptor implements RequestInterceptor { private static final String ACCEPT_LANGUAGE_HEADER = "Accept-Language"; @Override public void apply(RequestTemplate requestTemplate) { ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (requestAttributes == null) { return; } HttpServletRequest request = requestAttributes.getRequest(); if (request == null) { return; } String language = request.getHeader(ACCEPT_LANGUAGE_HEADER); if (language == null) { return; } requestTemplate.header(ACCEPT_LANGUAGE_HEADER, language); } }
So the important thing here is to first get the header information from the incoming HTTP request. This can be done using the RequestContextHolder#getRequestAttributes which is holding the current request information. After we got the original request, extracting the Accept-Language header is not a complicated thing to do. Then simply using the RequestTemplate , the header can be set for the Feign requests.
Marking the class with @Component will define it as a Spring bean and we are done.
Now if we try to invoke the test-app from your favorite REST client with the Accept-Language header with value de-DE , you will see the german text coming back in the response.
Using this example, you can customize your requests in any way you like.
The code can be found on my GitHub page. If you are interested in more topics, make sure you follow me on Twitter and shout out if you have questions.
I want to thank you for your blog post. I have an API Gateway, which uses Feign and Zuul; and, I have a backend service which returns a HATEOS response.
The links from the API Gateway was always returning the links from backend service. I was told that the X-forward-Host was not being sent by the requesting http client and had no idea till I saw this post.
If you have a simpler way of sending the header other than an interceptor, please let me know.
Thank you.