Consume RESTful APIs using WebClient

In this article, we will use WebClient to consume the RESTful APIs.

WebClient was introduced in Spring 5. It is a non blocking reactive web client used for consuming RESTful APIs.

WebClient is the new alternative provided by Spring for the existing RestTemplate.

This is what the javadoc of RestTemplate shows:

javadoc link: RestTemplate javadoc

NOTE: As of 5.0 this class is in maintenance mode, with only minor requests for changes and bugs to be accepted going forward. Please, consider using the org.springframework.web.reactive.client.WebClient which has a more modern API and supports sync, async, and streaming scenarios.

WebClient vs RestTemplate
  • WebClient is Non-Blocking Client, RestTemplate is Blocking Client.RestTemplate uses Java Servlet API and is therefore synchronous and blocking. In contrast, WebClient is asynchronous and will not block the executing thread while waiting for the response to come back. Only when the response is ready will the notification be produced.
  • RestTemplate supports only synchronous calls. WebClient supports asynchronous as well as synchronous calls. Use block() for synchronous calls in WebClient.

Let’s look how we can use WebClient to consume the RESTful APIs.

We will be consuming the APIs developed earlier in Building RESTful Webservices in Spring Framework using Spring Boot with Spring JDBC

Adding the below spring boot starter dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
 
Creating WebClient
 
WebClient webClient = WebClient.create();
WebClient webClient = WebClient.create(″http://localhost:8080″);
 
We can use the builder API in WebClient to build a WebClient instance by providing baseUrl, filters, default headers, cookies, client-connectors etc.
 
WebClient webClient = WebClient.builder().baseUrl(baseUrl).defaultHeader(HttpHeaders.USER_AGENT, “WebClient”)
.defaultHeader(HttpHeaders.CONTENT_TYPE, “application/json”).build();
 
Creating Request and fetching Response
 
We need to specific the uri and request parameters. Then use retrieve or exchange API to fetch the response.
 
  • retrieve method returns the response body only.
  • exchange method provides entire ClientResponse which includes response status, headers, body etc.
Using retrieve
Mono<Student> studentMono = webClient.get().uri(“/students/1”).retrieve().bodyToMono(Student.class);
studentMono.subscribe(student -> System.out.println(“Mono without block:” + student));
 
Using exchange
Mono<ClientResponse> clientResponse = webClient.get().uri(“/students/2”).exchange();
clientResponse.subscribe(x -> System.out.println(“Exchange Reponse Headers = ” + x.headers()));
clientResponse.subscribe(x -> System.out.println(“Exchange Response Status Code = ” + x.statusCode()));
clientResponse.flatMap(x -> x.bodyToMono(Student.class))
.subscribe(student -> System.out.println(“Using Exchange:” + student));
 
Mono vs Flux
Mono is used for handling zero or one result, the Flux is used to handle zero to many results
package com.spring.rest.config;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpHeaders;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;

import com.spring.rest.model.Student;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@SpringBootApplication
public class Application implements CommandLineRunner {

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

    @Override
    public void run(String...args) throws Exception {
        String baseUrl = ″http: //localhost:8080″;
            System.out.println("Started");
        // Building webClient - specify baseURl and defaultHeaders if any.
        WebClient webClient = WebClient.builder().baseUrl(baseUrl).defaultHeader(HttpHeaders.USER_AGENT, "WebClient")
            .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json").build();

        // Fetching list of students using retrieve asynchronously - mapping responseBody to Flux
        Flux < Student > studentFlux = webClient.get().uri("/students").retrieve().bodyToFlux(Student.class);
        studentFlux.subscribe(student - > System.out.println("Flux without block:" + student));

        // Fetching student with id =1 using retrieve asynchronously - mapping responseBody to Mono
        Mono < Student > studentMono = webClient.get().uri("/students/1").retrieve().bodyToMono(Student.class);
        studentMono.subscribe(student - > System.out.println("Mono without block:" + student));

        // Fetching student with id =2 using exchange asynchronously - //mapping responseBody to Mono and getting the response headers and status
        Mono < ClientResponse > clientResponse = webClient.get().uri("/students/2").exchange();
        clientResponse.subscribe(x - > System.out.println("Exchange Reponse Headers = " + x.headers()));
        clientResponse.subscribe(x - > System.out.println("Exchange Response Status Code = " + x.statusCode()));
        clientResponse.flatMap(x - > x.bodyToMono(Student.class))
            .subscribe(student - > System.out.println("Using Exchange:" + student));

        // Fetching student with id =2 using retrieve synchronously by using the  method block
        Student studentAsync = webClient.get().uri("/students/2").retrieve().bodyToMono(Student.class).block();
        System.out.println("Using Block:" + studentAsync);
        System.out.println("End");

    }

}
Started
Exchange Reponse Headers = org.springframework.web.reactive.function.client.DefaultClientResponse$DefaultHeaders@13caef6f
Exchange Response Status Code = 200 OK
Using Exchange:Student [id=2, name=rochit, age=16, weight=55]
Using Block:Student [id=2, name=rochit, age=16, weight=55]
End
Mono without block:Student [id=1, name=gyan, age=18, weight=70]
Flux without block:Student [id=1, name=gyan, age=18, weight=70]
Flux without block:Student [id=2, name=rochit, age=16, weight=55]
Flux without block:Student [id=8, name=ravi, age=17, weight=65]
Flux without block:Student [id=9, name=TEJA, age=14, weight=58]
Flux without block:Student [id=11, name=VIKU, age=16, weight=44]
Flux without block:Student [id=12, name=Ajay, age=16, weight=44]
Flux without block:Student [id=15, name=Ramu, age=18, weight=47]
Flux without block:Student [id=20, name=Sachin, age=14, weight=50]
Flux without block:Student [id=21, name=Ramesh, age=14, weight=50]
Flux without block:Student [id=23, name=Prabhakar, age=14, weight=50]
Flux without block:Student [id=30, name=Mantu, age=15, weight=50]

Related Articles:

Leave a Reply

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