67

Is it possible to set dynamic values to a header ?

@FeignClient(name="Simple-Gateway")
interface GatewayClient {
    @Headers("X-Auth-Token: {token}")
    @RequestMapping(method = RequestMethod.GET, value = "/gateway/test")
        String getSessionId(@Param("token") String token);
    }

Registering an implementation of RequestInterceptor adds the header but there is no way of setting the header value dynamically

@Bean
    public RequestInterceptor requestInterceptor() {

        return new RequestInterceptor() {

            @Override
            public void apply(RequestTemplate template) {

                template.header("X-Auth-Token", "some_token");
            }
        };
    } 

I found the following issue on github and one of the commenters (lpborges) was trying to do something similar using headers in @RequestMapping annotation.

https://github.com/spring-cloud/spring-cloud-netflix/issues/288

Kind Regards

Hasnain
  • 1,879
  • 2
  • 13
  • 12

7 Answers7

113

The solution is to use @RequestHeader annotation instead of feign specific annotations

@FeignClient(name="Simple-Gateway")
interface GatewayClient {    
    @RequestMapping(method = RequestMethod.GET, value = "/gateway/test")
    String getSessionId(@RequestHeader("X-Auth-Token") String token);
}
Hasnain
  • 1,879
  • 2
  • 13
  • 12
  • 1
    `@RequestHeader` seems to ignore both its `required` and `defaultValue` parameters when used with Feign. – jaco0646 Jul 25 '19 at 17:19
  • I would highly recommend looking at @David Salazar's answer below. It's the best solution for setting headers dynamically. – loyalBrown Jan 14 '22 at 18:39
27

The @RequestHeader did not work for me. What did work was:

@Headers("X-Auth-Token: {access_token}")
@RequestLine("GET /orders/{id}")
Order get(@Param("id") String id, @Param("access_token") String accessToken);
  • 13
    `@RequestHeader` is a Spring Annotation, `@Headers + @Param` should be used when working with OpenFeign. – silverfox Oct 23 '18 at 11:30
  • Downvoted for the bad suggestion. This has nothing to do with Spring which is clearly mentioned in the title as well as his description with the "@RequestMapping" annotation. – Robert Robertino Mar 13 '23 at 13:45
22

@HeaderMap,@Header and @Param didn't worked for me, below is the solution to use @RequestHeader when there are multiple header parameters to pass using FeignClient

@PostMapping("/api/channelUpdate")
EmployeeDTO updateRecord(
      @RequestHeader Map<String, String> headerMap,
      @RequestBody RequestDTO request);

code to call the proxy is as below:

Map<String, String> headers = new HashMap<>();
headers.put("channelID", "NET");
headers.put("msgUID", "1234567889");
ResponseDTO response = proxy.updateRecord(headers,requestDTO.getTxnRequest());
vijay
  • 609
  • 5
  • 9
3

I have this example, and I use @HeaderParam instead @RequestHeader :

import rx.Single;

import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;


@Consumes(MediaType.APPLICATION_JSON)
public interface  FeignRepository {

  @POST
  @Path("/Vehicles")
  Single<CarAddResponse> add(@HeaderParam(HttpHeaders.AUTHORIZATION) String authorizationHeader, VehicleDto vehicleDto);

}
Oscar Raig Colon
  • 1,302
  • 12
  • 14
2

You can use HttpHeaders.

@PostMapping(path = "${path}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<?> callService(@RequestHeader HttpHeaders headers, @RequestBody Object object);

private HttpHeaders getHeaders() {
  HttpHeaders headers = new HttpHeaders();

  headers.add("Authorization", "1234");
  headers.add("CLIENT_IT", "dummy");
  return headers;
}
0

I use @HeaderMap as it seems very handy if you are working with Open feign. Using this way you can pass header keys and values dynamically.

@Headers({"Content-Type: application/json"})
public interface NotificationClient {

    @RequestLine("POST")
    String notify(URI uri, @HeaderMap Map<String, Object> headers, NotificationBody body);
}

Now create feign REST client to call the service end point, create your header properties map and pass it in method parameter.

NotificationClient notificationClient = Feign.builder()
    .encoder(new JacksonEncoder())
    .decoder(customDecoder())
    .target(Target.EmptyTarget.create(NotificationClient.class));

Map<String, Object> headers = new HashMap<>();
headers.put("x-api-key", "x-api-value");

ResponseEntity<String> response = notificationClient.notify(new URI("https://stackoverflow.com/example"), headers, new NotificationBody());
Muhammad Usman
  • 863
  • 1
  • 11
  • 18
0

A bit late to the game here, but if one needs an enforced, templated value, I discovered that this works in Spring Boot. Apparently, as long as the toString() gives a valid header value, you can use any type.

@FeignClient(
    name = "my-feign-client",
    url = "http://my-url.com"
)
public interface MyClient {
    @GetMapping(
        path = "/the/endpoint",
        produces = MediaType.APPLICATION_JSON_VALUE
    )
    DataResponse getData(@RequestHeader(HttpHeaders.AUTHORIZATION) BearerHeader bearerHeader);
final class BearerHeader {
    private final String token;

    private BearerHeader(String token) {
        this.token = token;
    }

    @Override
    public String toString() {
        return String.format("Bearer %s", token);
    }

    public static BearerHeader of(String token) {
        return new BearerHeader(token);
    }
}
GreenSaguaro
  • 2,968
  • 2
  • 22
  • 41