Consuming REST API Using Feign

TL;DR

This is a beginner’s guide for understanding Feign and it will provide a brief overview of Feign. We will discuss :

  • RestTemplate vs Feign
  • how to do basic calls with Feign (GET, POST ...)
  • customizing Feign components (Encoder , Retryer)
  • handle errors using Feign ErrorDecoder

Introduction

We will start with the simple question: when am I going to use Feign? In today's micro-services era, it's usual to discuss synchronous and asynchronous method calls when calling another service, and even in a monolithic architecture sometimes you need to call an external service and interact with it. When to use each one depends a lot on the business logic you're creating, but we'll focus on the synchronous one here, with a particular focus on the Java platform.

In most cases, when making API rest call to another service we need to deal with :

  • putting up headers.
  • the body call.
  • manage the server response.

If you're a pure Java developer, OKHttpClient is undoubtedly your preferred library, however, if you're looking for a Spring-based option, RestTemplate can help, let's see some examples using these two solutions and discuss their advantages and disadvantages.

Let's imagine, in our application, we need to get a list of all posts from another API, and we will use 'https://jsonplaceholder.typicode.com/posts' in this example.

Using OKHttpClient we will have something like this :

Let's deep dive a little bit into the code :

    1. first, create the request for the remote resource by specifying the URL, and the ( headers, body ) if needed.
    2. execute the request and retrieve the response
    3. deserialize the HTTP response to a concrete type. Here I used Jackson object mapper class to deserialize from JSON to PostDTO class.

Sounds good, simple configuration but we still need to deal directly with the response handling, let's see the same example using RestTemplate

What we did here is:
1. Instantiate RestTemplate.
2. Call getForObject with the specific URL, and the desired class to map to it.

That's OK. We don't have to worry about response handling because Spring will change the incoming response into the object we want.

However, as you are aware, not all API requests are successful. We must deal with unanticipated problems in the majority of cases, some of which are caused by network status, timeouts, or simply internal server errors. Whatever the case may be, we must be prepared. We may use the ResponseEntity wrapper to access the request call status and body, and apply some exception handlers. Let's try this:

Using a try-catch block to catch the HttpClientErrorException exception is the simplest approach to create a custom error handler. You can then get the response status code, body, and headers from the HttpClientErrorException instance. Let's assume we miss-spelled the URL and instead of /posts we wrote /not-posts, the expected result is 404 let's execute the code.

The application prints the 404 status code as expected.

It looks good, so what is that Feign? Why don't we just use RestTemplate? Ugghhh Confused.

In any case, dealing with errors or any other case like using a custom encoder or decoder for the request or the response will end in :

  • more lines of code, probably repeated across many rest call methods.
  • harder to maintain in the future.

Netflix had to deal with these problems, thus they chose to build their rest client leveraging the Spring framework's capabilities: Feign was the name given to it.

Feign is part of the Spring Cloud Netflix bundle, just like Eureka, Zuul, Hystrix, and other libraries. Most of these libraries were deprecated in 2018 (because Netflix no longer supported them), thus the open-source software community stepped in to continue the work; in the case of Feign, it was transferred from Netflix and renamed OpenFeign.

So in this article, we will be focusing only on OpenFeign. As defined in the Spring documentation OpenFeign:

 "Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations"

Similar to Spring Data, OpenFeign uses the same abstraction to implement declared interfaces marked with the @FeignClient annotation, and we will use the same Spring MVC annotations, to set the headers, body requests, and the object type that we wish to return.

So if we want to try our posts example with OpenFeign it will look like this:

So why use Feign?

  1. we don't need to learn any new syntax, we can use the same Spring MVC annotations like (@RequestMapping, @PathVariable, @RequestParam, @RequestBody, @ResponseBody, @RequestHeader, and @ResponseHeader ...).
  2. easy to read and maintain, Feign abstracts the implementation of how requests are made, and you just need to care about configuration.
  3. each Feign client is composed of a set of customizable components. These components are
    • Decoder: process the incoming server response to transform it into our desired object, It uses a ResponseEntityDecoder.
    • Encoder: we must process our outgoing object before calling the other service, the default one here is SpringEncoder.
    • Logger: For our application, we may set the logging level we wish. These logs are only available in DEBUG mode, and any implementation that extends the Slf4jLogger can be provided.
    • Contract: defines which annotations will be valid on our clients, for our examples, we are using SpringMvcContract to enable Spring MVC annotations.

Let us dig into Feign clients more deeply and discuss how Feign clients can be created and configured to call external services using POST, GET methods. We will also discuss how to pass query parameters, path variables, HTTP headers, and request bodies.

How to pass query parameters?

In the following example, our PostsClient will call the same rest service located on host “https://jsonplaceholder.typicode.com” and path “/posts”. The service takes a query parameter called “userId”. Depending on the value, the server will return only the posts of the given user. The full path of the service will look like this: https://jsonplaceholder.typicode.com/posts?userId=1

As I mentioned before, we don't need to learn a new syntax, we will configure the query parameters using Spring web framework annotations.

This will automatically add a query parameter with the name “userId” into the request URL when calling the remote service, Now you can call the client just like any other Spring service with the integer argument value that is needed.

How to pass path variables?

Path variables are parts of the actual address being accessed. They are part of the path (URL) and change in value depending on the resource we try to access (hence the name path “variables”).

To configure path variables in Feign clients, we must do the following:

  1. specify which section of the URL the path variable will replace.
  2. specify the value that will be used in the path.

In the following example, we will consume this API, "https://jsonplaceholder.typicode.com/posts/{postId}" that accepts postId as a path variable.

Let's turn this into a Feign client method. To map the path variable to a method argument, we will use the @PathVariable annotation from Spring web.

What about a post request?

In this example, we will create a new post using Feign client, the API that we are consuming accept a post body in a JSON format, so it's simple we will just use the same spring web annotations to achieve that.

It's so simple, but let's complicate things a little bit and assume that the API we are consuming exposes the following method :

POST : https://jsonplaceholder.typicode.com/posts
Content-type: application/x-www-form-urlencoded

Let’s add a PostsController that expose this method

POST : http://localhost:8081/api/posts
Content-type: application/json

Our controller should look like this

and we will change our PostsClient to adapt to this new content-type

Note we’ve added a consumes attribute of MediaType.APPLICATION_FORM_URLENCODED_VALUE, the consumes attribute consist of the media types which must match the request Content-Type header

So the whole workflow of the request will be like this:

1 -> 2 PostsController need to convert the JSON request body to PostDTO object using Jackson
2 -> 3 PostsClient need to convert the PostDTO object to x-www-form-urlencoded payload.

Let’s make our request and…error!

feign.codec.EncodeException: Could not write request: no suitable HttpMessageConverter found for request type [com.feigndemo.demo.posts.PostDTO] and content type [application/x-www-form-urlencoded]

Ok, focus just on the first lines: EncodeException. That line tells us directly where is our mistake, we have not defined an encoder for the request object yet, so let’s look at our data type for this request:

Content-type: application/x-www-form-urlencoded

The data is sent in the form of a key-value array, just like a Form object. Feign offers a pre-built encoder for this type of data called FormEncoder.

And now, we need to overwrite the default encoder in our configuration class.

and our PostsClient will look like this :

Send the request again, and now you will have a successful response from the server!

But as I mentioned earlier, not all API requests are successful... so how Feign is helping us to manage this?

Managing errors is the most important thing because of what can happen if you don't, and if it's done properly it will give you helpful information that will make it easier for the team to investigate when things go wrong.

By default Feign only throws FeignException for any error situation, but you probably want an application-specific exception instead. This is easily done by providing your implementation of ErrorDecoder.

To use ErrorDecoder, you must first create a new Java class that implements the ErrorDecoder interface. as well as override the decode method

public Exception decode(String methodKey, Response response)

Implementing ErrorDecoder interface you give you access to: methodKey and Response objects.

  • methodKey – will contain a Feign client class name and a method name,
  • response – will allow you to access HTTP status code, Body of HTTP Response, and also the Request object. You can use these details when handing an error message and preparing a response.

Below is an example of an ErrorDecoder interface being implemented that does two things :

  • log the error with the status, what method caused it, and the response body
  • return a server error status when other client errors occur

Let's add another cool thing to our example: suppose we want to retry on any server error 5 times max.

To handle this we have to provide the retry bean at configuration file as shown below:

Retry is only activated when RetryableException is raised.

So, let's add more logic to PostsClientErrorDecoder class, the syntax should be something like:

As you can see we have 5 retries by default, but you can customize it as you like.

Conclusion

In this article, we've explained how to build an HTTP client using Feign to consume external APIs. It makes the code easier to read by avoiding boilerplate code, easier to maintain with the help of Feign error decoders, and the most fun part is that you can customize it as you like to fit your needs. However, we focused only on the synchronous calls because Feign does not support reactive calls, but basically for a reactive way you should consider using Spring Boot's WebClient.