Search code examples
javaspring-webfluxproject-reactorspring-webclient

Reactor - How to avoid recursion?


Using spring WebFlux, I would like to send HTTP requests one-by-one until a response fulfils a certain criteria. I also need to collect all responses. In the blocking world, the solution would be something like this:

List<String> responses = new ArrayList<>();
String lastResponse;
do {
  lastResponse = webClient.get()
    .uri(uri)
    .retrieve()
    .bodyToMono(String.class)
    .block();
  responses.add(lastResponse);
} while(!finished(lastResponse));

How to implement this without blocking?

note: there is a naive solution with recursion, but I'm looking for a more elegant way:

private List<String> collectRemaining() {
  return webClient.get()
    .uri(uri)
    .retrieve()
    .bodyToMono(String.class)
    .flatMap(response -> {
      if(finished(response)) {
        return List.of(response);
      }
      return collectRemaining().flatMap(remaining ->
          Stream.concat(Stream.of(response), remaining.stream()).collect(Collectors.toList());
    });
}

Solution

  • To replace recursion you can use expand() operator which makes it possible to generate the next element based on a previous one. It's commonly used to implement pagination logic. So something like the following could work:

    webClient.get()
            .uri(uri)
            .retrieve()
            .bodyToMono(String.class)
            .expand(response -> {
                if (finished(response)) {
                    return Mono.empty();
                }
                return webClient.get()
                        .uri(uri)
                        .retrieve()
                        .bodyToMono(String.class);
            }).collectList();
    

    Inspired by this article.