Feign Client to Call Another Microservice

In this tutorial, I will share how to use Feign Client to send HTTP Requests to another Microservice.

For a step-by-step series of video lessons, please check this page: Spring Boot Microservices and Spring Cloud.

Adding Feign to Your Project

To use Feign Client in your Spring Boot application, add the following dependency to a pom.xml file of your project.

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

Add @EnableFeignClients Annotation

To enable your Spring Boot application to use Feign client, add the following annotation @EnableFeignClients next to a @SpringBootApplication annotation.

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class PhotoAppApiApplication {

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

}

Destination Microservice

Let’s assume that we have a destination Microservice called albums-ws which returns a JSON list of user photo albums.

[
       {
           "albumId": "album1Id",
           "userId": "$638d27ef-4c19-46da-91ac-a5d4644b469d",
           "name": "album 1 name",
           "description": "album 1 description"
       },
       {
           "albumId": "album2Id",
           "userId": "$638d27ef-4c19-46da-91ac-a5d4644b469d",
           "name": "album 2 name",
           "description": "album 2 description"
       }
   ]

The albums-ws Microservice is registered with the Eureka discovery service under the name albums-ws and has the following RestController:

@RestController
@RequestMapping("/users/{id}/albums")
public class AlbumsController {
    
    @Autowired
    AlbumsService albumsService;
  
    @GetMapping( 
            produces = { 
                MediaType.APPLICATION_JSON_VALUE,
                MediaType.APPLICATION_XML_VALUE,
            })
    public List<AlbumResponseModel> userAlbums(@PathVariable String id) {
       
        List<AlbumResponseModel> returnValue = new ArrayList<>();
        
        List<AlbumEntity> albumsEntities = albumsService.getAlbums(id);
        
        if(albumsEntities == null || albumsEntities.isEmpty())
        {
            return returnValue;
        }
        
        Type listType = new TypeToken<List<AlbumResponseModel>>(){}.getType();
 
        returnValue = new ModelMapper().map(albumsEntities, listType);
 
        return returnValue;
    }
}

Note the value in @RequestMapping annotation: @RequestMapping(“/users/{id}/albums”)

Create Feign Client

To send HTTP Requests to a destination albums-ws Microservice, we will need to create a Feign Client interface. Please note the use of @FeignClient annotation, which accepts the name albums-ws under which the destination Microservice is registered with Eureka Discovery Service.

import com.appsdeveloperblog.photoapp.api.users.ui.model.AlbumResponseModel;
import java.util.List;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "albums-ws")
public interface AlbumsServiceClient {
        
 @GetMapping("/users/${id}/albums")
 public List<AlbumResponseModel> getAlbums(@PathVariable String id);
 
}

The @GetMapping annotation indicates that this will be an HTTP GET request.  And it contains a path to an API endpoint exposed by the destination Microservice(albums-ws). We will create a new Java class to consume the JSON Array with a list of albums that the albums-ws Microservice returns. This Java class must have class fields matching the JSON object’s names.

AlbumResponseModel Java class

public class AlbumResponseModel {
    private String albumId;
    private String userId; 
    private String name;
    private String description;

    public String getAlbumId() {
        return albumId;
    }

    public void setAlbumId(String albumId) {
        this.albumId = albumId;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
    
}

Use Feign Client

Now that we have created the Feign client, we are ready to use it to send an HTTP GET request and get a list of albums from the albums-ws Microservice.

To create an instance of Feign client, you will need to Autowire the feign client interface into your service class. To inject feign client into your service class, you can use constructor-based dependency injection, as shown in the example below.

@Service
public class UsersServiceImpl implements UsersService {

@Autowired
AlbumsServiceClient albumsServiceClient;

....

List<AlbumResponseModel> albumsList = albumsServiceClient.getAlbums(userId);
....

}

Sending HTTP Request to an External Web Service

If you need to consume an external Web Service, which is not part of your Microservices architecture and is not registered with your Eureka Discovery service, annotate Feign client interface providing the destination Web Service URL in the following way.

@FeignClient(name = "AlbumsWebService", url = "http://localhost:8089")
public interface AlbumsServiceClient {
        
 @GetMapping("/users/${id}/albums")
 public List getAlbums(@PathVariable String id);
 
}

Note the use of URL in the @FeignClient annotation.

Error Handling

The destination microservice may return an error response. Read the following tutorial to learn how to handle errors Feign ErrorDecoder.

I hope this tutorial was helpful to you. To learn more about Spring Cloud, check out the following tutorials.  And if you enjoy learning by following a series of step-by-step video lessons, then look at the below list of online video courses that teach Spring Cloud.


Leave a Reply

Your email address will not be published. Required fields are marked *