How to Get a Response Body When Testing the Status Code in WebFlux WebClient?
Spring WebFlux is an HTTP request client. Reactor is the foundation of WebClient’s functional and fluid API, allowing declarative building of asynchronous logic without requiring knowledge of threads or concurrency. It uses the same codecs that are also used to encode and decode request and response material on the server side, and it is completely non-blocking and streaming-compatible.
Example of Testing the Status Code in WebFlux WebClient
Here is an example of Get a Response Body when Testing the Status Code in WebFlux WebClient.
// Making a POST request and retrieving the response
client.post()
.exchange()
.doOnSuccess(response -> {
// Check if the HTTP status code is 201 (Created)
if (response.statusCode().value() == 201) {
// If status code is 201, throw a runtime exception
throw new RuntimeException("Unexpected HTTP status code 201");
}
});
Step-by-Step Implementation to get a Response Body When Testing the Status Code in WebFlux WebClient
Below are the steps to implement to get a Response Body while testing the status code in WebFlux WebClient.
Step 1: Add Maven Dependencies
The spring-boot-starter-webflux module has to be imported into our Spring Boot project in order for us to access the WebClient API.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Step 2: Use WebClient.Builder API
The DefaultWebClientBuilder class, which employs the builder pattern style fluent-API, is another way we might construct the client.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebConfig
{
@Bean
public WebClient webClient()
{
// create a WebClient bean with a base URL and default settings
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:3000")
.defaultCookie("cookie-name", "cookie-value")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
// return the configured WebClient bean
return webClient;
}
}
Step 3: Get the WebFlux WebClient to use onStatus
An integrated method for managing a WebClient response is onStatus. This enables us to apply fine-grained functionality depending on certain replies or status categories.
WebClient
.builder()
.build()
.post()
.uri("/some-resource")
.retrieve()
.onStatus(
HttpStatus.INTERNAL_SERVER_ERROR::equals,
response -> response.bodyToMono(String.class).map(Exception::new))
Step 4: Use ExchangeFilterFunction to handle specific status codes
A further method to handle certain status codes and obtain response bodies is to use an ExchangeFilterFunction. The exchange filter is adaptable and may apply to filter functionality based on any Boolean expression, in contrast to onStatus.
/**
* Processes the client response by checking its HTTP status code and handling specific cases.
*
* @param response The client response to be processed.
* @return A Mono representing the processed response or an error Mono with a custom exception.
*/
private static Mono<ClientResponse> exchangeFilterResponseProcessor(ClientResponse response)
{
// extract the HTTP status code from the response
HttpStatus status = response.statusCode();
// handle Internal Server Error (500) case
if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status))
{
return response.bodyToMono(String.class)
.flatMap(body -> Mono.error(new CustomServerErrorException(body)));
}
// handle Bad Request (400) case
if (HttpStatus.BAD_REQUEST.equals(status)) {
return response.bodyToMono(String.class)
.flatMap(body -> Mono.error(new CustomBadRequestException(body)));
}
// if the response does not match any special case, return it as is
return Mono.just(response);
}
Step 5: Use a method reference to handler
Now we will use a method reference to handler to test the status code.
// define an ExchangeFilterFunction for handling responses
ExchangeFilterFunction errorResponseFilter = ExchangeFilterFunction
// use the ofResponseProcessor method to specify a response processor
.ofResponseProcessor(WebClientStatusCodeHandler::exchangeFilterResponseProcessor);
// this filter is likely to be applied to a WebClient instance for handling HTTP responses
// define an ExchangeFilterFunction for handling responses
ExchangeFilterFunction errorResponseFilter = ExchangeFilterFunction
// use the ofResponseProcessor method to specify a response processor
.ofResponseProcessor(WebClientStatusCodeHandler::exchangeFilterResponseProcessor);
Step 6: Apply this ResponseFilter to WebClient
Now use this on a WebClient object to accomplish the same goal as the onStatus chained call:
// make a POST request using WebClient
Mono<String> response = WebClient
.builder()
// apply the errorResponseFilter as a filter for handling responses
.filter(errorResponseFilter)
.build()
.post()
.uri("some-resource")
.retrieve()
// extract the response body as a Mono<String>
.bodyToMono(String.class);
// perform further actions with the response, such as handling or processing it
response.subscribe(
// onSuccess: Handle the successful response
successResponse -> {
System.out.println("Successful Response: " + successResponse);
},
// onError: Handle errors that may occur during the request
error -> {
// Handle and log the error (e.g., network issues, HTTP errors, etc.)
System.err.println("Error during request: " + error.getMessage());
},
// onComplete: Handle completion (optional)
() -> {
// Optionally handle completion, if needed
System.out.println("Request completed successfully");
}
);
By using the above methods, we can get the response body based on the HTTP Status code in WebFlux WebClient.