2

I have a code as follows. I am trying to zip the content. p1Mono and p2Mono are API calls to remote services. They throw various response HTTP response codes. How do I handle those API failures and return the exception with the corresponding codes?

 return Mono.zip(p1Mono,
                       p2Mono).flatMap(data -> {
            P1 p1 = data.getT1();
            p2 p2 = data.getT2();
            //some operation and combine result to p
            return Mono.just(p);
        });

1 Answers1

1

How about something like this:

Note- You can define separate custom exceptions or even handle your errors in other ways.

    Mono<ClientResponse> api1ResponseMono = webClient.post().uri("/some/api1").exchange();
    Mono<ClientResponse> api2ResponseMono = webClient.post().uri("/some/api2").exchange();

    return Mono.zip(api1ResponseMono,api2ResponseMono)
        .flatMap(tuple -> {
          ClientResponse api1Response = tuple.getT1();
          ClientResponse api2Response = tuple.getT2();

          HttpStatus api1ResponseHttpStatus = api1Response.statusCode();
          if(api1ResponseHttpStatus.is4xxClientError() || api1ResponseHttpStatus.is5xxServerError()){

            return api1Response.bodyToMono(String.class)
                      .flatMap(api1ResponseBody -> {
                        return Mono.error(new MyCustomException("Call to Api1 failed with response code: " + api1ResponseHttpStatus.value() + " because: " + api1ResponseBody));
                      });

          }

          HttpStatus api2ResponseHttpStatus = api2Response.statusCode();
          if(api2ResponseHttpStatus.is4xxClientError() || api2ResponseHttpStatus.is5xxServerError()){

            return api2Response.bodyToMono(String.class)
                .flatMap(api2ResponseBody -> {
                  return Mono.error(new MyCustomException("Call to Api2 failed with response code: " + api2ResponseHttpStatus.value() + " because: " + api2ResponseBody));
                });

          }

          Mono<MyCustomResponsePojo1> api1ResponseBodyMono = api1Response.bodyToMono(MyCustomResponsePojo1.class);
          Mono<MyCustomResponsePojo2> api2ResponseBodyMono = api1Response.bodyToMono(MyCustomResponsePojo2.class);

          return Mono.zip(api1ResponseBodyMono,api2ResponseBodyMono)
              .flatMap(t -> {
                MyCustomResponsePojo1 api1ResponseBody  =t.getT1();
                MyCustomResponsePojo2 api2ResponseBody  =t.getT2();
                //some operation and combine result to p
                return Mono.just(p);
              });
        });
Abhinaba Chakraborty
  • 3,488
  • 2
  • 16
  • 37
  • Thanks. I have also come up with a similar approach. My guess is there is no better way of doing than handling every response in an independent way. But is it possible to club the method in a single method so that it can be reused? – jagannathan rajagopalan Jul 11 '20 at 13:10
  • "handling every response in an independent way" - do you want to have a global exception handler for any web client response exception ? you can do that too (i can give some example of that , if you want) but you probably wont want to do that, coz it's better to have dedicated error handling for each dependent api call. – Abhinaba Chakraborty Jul 11 '20 at 13:21
  • and you can easily put this logic in a reusable method which accepts two client response monos and returns a combined result. – Abhinaba Chakraborty Jul 11 '20 at 13:22
  • Hey @jagannathanrajagopalan , there is always more than one approach to achieve the same thing. You gotta choose one fitting your need. And regarding your qstn, "How do I handle those API failures and return the exception with the corresponding codes?", I feel that, my approach definitely solves this problem in one way. So I would appreciate if you please accept the answer. – Abhinaba Chakraborty Jul 11 '20 at 18:54