The subject of this lab is the Spring Cloud Feign project. Feign is known as a declarative REST Client. We will familiarize ourselves with Feign by refactoring the greeting project to use Feign in lieu of Spring’s RestTemplate.

Spring’s RestTemplate is widely used and supported, and many projects don’t see a compelling reason to switch. Whether to use Feign or RestTemplate is largely a matter of taste.

1. Introduction to Feign

Feign’s interface is very different from RestTemplate. It provides an abstraction over explicit http calls. In some ways Feign resembles the design of Spring MVC, but for writing REST clients instead of implementing services. In Spring MVC, we define a controller class by annotating it with @Controller or @RestController. Further, we map http routes or endpoints to specific handler methods also with the @RequestMapping annotation.

Think of Feign as an adapter for making REST client API calls for Java. In Java, we define an API via the interface. This is the procedure:

  • define an interface and annotate it with @FeignClient

  • define methods that represent outbound calls to a remote service, and annotate them with the same @RequestMapping annotation we use in Spring MVC

  • anywhere our application needs to make a call to the REST API, just autowire the interface, and make method calls against it

Spring Cloud Feign takes care of the rest: it injects an implementation of the interface in question that makes the specified http calls to the service. Feign can be configured to use any of a variety of http client libraries, such as OkHttp.

Like Eureka, Hystrix, and Ribbon, Feign was created at NetFlix. As you might expect, Feign is well-integrated with these other projects.

2. Refactoring to Feign

Open the greeting project, and make the following edits:

  1. Add the spring-cloud-starter-feign dependency to the build file:

    greeting-app/build.gradle
    @@ -32,6 +32,7 @@ dependencies {
    
       compile 'org.springframework.cloud:spring-cloud-starter-hystrix'
       compile 'org.springframework.cloud:spring-cloud-starter-eureka'
    +  compile 'org.springframework.cloud:spring-cloud-starter-feign'
    
       runtime 'org.springframework.boot:spring-boot-devtools'
  2. In GreetingApplication, turn on Feign support by adding the annotation @EnableFeignClients. Also, remove the RestTemplate @Bean definition (we’ll be replacing it with a Feign client shortly), like this:

    greeting-app/src/main/java/io/pivotal/training/GreetingApplication.java
    @@ -4,23 +4,16 @@ import org.springframework.boot.SpringApplication;
     import org.springframework.boot.autoconfigure.SpringBootApplication;
     import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
     import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    -import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    -import org.springframework.context.annotation.Bean;
    -import org.springframework.web.client.RestTemplate;
    +import org.springframework.cloud.netflix.feign.EnableFeignClients;
    
     @SpringBootApplication
     @EnableCircuitBreaker
     @EnableDiscoveryClient
    +@EnableFeignClients
     public class GreetingApplication {
    
       public static void main(String[] args) {
         SpringApplication.run(GreetingApplication.class, args);
       }
    
    -  @Bean
    -  @LoadBalanced
    -  public RestTemplate restTemplate() {
    -    return new RestTemplate();
    -  }
    -
     }

2.1. The Interface

Study the following interface definition:

greeting-app/src/main/java/io/pivotal/training/greeting/FortuneAPI.java
package io.pivotal.training.greeting;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Map;

@FeignClient("fortune") (1)
public interface FortuneAPI {

  @RequestMapping("/") (3)
  Map<String, String> getFortune(); (2)

}
1 The annotation marks this interface as a feign client, and provides the eureka service id used to obtain the url of the service instance
2 The method definition specifies what arguments will get sent and returned to the fortune service
3 We map this method to the root endpoint of the fortune service: "/"

It’s interesting to point out that the @RequestMapping annotation is a pure description of a mapping. As such, it can be used either on the server side, as in Spring MVC, or the client side, as shown here with Feign. We can use all of the familiar features of @RequestMapping such as path variables, without having to learn a different vocabulary.

The load balancing and eureka service lookup still takes place. Feign is also integrated into Hystrix, and we could choose to provide a fallback class that would define fallback methods for each interface method in FortuneAPI. But in this case we’ll leave things as shown above.

2.2. Retrofitting FortuneServiceClient

Let’s turn our attention now to the FortuneServiceClient class. Our task here is to yank out the RestTemplate and replace it with an instance of the above FortuneAPI:

+++ b/config/greeting-app/src/main/java/io/pivotal/training/greeting/FortuneServiceClient.java
@@ -10,15 +10,15 @@ import java.util.Map;
 @Component
 @Slf4j
 public class FortuneServiceClient {
-  private RestTemplate restTemplate;
+  private FortuneAPI fortuneAPI;

-  public FortuneServiceClient(RestTemplate restTemplate) {
-    this.restTemplate = restTemplate;
+  public FortuneServiceClient(FortuneAPI fortuneAPI) {
+    this.fortuneAPI = fortuneAPI;
   }

   @HystrixCommand(fallbackMethod = "defaultFortune")
   public String getFortune() {
-    Map<String,String> result = restTemplate.getForObject("http://fortune/", Map.class);
+    Map<String,String> result = fortuneAPI.getFortune();
     String fortune = result.get("fortune");
     log.info("received fortune '{}'", fortune);
     return fortune;

FortuneAPI falls into place neatly.

3. Trying it out

  1. start eureka-server, and one ore more instances of fortune

  2. as usual, verify in the eureka dashboard that fortune is up and registered

  3. start greeting

  4. in a browser, visit http://localhost:8080/ and verify that, as before, you’re obtaining greetings

  5. optionally, you can also verify that ribbon load balancing across multiple fortune instances still takes place.

4. Congratulations

There’s much more to Feign. The API is simple and clean. This library is versatile and un-opinionated. Feign can be used with a variety of underlying http client libraries, encoders and decoders, loggers, interceptors, and more. Feign today is a community-driven project. You can find out more at https://github.com/OpenFeign/feign. You might also want to check out this excellent devoxx talk on Feign by Igor Laborie.

In this lab, we’ve focused on the integration of Feign with Ribbon and Eureka, and the Spring-specific customization of the Feign library.