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.
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Creating WebClient
WebClient webClient = WebClient.create(″http://localhost:8080″);
Creating Request and fetching Response
- retrieve method returns the response body only.
- exchange method provides entire ClientResponse which includes response status, headers, body etc.
Using retrieve
Using exchange
Mono vs Flux
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: