Simplifying Microservices Communication Using Spring Cloud OpenFeign

unsplash-logoPavan Trikutam

What is Feign?

Feign is a Java to HTTP client binder. Feign Simpliffyes the HTTP API Clients using declarative way.
Feign is a library for creating REST API clients in a declarative way. it makes writing web service clients easier. Developers can use declarative annotations to call rest servicese instead of writing repetitive boilerplate code.

Spring Cloud OpenFeign provides OpenFeign integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms

The code for this post is available for download here.

Demo Application
We Have Simple User Service that provides crud operations for Users. We will write client to call these rest endpoints.

Why Feign?

Without Feign, In Spring Boot Applications We will be using RestTemplate to call User service. We need to write code somewhat similar to below.

HTTP Client Using RestTemplate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@GetMapping
public List<User> getAllUsers() {
System.out.println("Calling User Service using Feign Client!!");
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<List<User>> response = restTemplate.exchange(
"http://localhost:8080/user/",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<User>>() {
});
List<User> users = response.getBody();
return users;
}
@GetMapping("{id}")
public User getUserById(@PathVariable("id") int id) {
Map<String, String> uriParams = new HashMap<String, String>();
uriParams.put("id", String.valueOf(id));
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:8080/user/{id}")
.buildAndExpand(uriParams)
.toUri();
System.out.println(uri);
RestTemplate restTemplate = new RestTemplate();
User forEntity = restTemplate.getForObject(uri, User.class);
return forEntity;
}
@PostMapping
public ResponseEntity addUser(@RequestBody User user) {
System.out.println("Add user");
System.out.println(user.toString());
RestTemplate restTemplate = new RestTemplate();
HttpEntity<User> request = new HttpEntity<>(user);
ResponseEntity exchange = restTemplate
.exchange("http://localhost:8080/user/", HttpMethod.POST, request, String.class);
return exchange;
}
@DeleteMapping("{id}")
public ResponseEntity deleteUser(@PathVariable int id) {
System.out.println("delete user");
Map<String, String> params = new HashMap<String, String>();
params.put("id", String.valueOf(id));
RestTemplate restTemplate = new RestTemplate();
restTemplate.delete("http://localhost:8080/user/{id}", params);
return new ResponseEntity("User Deleted successfully", HttpStatus.OK);
}

From above code we can easily figure out that most of the code is repetitive and has nothing to do the business logic. Let’s Simplify Above code using Spring Cloud OpenFeign.

Getting Started With Spring Cloud OpenFeign

To include Feign in project We need to use artifact id spring-cloud-starter-openfeign

openfeign Maven
1
2
3
4
   <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

EnableFeignClients

EnableFeignClients
1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableFeignClients
public class SpringCloudFeignClientDemoApplication {

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

Creating Feign Client With Sensible Defaults.

FeignClient
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

@FeignClient(name = "User", url = "http://localhost:8080")
public interface UserClient {

@RequestMapping(method = RequestMethod.GET, value = "/user")
List<User> getAllUsers();

@RequestMapping(method = RequestMethod.GET, value = "/user/{id}")
User getUser(@PathVariable("id") int id);

@RequestMapping(method = RequestMethod.DELETE, value = "/user/{id}")
ResponseEntity deleteUser(@PathVariable("id") int id);

@RequestMapping(method = RequestMethod.POST, value = "/user/")
ResponseEntity addUser(@RequestBody User user);

@RequestMapping(method = RequestMethod.PUT, value = "/user/")
ResponseEntity updateUser(User user);}

The above code is self explanatory. At minimal we just have to specify name = "User" is an arbitrary client name and url.
If we compare our UserClient with the code that we have written using RestTemplate, It’s visible that without writing any code specific to calling HTTP Service our UserClient supports all operations. Feign is doing magic under the hood.

Overriding Feign default properties

We Can provide custom configuration class to Overriding default properties.
e.g. let say we want to Log the headers, body, and metadata for both requests and responses.
lets Create UserClientConfig class to setup log level.

UserClientConfig
1
2
3
4
5
6
7
8
@Configuration
public class UserClientConfig {

@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.HEADERS;
}
}

Update UserClient To use this config class.

Updated FeignClient
1
2
3
4
5

@FeignClient(name = "User", url = "http://localhost:8080",configuration=UserClientConfig.class)
public interface UserClient {

}

Note : Feign gets integrated with Hystrix, Ribbon and Eureka quite easily. I will cover that in separate Post.

The code for this post is available for download here.

Share Comments