Setting Up Multiple Configurations for Feign Clients [A Step-by-Step Guide]

Written by shokri4971 | Published 2020/06/21
Tech Story Tags: spring | java | feign | latest-tech-stories | multi-config-feign-clients | feign-and-jax-rs-annotations | foo-feign-client-install-guide | bar-request-interceptor-feign

TLDR 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. Feign is a declarative web service client that makes writing web service clients easier. To use Feign, create an interface and annotate it with @FeignClient. It has pluggable annotation support including Feign and JAX-RS annotations.via the TL;DR App

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 fooContextIdvalue 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, valueurl 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 getFoo
2019-11-28 22:33:17.046  INFO 18208 --- [nio-8080-exec-1] c.e.f.foo.FooRequestInterceptor          : foo authentication applied
2019-11-28 22:33:17.472  INFO 18208 --- [nio-8080-exec-1] com.example.feignconfig.HomeController   : calling getBar
2019-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:


Published by HackerNoon on 2020/06/21