0

I'm converting Spring Boot (MVC) application to Reactive Programming (Spring Webflux)

For making external rest calls, I'm using WebClient.

List<String> targetUrls = Arrays.asList("one","two","three");

        int iteration = 1;
        for(String target:targetUrls){

            // make a rest call here 
            // if 200 break the loop
            // else  loop continues
        }

The rest call here returns a Mono.

Is there a way to iterate over the list of urls(here in this case) and break the loop based on some response

Tried flatMap on the Mono and based on response can make a rest call to another url --> This works in case we know before hand the number of urls

2 Answers2

0

I'm not sure how you call the urls from the WebClient, but just assuming the URLs are passed to a method WebClient.get(String url), I will continue with the example.

The steps would be somewhat like you will first get a Flux of the URLs, then use flatMap (because your response is a Mono), then use map on these.

Flux.fromIterable(targetUrls)
  .flatMap(webClient::get)
  .map(response -> doSomethingWith(response))

Now you should have a Flux of responses. If the error handling from the WebClient isn't enough, you can also insert something inbetween.

Flux.fromIterable(targetUrls)
  .flatMap(webClient::get)
  .doOnError(errorHandler::handle)
  .map(response -> doSomethingWith(response))
thinkgruen
  • 929
  • 10
  • 15
  • Thanks for your response. I'm a beginner to reactive programming but if I understand correctly the above two examples will execute all the rest calls ( let say 3 rest calls here ) and we have a flux of responses. but my requirement here is to have the second rest call only if the first response is not 200OK. If the first response is 200 OK , break the loop or cancel the flux or do not make further api calls – Sunny Pukkalli Jun 21 '22 at 14:58
  • I haven't validated for your use case, but I think according to [this explanation and diagram](https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#doOnError-java.util.function.Consumer-), any failure will stop processing. You could also use `doOnNext` and then handle the response code on your own. I am not 100% sure if the WebClient treats a 4xx and 5xx as an error already. I think it does. – thinkgruen Jun 21 '22 at 17:19
  • In case it doesn't [here](https://stackoverflow.com/a/60688375/3393379) are a few more pointers. – thinkgruen Jun 21 '22 at 17:24
0

There are several patterns you could apply to implement this logic

You can use flatMap to execute multiple queries concurrently. By default, flatMap will process Queues.SMALL_BUFFER_SIZE = 256 number of in-flight inner sequences.

Flux.fromIterable(targetUrls)
  .flatMap(url -> webClient.get(url)) 
  .map(response -> process(response))

You could control concurrency flatMap(url -> webClient.get(url), concurrency) or use concatMap operator if you want to execute queries sequentially.

Another useful pattern in case you need response to make decision about next request - use expand operator. For example, in case of paginated requests.

webclient.get(url)
        .expand(response -> {
            if (<should stop>) {
                // stop the loop
                return Mono.empty();
            }

            return webclient.get(url);
        });

Alex
  • 4,987
  • 1
  • 8
  • 26