Multiple Configurations for Feign Clients

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign, create an interface and annotate it. It has pluggable annotation support including Feign and JAX-RS annotations.

Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced HTTP client when using Feign. (https://cloud.spring.io)

Creating a Feign client in Spring cloud is simple. All you have to do is to create an interface and annotate it with @FeignClient.

Requests generated by Feign clients can have configurations, for example how to encode, decode and intercept requests.

Consider a Feign client that must be used with different configurations at different places in the code, or multiple Feign clients that each must be used with its own configuration. For example Feign client A must be configured with decoder A and request interceptor A and Feign client B with decoder B and interceptor B.

One possible scenario is setting different authentication approaches for different Feign clients.

Let’s get our hands dirty:

Suppose there are two Rest API, one for getting “Bar” objects on Bar server and another for getting “Foo” Objects on Foo server. The problem is that those services have different authentication approaches.

We have two Feign clients for two services, FooClient and BarClient. These Feign clients need to adopt different authentication configuration.

Here is the FooClient class. The FeignClient has a fooContextId, value and specific url and is configured in FooConfig class.

@FeignClient(contextId = "fooContextId", value = "fooValue", url = "http://foo-server.com/services", configuration = FooConfig.class)
public interface FooFeignClient {

@GetMapping("{id}/foo")
void getFoo(@PathVariable("id") Long id);
}

And this is the BarClient class. Again, it has its own specific contextId, value, url and BarConfig.

@@FeignClient(contextId = "barContextId", value = "barValue", url = "http://bar-server.com/services", configuration = BarConfig.class)
public interface BarFeignClient {

@GetMapping("{id}/bar")
void getBar(@PathVariable("id") Long id);
}

BarConfig and FooConfig should not be annotated with @Component or any other Spring bean annotations.

Next, we should instantiate BarRequestInterceptor and FooRequestInterceptor beans in these configuration classes.

public class BarConfig {

@Bean
public BarRequestInterceptor barRequestInterceptor() {
return new BarRequestInterceptor();
}
}
public class FooConfig {

@Bean
public FooRequestInterceptor fooRequestInterceptor() {
return new FooRequestInterceptor();
}
}

Both BarRequestInterceptor and FooRequestInterceptor classes implement RequestInterceptor and must override apply method to specify their own authentication approaches.

public class BarRequestInterceptor implements RequestInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(BarRequestInterceptor.class);

@Override
public void apply(RequestTemplate template) {
template.header("authorization", "auth-bar");
LOGGER.info("bar authentication applied");
}
}
public class FooRequestInterceptor implements RequestInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(FooRequestInterceptor.class);

@Override
public void apply(RequestTemplate template) {
template.header("authorization", "auth-foo");
LOGGER.info("foo authentication applied");
}
}

Finally, create a method to call these Feign clients:

@RestController
public class HomeController {
private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class);

@Autowired
private FooFeignClient fooFeignClient;
@Autowired
private BarFeignClient barFeignClient;

@GetMapping("test")
public void home() {
try {
LOGGER.info("calling getFoo");
fooFeignClient.getFoo(100L);
} catch (Exception e) {
}

try {
LOGGER.info("calling getBar");
barFeignClient.getBar(100L);
} catch (Exception e) {
}
}
}

If we run the application and call the home controller, first “getFoo” method of FooClient with FooConfiguration will be invoked and then “bar” method of BarClient with BarConfiguration. This is output log of this request:

2019-11-28 22:33:17.041  INFO 18208 --- [nio-8080-exec-1] com.example.feignconfig.HomeController   : calling getFoo2019-11-28 22:33:17.046  INFO 18208 --- [nio-8080-exec-1] c.e.f.foo.FooRequestInterceptor          : foo authentication applied2019-11-28 22:33:17.472  INFO 18208 --- [nio-8080-exec-1] com.example.feignconfig.HomeController   : calling getBar2019-11-28 22:33:17.473  INFO 18208 --- [nio-8080-exec-1] c.e.f.bar.BarRequestInterceptor          : bar authentication applied

You can find source code of this tutorial on my GitHub repository:

https://github.com/shokri4971/multiple-feign-config

Java Developer