Skip to main content
Article

Spring WebClient – ​​Non-blocking and responsive web client

In this article, we will see how to configure Spring WebClient and how to use it to make GET, POST or any other HTTP requests.We will also learn how to configure the client to handle timeout and other HTTP related configurations.

5 min read
javaspringspring-boot
javaspringspring-boot

In this article, we will see how to configure Spring WebClient and how to use it to make GET, POST or any other HTTP requests.We will also learn how to configure the client to handle timeout and other HTTP related configurations.

Spring WebClient?

Spring WebClient is a non-blocking reactive client that allows you to make HTTP requests.It was introduced in Spring 5. The WebClient APIs are introduced as part of replacing the existing Spring RestTemplate.

Important features of Spring WebClient

Let's take a look at some of the important features of this new client.

  • Spring WebClient is both synchronous and asynchronous.
  • Support upstream and downstream streaming.
  • Works with HTTP/1.1
  • Supports a highly concurrent, responsive, non-blocking and less resource-intensive framework.
  • Support for traditional reactive module and Spring reactive module.
  • Provides a working API that takes advantage of Java 8's lambdas.

Starting with version 5.0, the non-blocking and responsive WebClient offers a modern alternative to RestTemplate with effective support for sync and async scenarios, as well as streaming scenarios.RestTemplate will be deprecated in a future release and will not have any major new features from now on.I highly recommend switching to WebClient

We will set up a spring boot application to configure and use Spring WebClient

1- Added Spring WebClient in pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>net.autourducode</groupId>
    <artifactId>spring-WebClient</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-WebClient</name>
    <description>spring-WebClient</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <!-- Build a responsive web application with spring webflux and netty -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
 
        <!-- Useful for unit testing -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>

I'm using https://reqres.in to simulate our HTTP REST call.

2- Creating WebClient

WebClient provides the create() method to create a default instance.These are the most basic steps to create the client.The Functional API provides a more flexible and powerful way to build the client, which includes:

  • Client initialization with base URI; *Configuration of cookies;
  • Configuring HTTP headers.
@Configuration
public class WebClientConfig {
    // Configuring WebClient
    @Bean
    public WebClient webClient(WebClient.Builder webClientBuilder) {
        return webClientBuilder
                .baseUrl("https://reqres.in/api")
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .build();
    }
}

Spring Boot makes it very easy by injecting WebClient.Builder.This is part of the DefaultWebClientBuilder class.We can use the constructor to customize client behavior.Another option is to create the WebClient using WebClient.create() and configure it accordingly.

WebClient client = WebClient.create("https://reqres.in/api");

3- Send a request

Sending requests using Spring WebClient is similar to what we did with RestTemplate, except that it provides a smoother API and control over API calls.Let's look at some important points when using WebClient to send requests.

  1. The RequestHeadersUriSpec option allows using the HTTP method (e.g. GET or POST, etc.) when calling the API.
  2. Add header, cookies or authentication details (if necessary).
  3. Set the request URI.
  4. Configuration request body (e.g. sending a POST request).
  5. Call the retrieve() or exchange() method.
  6. Manage API response.
WebClient webClient = webClientBuilder
    .clientConnector(new ReactorClientHttpConnector(getHttpClient()))
    .baseUrl("https://reqres.in/api")
    .build();
 
Mono<User> user = webClient.get()
    .uri("/users/{id}", id)
    .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
    .retrieve()
    .bodyToMono(User.class);

4- Receive a response

We can use the retrieve() method, then the bodyToFlux() and bodyToMono() methods if we are only interested in the API response.

We can use the exhange() method if we need more details in the response.

5- Web Client – GET request

Let's look at the HTTP GET call using the WebClient.We use GET method whenever we want to get/fetch resources.

@Resource
private WebClient webClient;
 
@Test
public void getUsers() {
    String str = webClient.get()
        .uri("/users/")
        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .retrieve()
        .bodyToMono(String.class)
        .block();
    System.out.println(str);
}

6- Web Client – POST Request

@Resource
private WebClient webClient;
 
@Test
public void postUser() {
    User user = new User();
    String str = webClient.post()
        .uri("/users/")
        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .body(Mono.just(user), User.class)
        .retrieve()
        .bodyToMono(String.class)
        .block();
    System.out.println(str);
}

7- WebClient – retrieve() vs exchange()

Using the Spring WebClient, we have the option to use the retrieve() or exchange() method.Let’s see the difference between these 2 methods to understand their use cases.

  • The retrieve() method should be preferred in case we are interested in the response body.
  • The exchange() method provides more control and details like response status, headers and body, etc.
  • The retrieve() method provides an automatic error signal (e.g. 4xx and 5xx).
  • No automatic error signal is available for exchange() method and we need to check the status code and handle it.

To understand the Flux and Mono types available with Reactor.

8- Configuring timeout with Spring WebClient

Similar to Spring RestTemplate, we can configure the connection timeout for the WebClient.Use the HttpClient class to configure the timeout for the client.Let's see how to do it:

@Configuration
public class WebClientConfig {
    // Configuring WebClient
    @Bean
    public WebClient webClient(WebClient.Builder webClientBuilder) {
        return webClientBuilder
                .clientConnector(new ReactorClientHttpConnector(getHttpClient()))
                .baseUrl("https://reqres.in/api")
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .build();
    }
 
    private HttpClient getHttpClient() {
        return HttpClient.create()
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
                .doOnConnected(connect -> connect
                        .addHandlerLast(new ReadTimeoutHandler(10))
                        .addHandlerLast(new WriteTimeoutHandler(10)));
    }
}

Let's look at some important points:

  • The ChannelOption.CONNECT_TIMEOUT_MILLIS option allows us to set the connection timeout.
  • Configuring read and write timeouts using the ReadTimeoutHandler and WriteTimeoutHandler modules.
  • If you want, you can set the response timeout using Duration.ofMillis()

Memory limit

The default memory limit for in-memory buffer data is 256 KB.If this limit is exceeded, Spring will throw the DataBufferLimitException error.Spring provides the ability to increase the buffer data limit using the max-in-memory-size property.We can set this property in our application.properties file.

spring.codec.max-in-memory-size=5MB

In this article, we studied Spring's WebClient.We have seen how to configure and configure the client.We also saw how to configure the timeout and memory limit for your client.

Source code

I hope this article was useful to you.Thanks for reading it.

Find our #autourducode videos on our YouTube channel:\1

ShareXLinkedIn