Spring boot feign client

In this article, we will take a look at Feign client, its use and how to integrate it with Spring boot to send HTTP requests with examples.
Following is the table of contents

What is Feign client
Feign is a declarative web client used to sending HTTP requests.
It eliminates the requirement of writing code to initialize a client, create request and send it as you will see in below examples.

With feign, you have to simply create an interface, write an annotation over it along with the base URL of the remote service.
Then, create methods to access an API endpoint with Spring MVC annotations such as @GetMapping, @PostMapping corresponding to the HTTP methods of the endpoint.

Feign uses libraries such as Jersey and CXF to create java clients for REST and SOAP services. But, you can customize this and use clients such as OkHttpClient and Apache HttpClient to send HTTP requests.

To use these clients, we need to add their dependencies in the project.

Feign versions above 10 support Java 8 and above. Use Feign 9.x for java 6.
Spring Feign configuration
To add Feign support, use below spring starter openfeign gradle dependency

implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.3'

This will pull feign version 11.8.

Below is the maven dependency

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>3.1.3</version>
</dependency>

Initial Setup
To send HTTP requests, we need a web service endpoint. For this, we will be using a fake webservice https://jsonplaceholder.typicode.com

To fetch json string and convert it to an object and send POST request, we need an object and for this purpose, we will be using below class

@Data
public class Post {
  private int id;

  private String title;
  
  private String body;
  
  private int userId;

}

Fields of this class match with keys of json response sent by the above URL.

Note that @Data is an annotation from Project Lombok, which generates getter, setter methods, a constructor and toString() method for this class automatically.

Using Feign client
To use Feign client with default configuration, follow below steps
1. Create an interface and annotate it with @FeignClient annotation.
There are two mandatory attributes required with this annotation. These are
name
The name of this feign client. This name is useful when creating load balancers.
For this article, it has no significance.
If you are simply using feign client without any load balancer, this name can be any string.
url
The URL of the service to which feign client will send requests to. For this article, it will be https://jsonplaceholder.typicode.com

This interface will contain declarations for the APIs that you want to support.

package com.codippa;

import java.util.List;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@FeignClient(name="client",
         url="https://jsonplaceholder.typicode.com")
public interface RestClient {
  
  /**
   * Fetch all posts
   * @return
   */
  @GetMapping("posts")
  public List<Post> getPosts();
  
  
  /**
   * Create a post
   * @param p
   * @return
   */
  @PostMapping("posts")
  public Post createPost(Post p);
}

Note that @GetMapping and @PostMapping are Spring MVC annotations that we use in controller classes to expose application endpoints.
Remember that declaring these methods does not expose them for your application, we need a rest controller for the same.

2. Annotate the main class of Spring boot application with @EnableFeignClients as shown below.

This will instruct Spring boot to scan for @FeignClient annotations.

package com.codippa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class FeignDemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(FeignDemoApplication.class, args);
  }

}

That is all, we have completed configuring feign client in a spring boot application.
Test Feign client
To show the power of feign client, create a controller class that exposes a couple of endpoints to fetch the list of posts and to create a post as shown below.

package com.codippa;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PostController {

  @Autowired
  RestClient client;
  
  @GetMapping("posts")
  public ResponseEntity<List<Post>> getAll() {
    List<Post> posts = client.getPosts();
    return ResponseEntity.of(Optional.of(posts));
  }
  
  @PostMapping("post")
  public ResponseEntity<Post> createPost(@RequestBody Post p) {
    Post post = client.createPost(p);
    return ResponseEntity.of(Optional.of(post));
  }
}

Note that we have @Autowired feign client that we created above. Spring boot will automatically create its instance and inject it.

These two controller method expose URLs /posts and /post from our application. When these are accessed, they will in turn access the remote service URLs and perform the requested operations.

You can see that we did not create any client object, did not open any connection to the REST service, did not parse the response anywhere.
All this is managed by feign client.

Customizing Feign configuration
Feign client is composed of following components

A. Encoder
Converts an object into an HTTP request body. Utilized while sending requests to an endpoint URL.
Default encoder is SpringEncoder.
B. Decoder
Converts HTTP response into an object of some type. Utilized while sending response back to the client.
C. Contract
Contract specifies which annotations are applicable over interfaces. Default contract is Spring MVC, which means that it will recognize Spring specific annotations such as @GetMapping etc., but not Feign specific annotations such as @RequestLine.
D. Logger
Used to perform logging. Default logger is Slf4j.
E. Client
Used for sending requests and receiving response.

Default connection timeouts such  as connect timeout is 10 seconds, read timeout is 60 seconds.

All these configurations can be customized in application.properties file as shown below

feign.client.config.<clientName>.connectTimeout=60
feign.client.config.<clientName>.readTimeout=60
feign.client.config.<clientName>.encoder=com.codippa.CustomerEncoder
feign.client.config.<clientName>.decoder=com.codippa.CustomDecoder

where clientName should be replaced with the value of name attribute in @FeignClient annotation.

This configuration will be applicable to all feign clients.
Creating custom Feign client
You can create a feign client with your own encoder, decoder and other component implementations.

To create a feign client, use Feign.builder() method as shown below

import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import feign.Contract;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;

@Import(FeignClientsConfiguration.class)
public class FeignConfig {

  @Bean
  public RestClient getClient(Contract c) {
    return Feign.builder().
        contract(c).
        encoder(new JacksonEncoder()).
        decoder(new JacksonDecoder()).target(RestClient.class,
        "https://jsonplaceholder.typicode.com");
  }
}

In the above example, we are using JacksonEncoder() and JacksonDecoder() as encoder and decoder respectively.
To use these, include Jackson dependencies for feign.

Contract is the default feign contract, which is available since we have imported the default configuration with FeignClientsConfiguration.class in @Import annotation.

target() method specifies the class which will be used as the client and url is the endpoint URL.

Finally, provide this class name as the value of configuration property with @FeignClient annotation as shown below

@FeignClient(name="client",
          url="https://jsonplaceholder.typicode.com", 
          configuration = FeignConfig.class)
public interface RestClient {
 ...
}

Summary
In this article, we learnt what is feign client and how to use it with Spring boot to send HTTP requests to replace the code for creating a client and receiving response.

Though Feign client has other vast uses such as performing load balancing, circuit breaker, compressing request and response etc., which are outside the scope of this article.