Setup and Examples for the Spring WebFlux WebClient

Last Updated:  May 19, 2021 | Published: June 23, 2019

RESTful communication is the de-facto standard for interchanging data in a microservice-based environment. Usually, every participating microservice offers different parts of the application's domain in a RESTful way and calls other microservices to gather data for e.g. a different part of the application's domain. Resilience and efficient data interchange is, therefore, a key factor when it comes to the success of the whole application. With Spring we usually made use of the RestTemplate to perform HTTP requests, but can now also use the Spring WebClient.

With the release of Spring Framework 5.0, the documentation of the RestTemplate says the following:

NOTE: As of 5.0, the non-blocking, reactive org.springframework.web.reactive.client.WebClient offers a modern alternative to the RestTemplate with efficient support for both sync and async, as well as streaming scenarios. The RestTemplatewill be deprecated in a future version and will not have major new features added going forward. See the WebClient section of the Spring Framework reference documentation for more details and example code.

To be future-ready,  your Spring-based application should migrate to the reactive and non-blocking Spring WebClient for both its async & sync HTTP communication.

With this blog post, you'll learn how to effectively use the WebClient class for HTTP requests. Furthermore, we'll take a look at the WebClient configuration, filtering requests, and testing. For the demo application, we'll use Java 11 and Spring Boot 2.4.

Create and Configure the WebClient

To take advantage of the WebClient, we need the following dependency for our Spring Boot project:

The WebClient internally delegates to an HTTP client library (by default Reactor Netty), but others can be plugged in through a ClientHttpConnector.

When it comes to configuring resilient HTTP clients, connection/read/write timeouts are important to avoid long-running tasks. In addition, HTTP headers and cookies are essential for e.g. authentication or content negotiation. We can configure such timeouts when creating our WebClient instance.

When using the WebClient  within a Spring Boot project, we can inject the auto-configured WebClient.Builder and create the instance using this builder. This auto-configured builder customizes the WebClient to, among other things, emit metrics about the HTTP response code and response time when the Spring Boot Actuator is on the classpath:

The configuration above defines convenient defaults for the connect, read and write timeouts. Furthermore, we define default cookies, headers, and filters that are presented (unless we override them) for each request made with this WebClient bean. More about the filtering mechanism in one of the upcoming sections.

We can also create our own WebClient  from scratch without using the pre-configured WebClient.Builder from Spring Boot:

HTTP GET Request Example With Spring WebClient

Once our WebClient is configured for a specific baseUrl, we can start performing HTTP requests.

As the internal WebClient architecture is designed for reactive and non-blocking applications, we either have to call .block() or rewrite our codebase to accept Mono<T> and Flux<T> as method return types.

A simple sync HTTP GET request with our previously configured WebClient looks like the following:

To trigger the actual HTTP request, we can either use .retrieve() or .exchange() whereby the first method is the preferred way. With .exchange(), we have more control about the response but also more responsibilities. Take a look at this blog post or the relevant part of the documentation to understand their difference in detail.

All upcoming examples use the preferred .retrieve()  method.

Handle Different HTTP Response Codes

By default, HTTP responses with 4xx (e.g. 404 for not found) or 5xx (e.g. 500 service unavailable) status codes result in an WebClientResponseException.

For modifying the way how errors are handled, we can use the onStatus method of Spring's WebClient to customize the resulting exception:

HTTP GET Request Example With Spring WebClient

Performing HTTP POST request with the WebClient is as simple as the following:

To put the request body in place, we can use the BodyInserters utility class and add any kind of Object, FormData, Publisher, MultipartData, Resource , etc.

Retry Configuration On Failure

For a more resilient architecture, we can configure retries for our WebClient . We can use the public methods of  Mono and Flux for this purpose.

Let's say we want to retry two times (max. three HTTP calls) and add a small delay between each retry:

Furthermore, we can combine the retry mechanism with a timeout from Mono or Flux to provide a fallback value:

Configure Filters for the Spring WebClient

If we have business logic or a configuration setup that applies to every HTTP request and response made with the WebClient, we can configure and chain multiple filters.

Logging the request/response might be such a requirement or adding authentication to the request. This is configured during the WebClient setup:

We can also provide global customizations for our WebClient instances using the WebClientCustomizer interface.

Writing Tests For Classes Using the WebClient

When it comes to writing unit tests for API clients, mocking the entire WebClient interaction with Mockito is usually not a good fit. A better approach is to start a local HTTP server and mock the HTTP responses from the remote system:

More information and examples for this test setup can be found here.

Integration Testing With the WebTestClient

For efficient integrations tests that test HTTP endpoints of our own application, we can use the WebTestClient. It's similar to the TestRestTemplate.

This client offers the same functionality as the normal WebClient but has additional methods for convention assertions and expectations for the HTTP result. As soon as we use @SpringBootTest with a not-mocked Servlet environment, Spring Boot auto-configures the WebTestClient  for us.

Let's assume we want to write an integration test for our HTTP endpoint /api/customers/1 to ensure our clients can search for a particular customer:

The detailed usage of the WebTestClient is covered in another blog post.

Accessing OAuth2 Protected Resources with Spring WebClient

With Spring Security we get a full integration for OAuth2. Have a look at the following blog posts where I demonstrate how to enable the OAuth2 integration for the Spring WebClient:

You can find the full source code for all examples on GitHub and more detailed information about the WebClient as part of the Spring documentation.

PS: If you want to achieve the same with Jakarta EE, take a look at the JAX-RS Client or the MicroProfile RestClient.

Have fun using the Spring WebFlux WebClient,

Phil

    • Hey Fernando,

      the WebClient is part of the WebFlux Spring dependency. You can pull this in your project without using Spring Boot. If you are using Maven, you can use the following import:


      <dependency<
         <groupIdorg.springframework</groupId>
         <artifactId>spring-webflux</artifactId>
         <version>5.2.2.RELEASE</version>
      </dependency>


      Make sure to align the version with the Spring version you have in use.

  • One question, Why do I get the illegal StateException: The underlying HTTP client completed without emitting a response when using the web client? When I use block it works correctly, any idea why it could be happening?

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
    >