How do I conditionally chain webclient calls in spring webflux/webclient

Viewed 3176

I am trying to achieve the following scenario using WebClient. It is trivial using RestTemplate, but I can't do it anymore.

Relevant parts of a Spring controller in pseudo-java code:

Mono<T1> t1 = webClient.get()...retrieve()...;
Mono<T2> t2;

if (t1.getResult().getValue() > 0) {
    t2 = webClient.get().buildUsing(t1.getResult().getValue())...retrieve()...);
} else {
    t2 = Mono.empty();
}

return(Mono.zip(t1, t2, mergeFunction));

I am not asking how to use Webflux. I can also add error handling myself. My problem is how to pass data to the second call if the first call is successful and where to merge results of both calls one of which may or may not happen. The task is absolutely trivial if I could use RestTemplate.

There is a question with a very similar title, but it was not answered.

2 Answers

I think zipWhen fits well for this purpose. zipWhen waits for the result from first mono and then combines both results into a Tuple2

WebClient.builder().baseUrl("https://jsonplaceholder.typicode.com/todos/1")
    .build()
    .get()
    .retrieve()
    .bodyToMono(User.class)
    .zipWhen(r -> {
      if (r.getId() == 1) {
        return  WebClient.builder().baseUrl("https://jsonplaceholder.typicode.com/todos/2")
            .build()
            .get()
            .retrieve()
            .bodyToMono(User.class);
      } else {
        return Mono.empty();
      }
    });

The result is a Mono<Tuple2<T, T2>> holding both values.

as far as I could understand your problem, this is my reactive solution to this:

 private static Mono<String> mono() {
    Mono<Integer> t1 = Mono.just(0);

    return t1.flatMap(outerResult -> outerResult > 0
        ? Mono.just("VALUE").map(innerResult -> outerResult + "" + innerResult)
        : Mono.just(outerResult.toString())
    );
}

So what's happening here:

With .flatMap you subscribe to a new Mono and take the result of that. Inside the lambda of the .flatMap you still have the result of your t1, so you can use .map on t2, if you need to subscribe, or just do whatever you need to do with the result of t1 to bring it to the wanted return value.

Related