I'm using Spring WebFlux WebClient to retrieve data from an external API, like this:
public WeatherWebClient() {
this.weatherWebClient = WebClient.create("http://api.openweathermap.org/data/2.5/weather");
}
public Mono<String> getWeatherByCityName(String cityName) {
return weatherWebClient
.get()
.uri(uriBuilder -> uriBuilder
.queryParam("q", cityName)
.queryParam("units", "metric")
.queryParam("appid", API_KEY)
.build())
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(String.class);
}
This works fine and produces a response like this:
{
"coord":{
"lon":-47.06,
"lat":-22.91
},
"weather":[
{
"id":800,
"main":"Clear",
"description":"clear sky",
"icon":"01d"
}
],
"base":"stations",
"main":{
"temp":16,
"pressure":1020,
"humidity":67,
"temp_min":16,
"temp_max":16
},
"visibility":10000,
"wind":{
"speed":1,
"deg":90
},
"clouds":{
"all":0
},
"dt":1527937200,
"sys":{
"type":1,
"id":4521,
"message":0.0038,
"country":"BR",
"sunrise":1527932532,
"sunset":1527971422
},
"id":3467865,
"name":"Campinas",
"cod":200
}
But I'm only interested in the "temp" property (main -> temp). How could I transform the response (using Jackson's ObjectMapper, for example) to return only "temp" value in a reactive/non-blocking way?
I understand the first thing is replacing ".retrieve()" by ".exchange()" but I can't figure out how to make it work.
PS: This is my first question here. Please let me know if I'm doing something wrong or if you need more details.
Thanks!
WebClient Non-Blocking Client. On the other side, WebClient uses an asynchronous, non-blocking solution provided by the Spring Reactive framework. While RestTemplate uses the caller thread for each event (HTTP call), WebClient will create something like a “task” for each event.
A non-blocking way would be via one of the overloaded subscribe() methods. In this example, we will use the subscribe(Consumer<? super T> consumer) to get the data from Mono asynchronously. With subscribe(), the current thread will not be blocked waiting for the Publisher to emit data.
Mono is a reactive publisher, that can emit 0 zero or 1 elements. Thus, in order to retrieve a single JSON resource with WebClient, we should use Mono publisher. We will use WebClient to read a JSON object and parse it into POJO. Example of WebClient reading single JSON Object as a POJO with Mono.
You need to create a type that corresponds to the response sent by the server. A very minimal example could be like this:
@JsonIgnoreProperties(ignoreUnknown = true)
public class WeatherResponse {
public MainWeatherData main;
}
and the MainWeatherData
class could be:
@JsonIgnoreProperties(ignoreUnknown = true)
public class MainWeatherData {
public String temp;
}
Finally, you could use WeatherResponse
in bodyToMono
:
...
.retrieve()
.bodyToMono(WeatherResponse.class);
The @JsonIgnoreProperties(ignoreUnknown = true)
annotation instructs Jackson to not give any errors if it encounters any value in JSON string that is not present in you POJO.
You can access the WeatherResponse
object with a chained map
operator:
getWeatherByCityName(cityName)
.map(weatherResponse -> weatherResponse.main.temp)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With