Spring WebClient (with Examples)

Spring WebClient is a non-blocking and reactive web client to perform HTTP requests. WebClient has been added in Spring 5 (spring-webflux module) and provides fluent functional style API.

Before Spring 5, RestTemplate has been the primary technique for client-side HTTP accesses, which is part of the Spring MVC project. Since Spring 5, WebClient is the recommended approach.

1. Maven

To use WebClient api, we must have spring-boot-starter-webflux module imported into the project.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

2. Creating Spring WebClient

To create WebClient bean, we can follow any one of the given approaches.

2.1. Using WebClient.create()

The create() method is an overloaded method and can optionally accept a base URL for requests.

WebClient webClient1 = WebClient.create();  //with empty URI

WebClient webClient2 = WebClient.create("https://client-domain.com");

2.2. Using WebClient.Builder API

We can also build the client using the DefaultWebClientBuilder class, which uses builder pattern style fluent-API.

WebClient webClient2 = WebClient.builder()
        .baseUrl("http://localhost:3000")
        .defaultCookie("cookie-name", "cookie-value")
        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .build();

3. Sending HTTP Requests

To send a request, we can use its fluent API and execute the necessary steps as per requirements. For example, sending an HTTP POST request involves the following steps.

  • Create WebClient.UriSpec reference using method(HttpMethod) or prebuilt methods such as get(), put(), post() or delete().
  • Set the request URI if not set already.
  • Set the request headers and authentication details, if any.
  • Set the request body, if any.
  • Call the retrieve() or exchange() method. The retrieve() method directly performs the HTTP request and retrieves the response body. The exchange() method returns ClientResponse having the response status and headers. We can get the response body from ClientResponse instance.
  • Handle the response returned from the server.

In the following example, we send an HTTP POST request to URI http://localhost:3000/employees that returns an Employee object after the successful call.

WebClient webClient = WebClient.create("http://localhost:3000");

Employee createdEmployee = webClient.post()
		.uri("/employees")
		.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
		.body(Mono.just(empl), Employee.class)
		.retrieve()
		.bodyToMono(Employee.class);

4. Handling API Response

If we want to get only the response body then using methods retrieve() and then use the bodyToFlux() and bodyToMono() methods.

....retrieve().bodyToMono(Employee.class);

//or

....retrieve().bodyToFlux(Employee.class);

Please note that bodyToMono() and bodyToFlux() methods always expect a response body of a given class type. If the response status code is 4xx (client error) or 5xx (Server error) i.e. there is no response body then these methods throw WebClientException. Use bodyToMono(Void.class) if no response body is expected.

webClient.put()
		.uri("/employees/100")
                .body(Mono.just(empl), Employee.class)
		.retrieve()
		.bodyToMono(Void.class);

Else, use the method exchange() which will return the ClientResponse which has all the response elements such as status, headers and response body as well.

When using exchange(), we must always use any of the bodyXXX() or toEntity() methods of ClientResponse to ensure resources are released and to avoid potential issues with HTTP connection pooling.

webClient.get()
    .uri("/employees/1")
    .exchange()
    .flatMap(clientResponse -> clientResponse.bodyToMono(Employee.class))
    .block();

As of Spring 5.3, the exchange() method is deprecated due to potential memory and connection leaks. Prefer exchangeToMono(), exchangeToFlux(), or retrieve() instead.

Mono<Employee> response = webClient.get()
		.uri("/employees/1")
		.exchangeToMono(response -> {
		
			if (response.statusCode().equals(HttpStatus.OK)) {
				return response.bodyToMono(Employee.class);
			} else if (response.statusCode().is4xxClientError()) {
				return Mono.just("Error response");
			} else {
				return response.createException().flatMap(Mono::error);
			}
		});

5. Spring WebClient Examples

5.1. GET API Example

Generally, we will use GET API to fetch either collection of resources or a singular resource. Let’s see the example of both use cases using get() method call.

  • HTTP GET /employees : collection of employees as Flux
  • HTTP GET /employees/{id} : single employee by id as Mono
@Autowired
WebClient webClient;

public Flux<Employee> findAll()
{
	return webClient.get()
		.uri("/employees")
		.retrieve()
		.bodyToFlux(Employee.class);
}

public Mono<Employee> findById(Integer id)
{
	return webClient.get()
		.uri("/employees/" + id)
		.retrieve()
		/*.onStatus(httpStatus -> HttpStatus.NOT_FOUND.equals(httpStatus),
                clientResponse -> Mono.empty())*/
		.bodyToMono(Employee.class);
}

5.2. POST API Example

POST API is commonly used for creating a resource. Let’s see an example of post() method to create an employee.

  • HTTP POST /employees : creates a new employee from request body and returns the created employee in response.
@Autowired
WebClient webClient;

public Mono<Employee> create(Employee empl)
{
	return webClient.post()
		.uri("/employees")
		.body(Mono.just(empl), Employee.class)
		.retrieve()
		.bodyToMono(Employee.class);
}

5.3. PUT API Example

PUT API is commonly used for updating a resource. Let’s see an example of put() method to update an employee.

  • HTTP PUT /employees/{id} : updates an existing employee data from the request body and returns the updated employee in response.
@Autowired
WebClient webClient;

public Mono<Employee> update(Employee e)
{
	return webClient.put()
		.uri("/employees/" + e.getId())
		.body(Mono.just(e), Employee.class)
		.retrieve()
		.bodyToMono(Employee.class);
}

5.4. DELETE API Example

DELETE API is commonly used for deleting a resource. Let’s see an example of delete() method to delete an employee from records.

  • HTTP DELETE /employees/{id} : deletes an existing employee by its id. It does not accept any request body as well as does not return any response body as well.
@Autowired
WebClient webClient;

public Mono<Void> delete(Integer id)
{
	return webClient.delete()
		.uri("/employees/" +id)
		.retrieve()
		.bodyToMono(Void.class);
}

6. Useful Configurations

6.1. Configuring Memory Limit

Spring WebFlux configures the default memory limit for buffering data in-memory to 256KB. If this limit is exceeded in any case then we will encounter DataBufferLimitException error.

To reset the memory limit, configure the below property in application.properties file.

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

6.2. Configuring Connection Timeouts

We can use HttpClient class to set timeout periods for connection timeout, read timeout and write timeouts.

@Bean
public WebClient getWebClient()
{
	HttpClient httpClient = HttpClient.create()
	        .tcpConfiguration(client ->
	                client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
	                .doOnConnected(conn -> conn
	                        .addHandlerLast(new ReadTimeoutHandler(10))
	                        .addHandlerLast(new WriteTimeoutHandler(10))));

	ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);	    

	return WebClient.builder()
	        .baseUrl("http://localhost:3000")
	        .clientConnector(connector)
	        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
	        .build();
}

Drop me your questions related to Spring WebClient.

Happy Learning !!

Sourcecode Download

Leave a Reply

6 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial