Spring Feign Client
Often a service needs to call Http endpoints , Feign comes from the OpenFeign project makes it easier to call http endpoints in a declarative fashion.
Spring has openfeign integration through its Spring Cloud OpenFeign integration.
How To include feign clients
The actual project for feign is OpenFeign https://github.com/OpenFeign/feign . Spring comes with a starter . Add the below dependency to the project
For an example let’s create a service named feign-serviceA which will call feign-serviceB . feign-serviceB exposes a GET endpoint /hello which returns a simple hello response body.
In order to call the endpoint using a feign client from feign-serviceA we need to do following -
- Create an interface annotated with @FeignClient like below
- Add @EnableFeignClients annotation to main class .
and we are all set we can simply autowire ServiceBClient and call method sayHello like any normal method call .
@EnableFeignClients takes a list of clients if we have many feign clients then it is better to mention the clients as argument otherwise spring will do a classpath scan to find out feign clients.
Feign Configuration
Under the hood feign comes with some components which are used to make a call to remote endpoints and encode/decode request response.
- Client — To make HTTP call feign requires http client. By default openfeign comes with a Default Client. We can override it with ApacheHttpClient, OkHttpClient or ApacheHC5FeignClient . These feign clients are wrapper around a delegate client. For example ApacheHttpClient wraps a httpcomponents httpclient and converts the response to feign response.
- Decoder — Something needs to convert the feign Response to the actual type of the feign method’s return type. Decoders are that instruments. By default spring provides an OptionalDecoder which delegates to ResponseEntityDecoder which further delegates to SpringDecoder. We can override it by defining a bean of Decoder .
- Encoder — We call feign methods by passing objects to it something needs to convert it to http request body. Encoder does that job. Again By default spring provides SpringEncoder.
Alongside the above components, there is also support for caching, and metrics provided by spring feign starter.
We can create a configuration class and override the defaults for the above components.
If we want to override the default for single components feign accepts configuration arguments which we can use to define custom override for default values.
Retry
Feign has baked in support for the retry mechanism. However, by default, it uses Retry.NEVER_RETR . For example, we can create a custom retry which will retry any status code > 400. Below is the code for our CustomRetryer.
One important fact is that feign Retry works either on IOException or RetryableException thrown from some errorDecoder . Below is what a custom decoder looks like -
Though documentation says feign retries on IOException internally when an IOException occurs it wraps it in a `RetryableException`.
Support for resiliency
One form of resiliency is through retries we saw in the last section. Spring has CircuitBreaker support for feign. It achieves it through a separate Feign builder FeignCircuitBreaker.Builder . The actual implementation of circuitbreaker comes from resilience4j library.
Interceptor
Sometimes we want to modify the request by adding some extra information. For example, we may add a header for each request. We can achieve this by using `RequestInterceptor`. For the experiment, I added the below interceptor which populates a header userid.
feign-serviceB reads this header and returns back as a header. If we do a curl we get the below response
We see userid is added to the response.
A very useful application for interceptor is when feign has to send an oauth2 access token. Out of the spring provides a OAuth2FeignRequestInterceptor which adds an access token for each request.
Client side loadbalancing support
From spring boot 2.4.0 feign has integration with spring-cloud-loadbalancer which can fetch client url info from various service discovery providers and make that info available to feign .
Usage of feign simplifies various aspects of making HTTP request. In a typical production environment, we may need to override several components like clients, decoder, errorDecoder etc . Also within the Spring ecosystem feign is nicely integrated with resiliency, load-balancing , metrics etc which makes it an automatic choice when we are working in a microservices architecture.