I am currently trying to consume a whole request coming back via webClient. I need to be able to read the body and the cookies that come with it. However I am currently having issues doing both together in one call. Below I have two ways of grabbing the data I want. I am pretty new at using lambdas and webClient. I do realize that exchangeToMono() is the latest method call to return a Mono or Flux because of the possible memory leak found in exchange(). I want to say subscribing() to a return monoBody might help me but so far I have had no luck extracting the data out that way as well. Thank you all for your input.
Mono<String> monoBody = webBuilder.build()
.get()
.uri(baseURI + "?Level=&pageSize=50&pageNo=&name=&id=&authToken=" + sessionToken)
.accept(MediaType.ALL)
.header("authToken", sessionToken)
.header("x-Token", sessionToken)
.header("X-token-X", sessionToken)
.header("Ref", ref)
.exchangeToMono(clientResponse -> clientResponse.bodyToMono(String.class));
Mono<MultiValueMap<String,ResponseCookie>> monoMap = webBuilder.build()
.get()
.uri(baseURI + "?Level=&pageSize=50&pageNo=&unitName=&id=&authToken=" + sessionToken)
.accept(MediaType.ALL)
.header("authToken", sessionToken)
.header("x-Token", sessionToken)
.header("X-token-X", sessionToken)
.header("Ref", ref)
.exchangeToMono(clientResponse -> Mono.fromCallable(()-> clientResponse.cookies() ));
The key thing to remember about the Reactor API (used by WebClient) is that you are always composing operations into a 'plan' of what to do and then at some point (subscription) you execute the entire plan.
In your case you've found the two methods to get the information you want but with a Reactive stream you can only ever have one type at any point in the stream, so if you need two types of data, you can always compose them into a composite object.
record DataWithCookies(MultiValueMap<String,ResponseCookie> cookies, String body){}
...
Mono<DataWithCookies> dataWithCookies =
webBuilder.build()
.get()
.uri(baseURI + "?Level=&pageSize=50&pageNo=&unitName=&id=&authToken=" + sessionToken)
.accept(MediaType.ALL)
.header("authToken", sessionToken)
.header("x-Token", sessionToken)
.header("X-token-X", sessionToken)
.header("Ref", ref)
.exchangeToMono(response ->
response.bodyToMono(String.class)
.map(stringBody -> new DataWithCookies(
stringBody,
response.cookies())
)
);
I used the previewed JDK 16 feature "Records" for brevity, but you could use a simple class for DataWithCookies
.
You now have a Mono that will yield the body along with the cookies. You might want to even extract that lambda into a private method for readability.
...
.exchangeToMono(this::extractBodyAndCookies);
...
private DataWithCookies extractBodyAndCookies(final ClientResponse response) {
return response.bodyToMono(String.class)
.map(stringBody -> new DataWithCookies(stringBody,
response.cookies())
);
}
Another option is to use Tuples.of(stringBody, response.cookies())
which avoids creating another type while still composing the two data.