Synchronous Communication with Feign Client



Introduction

In a distributed environment, services need to communicate with each other. The communication can either happen synchronously or asynchronously. In this section, we will look at how services can communicate by synchronous API calls.

Although this sounds simple, as part of making API calls, we need to take care of the following −

  • Finding address of the callee − The caller service needs to know the address of the service which it wants to call.

  • Load balancing − The caller service can do some intelligent load balancing to spread the load across callee services.

  • Zone awareness − The caller service should preferably call the services which are in the same zone for quick responses.

Netflix Feign and Spring RestTemplate (along with Ribbon) are two well-known HTTP clients used for making synchronous API calls. In this tutorial, we will use Feign Client.

Feign Dependency Setting

In order to use Feign Client API, we need to update the pom.xml of the client service with the following dependency −

<dependencies>
      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
</dependencies>

Enable Feign Clients

And then, annotate our Spring application class with the correct annotation, i.e., @EnableDiscoveryClient and @EnableFeignCLient

package com.tutorialspoint;

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

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class RestaurantService{
   public static void main(String[] args) {
      SpringApplication.run(RestaurantService.class, args);
   }
}

Points to note in the above code −

  • @ EnableDiscoveryClient − This is the same annotation which we use for reading/writing to the Eureka server.

  • @EnableFeignCLient − This annotation scans our packages for enabled feign client in our code and initializes it accordingly.

Once done, now let us look briefly at Feign Interfaces which we need to define the Feign clients.

Using Feign Interfaces for API calls

Feign client can be simply setup by defining the API calls in an interface which can be used in Feign to construct the boilerplate code required to call the APIs. For example, consider we have two services −

  • Service A − Caller service which uses the Feign Client.

  • Service B − Callee service whose API would be called by the above Feign client

The caller service, i.e., service A in this case needs to create an interface for the API which it intends to call, i.e., service B.

package com.tutorialspoint;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(name = "service-B")
public interface ServiceBInterface {
   @RequestMapping("/objects/{id}", method=GET)
   public ObjectOfServiceB getObjectById(@PathVariable("id") Long id);
   @RequestMapping("/objects/", method=POST)
   public void postInfo(ObjectOfServiceB b);
   @RequestMapping("/objects/{id}", method=PUT)
   public void postInfo((@PathVariable("id") Long id, ObjectOfBServiceB b);
}

Points to note

  • The @FeignClient annotates the interfaces which will be initialized by Spring Feign and can be used by rest of the code.

  • Note that the FeignClient annotation needs to contain the name of the service, this is used to discover the service address, i.e., of service B from Eureka or other discovery platforms.

  • We can then define all the API function name which we plan to call from service A. This can be general HTTP calls with GET, POST, PUT, etc., verbs.

Once this is done, service A can simply use the following code to call the APIs of service B −

@Autowired
ServiceBInterface serviceB
.
.
.
ObjectOfServiceB object = serviceB. getObjectById(5);
Advertisements