Search code examples
spring-bootmonoreactive-programmingspring-webfluxflux

How to make dependent webclient calls


I need to make 3 dependent WebClient API calls. In the end, I want a Mono of FinalResponse Object. I need to use the value from the first API response to make a call to the second API (which would return Mono of Purchase class. Purchase class would contain 2 member variables

  1. user object
  2. List Now for each value in the list, I need to make a third API call. and then return the final mono object to the controller.

I'm currently stuck with how to go about with an asynchronous call to 3rd API for each value in the list(returned by 2nd API)

service.getPurchases returns Mono<Purchase>. service.getSimilarItems returns Mono<List<Item>>.

class Purchase{
   private List<Item> purchasedItemsList;
}

class Item {
   private int itemId;
   private int categoryId;
   private String itemName;
}
public Mono<FinalResponse> getEndResults(UserRequest userRequest) {
        Mono<User> response1 = service.getUserResponse(userRequest);
        return response1.flatMap(response -> {
           int userId = response.getUserId();
           FinalResponse finalResponse = new FinalResponse();
           List<AllItems> itemList = new LinkedList<>();
           return service.getPurchase(userRequest, userId)
                    .map(purchasedItem -> {
                        val.getPurchasedItemsList().forEach(oneItem -> {      // please help me how to go about from here
                              service.getSimilarItemsInCategory(userRequest, userId, oneItem.getCategoryId)
                              .map(similarItem -> { 
                                AllItems allItem = new AllItems();     
                                allItem.setPurchasedItem(oneItem);
                                allItem.setSimilarItem(similarItem);
                                itemList.add(allItem);
                              });
                        });
                finalResponse.setResults(itemList);
                 return finalResponse;
                    });
        });
    }



class FinalResponse {
    private User user;
    private List<AllItems> results;
}
class AllItems {
    private Item purchasedItem;
    private List<Item> similarItem;
}

Basically the end response I need would look like

{
 "users":{//UserObject//},
 "results": [
     {
         "purchasedItem": {// Purschased Item 1},
         "similarItems": [
             {//Similar Item 1},
             {//Similar Item 2}
          ]
     },
     {
         "purchasedItem": {// Purschased Item 1},
         "similarItems": [
             {//Similar Item 1},
             {//Similar Item 2}
          ]
     }
 ]

}

Solution

  • Following Toerktumlare's comment: This can be fairly simple, if the WebClient calls return Monos or Fluxes of simple values or lists.

    You can use flatMapMany() or flatMapIterable().

    What about this simplified example?

    
        public Mono<FinalResponse> getEndResults(UserRequest userRequest) {
            Mono<User> userResponse = service.getUserResponse(userRequest);
            return userResponse.flatMap(response -> {
                        int userId = response.getUserId();
                        return service.getPurchase(userRequest, userId)
                                .map(Purchase::getPurchasedItemsList)
                                .flatMapIterable(purchasedItems -> purchasedItems)
                                .flatMap(oneItem -> getSimilarItemInCategory(userRequest, userId, oneItem))
                                .collectList();
                    })
                    .map(itemList -> {
                        FinalResponse finalResponse = new FinalResponse();
                        finalResponse.setResults(itemList);
                        return finalResponse;
                    });
        }
    
        public Mono<AllItems> getSimilarItemInCategory(UserRequest userRequest, int userId, Item oneItem) {
            return service.getSimilarItemsInCategory(userRequest, userId, oneItem.getCategoryId())
                    .map(similarItem -> {
                        AllItems allItem = new AllItems();
                        allItem.setPurchasedItem(oneItem);
                        allItem.setSimilarItem(similarItem);
                        return allItem;
                    });
        }