KPACHblu
KPACHblu

Reputation: 51

Webflux/Reactor makes two API calls instead of one

I have a webflux application. In one place I make 3 API calls. Every call depends on result of previous call.

Mono<List<Book>> books = bookService.find(params); //1st API call
Mono<List<User>> users = books.flatMapMany(Flux::fromIterable)
    .map(User::getId)
    .collectList()
    .map(allUserIds -> userService.findUsers(allUserIds)) //2nd API call
    .flatMap(mono -> mono);

Mono<List<User>> parents = users.flatMapMany(Flux::fromIterable)
    .filter(user -> user.getParentId() != null)
    .map(User::getParentId)
    .collectList()
    .map(parentIds -> userService.findUsers(parentIds)) //3rd API call
    .flatMap(mono -> mono);

Mono<List<User>> usersWithParents = Flux.merge(users, parents)
    .flatMapIterable(Function.identity())
    .collectList();

This code works, but I get 4 API calls in total. I get two API calls for 2nd step. I assume that reactor makes 1 call to calculate parents variable and 2n call for Flux.merge(users, parents). How can I update the call to avoid extra API call?

Upvotes: 0

Views: 1313

Answers (2)

Vova Bilyachat
Vova Bilyachat

Reputation: 19484

I think you should do smth like this

public Mono<List<User>> getAllUsers(){
    Mono<List<String>> booksMono = bookService.find(params)
            .flatMapMany(Flux::fromIterable)
            .map(User::getId)
            .flatMap(book->userService.findUsers(allUserIds))
            .collectList()
            .flatMap(users->Mono.zip(users, getParents(users)))
            .flatMap(zippedUsers->  Stream.concat(zippedUsers.getT1(), zippedUsers.getT2()));
}

private Mono<List<User>> getParents(List<User> users){
    return Flux.fromIterable(users)
            .filter(user -> user.getParentId() != null)
            .map(User::getParentId)
            .collectList()
            .map(parentIds -> userService.findUsers(parentIds));
}

Upvotes: 2

KPACHblu
KPACHblu

Reputation: 51

Found a solution. We need to combine 2nd and 3rd API calls into one chain with flatmap:

Mono<List<Book>> books = bookService.find(params); //1st API call
Mono<List<User>> users = books.flatMapMany(Flux::fromIterable)
    .map(User::getId)
    .collectList()
    .map(allUserIds -> userService.findUsers(allUserIds)) //2nd API call
    .flatMap(mono -> mono);
    .flatMap(children -> {
      List<Long> parentIds = children.stream()
          .filter(child -> child.getParentId() != null)
          .map(User::getParentId)
          .collect(toList());
      return userService.findUsers(parentIds);
    });

Upvotes: 0

Related Questions