Spring Boot WebClient and it’s testing

Table of contents
Reading Time: 3 minutes

Alright, In this article we will talk about Spring Boot Web Client. If you are using Spring WebFlux, you can choose to use WebClient to call external rest services. It was introduced in Spring 5 as as part of Web reactive framework that helps to build reactive and non blocking web applications. WebClient is simply an interface which offers some methods to make calls to rest services, there are 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, It’s reactive as it uses webflux and It’s also non blocking in nature by default and 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 – I would be using maven build tool to show the demo. If you are using any other build tool, please find the dependency on the internet, they are easily available.

Step1. Add Spring WebFlux dependency to you POM.XML



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


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

Step2. Create an interface with method which will return the response from rest call.



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


public interface ContentService {
public Mono<Post> getPost(int id);
}

https://gist.github.com/deepakmehra10/a0df105a32e53f1efbce6e42936971da#file-contenetservice-java

Step3. Create a ServiceImpl class which will have the implementation of Service interface created in Step2.



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


@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 step3 we have created an instance of WebClient and initialized it by using WebClient builder, it will create a WebClient object and will also allow you to customise your call with several methods 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 request to it. In the scenario above, we are leveraging GET method and returning a response from API call.

The method getPost is the method which will be making the request with the help of webclient instance and retrieve the response from external API call. If you have to make a POST call you can leverage 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?

To handle errors in WebClient you can use extend retrieve method. The retrieve method in WebClient throws WebClientResponseException when there will be a 4xx and 5xx series exception is received. You can further customise it using onStatus() method like below.



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


.retrieve()
.onStatus(HttpStatus::is4xxClientError, response ->
Mono.error(new MyCustomException())
)
.onStatus(HttpStatus::is5xxServerError, response ->
Mono.error(new MyCustomException())
)
.bodyToFlux(Post.class);
view raw

Error.java

hosted with ❤ by GitHub

Unlike, retrieve method exchange method will not be throwing exceptions in case 4xx and 6xx series exception from other end. So, it is always recommended to use 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(not recommending).

Writing Unit Test Cases for WebClient

Wrtiing Unit Test cases for WebClient was a little tricky as it included use of a library called 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?

Step1. First create an object of MockWebServer like below



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


private final MockWebServer mockWebServer = new MockWebServer();

Step2. Once the object is created you can stub the mock response like below.



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


mockWebServer.enqueue(
new MockResponse()
.setResponseCode(200)
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.setBody("{\"userId\": 1,\"id\": 1, \"title\": \"sunt aut facere repellat provident occaecati excepturi optio reprehenderit\", \"body\": \"quia et suscipit\"}"));

Now, you can simply assert the actual response with the expected response.

That’s it, you are good. What you learnt from this article?
1. How to make HTTP calls using WebClient.
2. How to write unit test cases to test the functionality.

Please refer to the github link for full code access. If you liked this article please help me spread this. Also, let me know in comments if you have any questions related to the article.

Knoldus-blog-footer-image

Written by 

Deepak is a Software Consultant having experince of more than 5 years . He is very enthusiastic towards his work and is a good team player. He has sound knowledge of different technologies which include Java, C++, C, HTML, CSS, Javascript, C# always keen to learn new technologies.

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading