Site icon Vinsguru

Spring WebClient With Feign

reactive feign

Overview:

In this tutorial, I would like to show you how we can use Spring WebClient with Feign to make HTTP calls in reactive manner.

Spring WebClient with Feign:

Spring WebClient is a non-blocking reactive client to make HTTP requests. Feign is a library which helps us to create declarative REST clients easily with annotations and it provides better abstraction when we need to call an external service in Microservices Architecture.

In this tutorial, Lets see we could integrate these two.

Sample Application:

As the aim of this tutorial is to learn how we could integrate Spring WebClient with Feign and make HTTP requests, we need a service which exposes REST API for us to play with.

I am going to use json-server which exposes dummy REST-APIs.

{
   "movies":[
      {
         "id":1,
         "title":"Lord of the Rings - The Fellowship of the Ring",
         "year": 2001,
         "imdbRating": 8.8
      },
      {
         "id":2,
         "title":"Lord of the Rings - The Two Towers",
         "year": 2002,
         "imdbRating": 8.7
      },
      {
         "id":3,
         "title":"Lord of the Rings - The Return of the King",
         "year": 2003,
         "imdbRating": 8.9
      }            
   ]
}
version: '3'
services:
  server:
    image: clue/json-server
    ports:
    - 3000:80
    volumes:
    - ${PWD}/db.json:/data/db.json
http://localhost:3000/movies
http://localhost:3000/movies/1
http://localhost:3000/movies
http://localhost:3000/movies/1
http://localhost:3000/movies/1

We have our movie-service ready. Lets create a Reactive Feign client to interact with this service.

Project Setup:

Lest create a Spring project with the following dependencies.

We also need to include this dependency.

<dependency>
    <groupId>com.playtika.reactivefeign</groupId>
    <artifactId>feign-reactor-spring-cloud-starter</artifactId>
    <version>3.1.0</version>
    <type>pom</type>
</dependency>

DTO:

Lets create a DTO to represent the movie object.

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor(staticName = "create")
public class MovieDto {

    private Integer id;
    private String title;
    private Integer year;
    private Double imdbRating;

}

Spring WebClient with Feign – MovieClient Interface:

Lets perform simple CRUD operations with our MovieService. For that lets create an interface as shown below.

@ReactiveFeignClient(value = "movie-service", url = "${movie.service.url}")
public interface MovieClient {

    @GetMapping("movies")
    Flux<MovieDto> getAllMovies();

    @GetMapping("movies/{movieId}")
    Mono<MovieDto> getMovie(@PathVariable("movieId") Integer movieId);

    @PostMapping("movies")
    Mono<MovieDto> saveMovie(MovieDto movieDto);

    @PutMapping("movies/{movieId}")
    Mono<Void> updateMovie(@PathVariable("movieId") Integer movieId, MovieDto movieDto);

    @DeleteMapping("movies/{movieId}")
    Mono<Void> deleteMovie(@PathVariable("movieId") Integer movieId);

}
movie.service.url=http://localhost:3000
@SpringBootApplication
@EnableReactiveFeignClients
public class WebClientFeignApplication {

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

}

Service:

@Service
public class FeignClientDemo implements CommandLineRunner {
    
    @Autowired
    private MovieClient movieClient;
    
    @Override
    public void run(String... args) throws Exception {
        
    }
}
private Mono<Void> getAll(){
    return this.movieClient.getAllMovies()
            .doOnNext(System.out::println)
            .doFinally(s -> System.out.println("------------- GET All completed ------------------"))
            .then();
}
private Mono<Void> post(){
    MovieDto dto = MovieDto.create(
            5,
            "Harry Potter and the Sorcerer Stone",
            1999,
            7.6
    );
    return this.movieClient.saveMovie(dto)
            .doFinally(s -> System.out.println("------------- POST Movie completed ------------------"))
            .then();
}
private Mono<Void> put(){
    MovieDto dto = MovieDto.create(
            null,
            "Harry Potter and the Sorcerer Stone",
            2001,
            7.6
    );
    return this.movieClient.updateMovie(5, dto)
            .doOnNext(System.out::println)
            .doFinally(s -> System.out.println("------------- Movie updated ------------------"))
            .then();
}
private Mono<Void> get(){
    return this.movieClient.getMovie(5)
            .doOnNext(System.out::println)
            .doFinally(s -> System.out.println("------------- GET Movie completed ------------------"))
            .then();
}
private Mono<Void> delete(){
    return this.movieClient.deleteMovie(5)
            .doOnNext(System.out::println)
            .doFinally(s -> System.out.println("------------- Movie deleted ------------------"))
            .then();
}
@Override
public void run(String... args) throws Exception {
    Flux.concat(
            getAll(), // first get all movies
            post(),   // create a new movie id 5
            get(),    // get movie id 5 - check if it is present
            put(),    // update movie id 5
            get(),    // get movie id 5 - check if it is updated
            delete()  // delete movie id 5
    ).subscribe();
}

Spring WebClient with Feign – Demo:

When I start the application, the run method invokes all the methods and we are able to interact with the MovieService. We get the response as shown below.

MovieDto(id=1, title=Lord of the Rings - The Fellowship of the Ring, year=2001, imdbRating=8.8)
MovieDto(id=2, title=Lord of the Rings - The Two Towers, year=2002, imdbRating=8.7)
MovieDto(id=3, title=Lord of the Rings - The Return of the King, year=2003, imdbRating=8.9)
------------- GET All completed ------------------
------------- POST Movie completed ------------------
MovieDto(id=5, title=Harry Potter and the Sorcerer Stone, year=1999, imdbRating=7.6)
------------- GET Movie completed ------------------
------------- Movie updated ------------------
MovieDto(id=5, title=Harry Potter and the Sorcerer Stone, year=2001, imdbRating=7.6)
------------- GET Movie completed ------------------
------------- Movie deleted ------------------

Summary:

We were able to successfully demonstrate Spring WebClient with Feign to create a declarative reactive client to make HTTP requests without much effort.

The source code is available here.

Learn more about Spring WebFlux.

Happy coding 🙂

Share This:

Exit mobile version