Spring Boot WebClient and Unit Testing
Learn more about the Spring Boot WebClient and writing your own unit test cases.
Join the DZone community and get the full member experience.
Join For FreeIn this article, we will talk about the Spring Boot WebClient. If you are using Spring WebFlux, you can choose to use WebClient to call external rest services. It was introduced in Spring 5 as part of the web reactive framework that helps build reactive and non-blocking web applications.
WebClient is simply an interface that offers methods to make calls to rest services. This includes methods like GET, POST, PUT, PATCH, DELETE, and OPTIONS. You can leverage any of these methods to make calls to the external service asynchronously.
The main advantage of using the WebClient is that it is reactive, as it uses Webflux and is also non-blocking by nature and the response will always be returned in either Mono or Flux. So, make sure you are using Spring WebFlux already if you plan to use WebClient to make API calls.
How to Use Spring WebClient?
Note that I would be using a Maven build tool to show the demo. If you are using any other build tool, please find the dependency on the Internet, as they should be easily available.
Step 1. Add Spring WebFlux dependency to you POM.XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Step 2. Create an interface with a method that will return the response from the REST call.
public interface ContentService {
public Mono<Post> getPost(int id);
}
Step 3. Create a ServiceImpl
class that will have the implementation of the Service
interface created in Step 2.
@Service
public class ContentServiceImpl implements ContentService {
private static final Logger LOGGER = Logger.getLogger(ContentServiceImpl.class.getName());
private final WebClient webClient;
public ContentServiceImpl(@Value("${content-service}") String baseURL) {
this.webClient = WebClient.builder().baseUrl(baseURL)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
.filter(logRequest())
.build();
}
@Override
public Mono<Post> getPost(int id) {
return webClient.get().uri("posts/{id}", id).retrieve().bodyToMono(Post.class);
}
}
In step 3, we have created an instance of WebClient and initialized it by using the WebClient builder. It will then create a WebClient object and also allow you to customize your call with several methods that it offers. Please refer to all the methods while you use it.
You can choose HTTP methods, depending upon the nature of the HTTP call, and make a request to it. In the scenario above, we are leveraging the GET method and returning a response from the API call.
The method getPost
is the method that will be making the request with the help of the WebClient instance and retrieve the response from an external API call. If you have to make a POST
call, you can leverage the POST
method. And in that case, you will have to pass a body to the method body; there are a lot of methods to play around with. Once you start to use it, you will have various methods to put in use for sure.
How to Handle Errors
WebClientResponseException
when there will be a 4xx and 5xx series exception received. You can further customize it using the
onStatus()
method, like below.
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response ->
Mono.error(new MyCustomException())
)
.onStatus(HttpStatus::is5xxServerError, response ->
Mono.error(new MyCustomException())
)
.bodyToFlux(Post.class);
Unlike the .retrieve()
method, the .exchange()
method will not be throwing exceptions in case 4xx and 6xx series exception from the other end. So, it is always recommended to use the .retrieve()
method so that you can find the real cause of the exception and pass it further to the client after wrapping it in a Custom Exception. And if you can want to silence the exception and move further, you can use .exchange()
method (which, however, I am not recommending).
Writing Unit Test Cases for WebClient
Writing unit test cases for WebClient is a little tricky, as it includes the use of a library called the MockWebServer.
Below is the Maven dependency for that library. Once you add the library dependency, you can start to write the test cases for WebClient.
How to Write Test Cases
Step 1. First, create an object of MockWebServer
, like below:
private final MockWebServer mockWebServer = new MockWebServer();
Step 2. Once the object is created, you can stub the mock response, like below:
mockWebServer.enqueue(
new MockResponse()
.setResponseCode(200)
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.setBody("{\"userId\": 1,\"id\": 1, \"title\": \"sunt aut facere repellat p
Now, you can simply assert the actual response with the expected response.
That's it, we are good to go! In this article, we learned both how to make HTTP calls using WebClient and how to write unit test cases designed for testing the functionality.
Please refer to GitHub for full code access, and let us know your thoughts down in the comments below.
Published at DZone with permission of Deepak Mehra, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments