Hi! In this article, I’d like to show you how to configure Feign Client in Spring Boot application.
Feign is a Java to HTTP client binder inspired by Retrofit among others. Thanks to it, we can build HTTP client easily without any boilerplate code and in a very concise way. Spring also has a special module with Feign Client so using both is much more easy.
Dependencies
If you use Maven you should import Feign Client by adding the dependency in this way:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.BUILD-SNAPSHOT</version>
<relativePath/>
</parent>
<properties>
<spring-cloud.version>Greenwich.BUILD-SNAPSHOT</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
If you use Gradle:
plugins {
id 'org.springframework.boot' version '2.2.0.BUILD-SNAPSHOT'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
ext {
set('springCloudVersion', 'Greenwich.BUILD-SNAPSHOT')
}
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
You can also use Spring Initializr and generate project specifing all what you need. In following examples I also used spring-boot-starter-web to create endpoints.
Example
At the first we should enable Feign Client in our Spring application. To do this we just annotate Spring Boot main class with @EnableFeignClients.
@EnableFeignClients
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Thanks to @EnableFeignClients annotation, all feign clients occuring in MyApplication package and its subpackages will be implemented and put in DI container. Let’s create such an examplary feign client interface.
@RestController
public class MyController {
private MyFeign myFeign;
public MyController(MyFeign myFeign) {
this.myFeign = myFeign;
}
@GetMapping("hello")
public String hello() {
return "hello";
}
@GetMapping
public String helloFeign() {
return myFeign.hello();
}
}
@FeignClient(url = "http://localhost:8080", name = "myFeign")
public interface MyFeign {
@GetMapping("hello")
String hello();
}
As we can see above, there are feign client and controller exposing “hello” endpoint we want to communicate with. Feign client interface is annotated with @FeignClient. This annotation allows to specify its name and url. Of course the url can be put there as a parameter from application properties – url = “${app.my-feign.url} what is a good practice.
Thanks to integration of Spring and Feign Client we can easily create HTTP clients just by adding already known Spring MVC annotations. So our client would also look like:
app.user.url = http://localhost:8080
@FeignClient(url = "${app.user.url}", name = "userClient")
public interface UserClient {
@GetMapping
List<UserDto> getUsers(@RequestHeader("X-Auth-Token") String xAuthToken);
@GetMapping
List<UserDto> findUsersBySurname(@RequestParam("surname") String name);
@GetMapping("{id}")
UserDto getUser(@PathVariable("id") long id);
@PostMapping
ResponseEntity<Void> createUser(@RequestBody NewUserDto newUserDto);
@PutMapping
void updateUser(@RequestBody UserDto userDto);
@DeleteMapping("{id}")
void deleteUser(@PathVariable("id") long userId);
}
In that version I used, I had to specify @PathVariable parameter equaled “id”. In Spring MVC it wasn’t necessary because the default @PathVariable name was just method parameter name. Notice also that there is ResponseEntity used. Thanks to it we can retrieve some additional information about response such as location of newly created resource or status of this response. However keep in mind that error statuses will cause throwing exceptions by feign client.
Configuration
There is also the possibility to customize our feign client. It can be done just by specifying configuration class in @FeignClient annotation.
@FeignClient(url = "${app.user.url}", name = "userClient", configuration = UserClientConfiguration.class)
public interface UserClient {
// ...
}
When can it be useful? An example of necessity of using it is communication with secured endpoints by a token. Then our configuration would look similar to this one:
public class UserClientConfiguration {
private static final String TOKEN_REQUEST_PARAM = "token";
@Value("${app.user.token}")
private String token;
@Bean
public RequestInterceptor includeJwtInterceptor() {
return template -> template.query(TOKEN_REQUEST_PARAM, token);
}
}
Conclusion
In this post, we saw how to configure Feign Client in Spring Boot application. Thanks to Feign Client it’s really easy to communicate with other microservices so we can build such an architecture faster and in a less error-prone way, using reusable feign clients.