Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

Spring RestTemplate has been the mainstay of most Java back-end projects. Some of the background material for using RestTemplate can be found here Using UriBuilder and Using Spring RestTemplate with path parameters. Spring RestTemplate isn’t gone, but the writing is on the wall. It’s time to get up to speed on WebClient, even if you aren’t being Reactive.

Spring RestTemplate has been the mainstay of most Java back-end projects. http://javaninja.net/2019/02/using-uribuilder/Spring RestTemplate isn’t gone, but the writing is on the wall. It’s time to get up to speed on WebClient, even if you aren’t being Reactive.

Maven Dependencies

Add the following Maven dependencies to your project.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>org.projectreactor</groupId>
    <artifactId>reactor-spring</artifactId>
    <version>1.0.1.RELEASE</version>
</dependency>

GET with static URL

Your RestTemplate call would have looked something like the following:

ConfigurationListModel configurationListModel = 
    restTemplate.getForObject(configurationServiceUrl + "/app/some/url", 
                              ConfigurationListModel.class);

The pertinent parts of that code are the static URL and the object that the response will be parsed into.

The WebcClient code is going to be a little more verbose, but it is simple enough.

ConfigurationListModel configurationListModel =
    WebClient.create(configurationServiceUrl)
             .get()
             .uri("/app/some/url")
             .retrieve()
             .bodyToMono(ConfigurationListModel.class)
             .block();
  • create – creates a WebClient with the specified base (host) URL. Scheme + host in this case.
  • get – prepares this request to be a GET request.
  • uri – the desired url. A static path in this case.
  • retrieve – performs the specified HTTP request against the specified resource.
  • bodyToMono – extracts the response body to a mono. A mono of my custom response object in this case.
  • block – wait till the requested HTTP resource responds (e.g. perform a synchronous call).

Get with Query Parameters

A typical RestTemplate get with request parameters is below. I use UriComponentsBuilder to build the URI.

URI uri = UriComponentsBuilder.fromUriString(configurationServiceUrl)
                              .path("/app/configuration/list")
                              .queryParam("param", param)
                              .build(true)
                              .toUri();
ConfigurationListModel configurationListModel = 
    restTemplate.getForObject(uri, ConfigurationListModel.class);

There are two different way that query parameters can be handled. The first way is to use parameter substitution.

ConfigurationListModel configurationListModel =
    WebClient.create(configurationServiceUrl)
             .get()
             .uri("/app/some/url?param={param}", paramValue)
             .retrieve()
             .bodyToMono(ConfigurationListModel.class)
             .block();

The second implementation takes advantage of the builder to create the URI.

ConfigurationListModel configurationListModel =
    WebClient.create(configurationServiceUrl)
             .get()
             .uri(builder -> builder.path("/app/some/url")
                                    .queryParam("param", param)
                                    .build())
             .retrieve()
             .bodyToMono(ConfigurationListModel.class)
             .block();

GET with a PATH variable

Let’s consider an example where the URL contains data. That data is commonly referred to as a PATH variable. I generally used the UriComponentsBuilder when it came to composing a URL. This moves the extra bit of complexity out of the RestTemplate call.

URI uri = UriComponentsBuilder.fromUriString(configurationServiceUrl)
                              .path("/app/configuration/{stackId}/list")
                              .buildAndExpand(stackId)
                              .encode()
                              .toUri();
ConfigurationListModel configurationListModel = 
    restTemplate.getForObject(uri, ConfigurationListModel.class);

The conversion to WebClient is very similar to the static URL call. The only difference is in the uri method call.

ConfigurationListModel configurationListModel =
    WebClient.create(configurationServiceUrl)
             .get()
             .uri("/app/configuration/{stackId}/list", stackId)
             .retrieve()
             .bodyToMono(ConfigurationListModel.class)
             .block();

The uri method now takes an additional value. It is substituted in the specified path parameter. The path parameter value is specified by {}, like it is for UriComponentsBuilder.

POST with a body

Building on top of the examples that we have already is the need to perform a POST. Here is what a typical RestTemplate POST will look like.

ConfigurationValueModel request = new ConfigurationValueModel();
request.setAffiliateId(affiliateId);
request.setStackId(stackId);
request.setKey(key);

ConfigurationValueModel configurationValueModel = 
    restTemplate.postForObject(configurationServiceUrl + "/app/some/url", 
                               request, 
                               ConfigurationValueModel.class);

I built the contents of the body in an object that has all of the properties that I need. That part of the solution will stay the same.

ConfigurationValueModel request = new ConfigurationValueModel();
request.setAffiliateId(affiliateId);
request.setStackId(stackId);
request.setKey(key);

ConfigurationValueModel configurationValueModel = WebClient.create(configurationServiceUrl)
         .post()
         .uri("/app/configuration/value/get")
         .body(BodyInserters.fromObject(request))
         .retrieve()
         .bodyToMono(ConfigurationValueModel.class)
         .block();

The post method is specified instead of the get method. The next big change is the inclusion of the body method. The body method needs a body inserter. In this case, I use an inserter that inserts the body from a specified object. I specify my previously used object.

With this foundation, it should be very easy to build out the replacements for the rest of your Spring RestTemplate calls as you migrate to the new WebClient.

April 27th, 2019

Posted In: Javaninja

Leave a Reply

Your email address will not be published. Required fields are marked *

WP to LinkedIn Auto Publish Powered By : XYZScripts.com