javaspring-webfluxspring-reactive

Spring WebClient nested Mono according to status codes


Using WebClient I want to handle ClientResponse separately according to HTTP status codes. Below you see two new subscribe() method used in top doOnSuccess. How can I carry those nested Monos to WebClient's Mono chain? That is to say, how to eliminate inner monos.

webClient.post()
            .uri( soapServiceUrl )
            .contentType(MediaType.TEXT_XML)
            //.body(Mono.just(req), String.class )
            .body( Mono.just(getCountryRequest) , GetCountryRequest.class  )
            .exchange()
            .filter( (ClientResponse response) -> { return true; } )
            .doOnSuccess( (ClientResponse response) -> {
                //nested mono 1
                if( response.statusCode().is5xxServerError() ){
                    response.toEntity(String.class).doOnSuccess(
                            error -> {
                                System.out.println("error : "+ error);
                            }).subscribe();
                }

                //nested mono 2
                if( response.statusCode().is2xxSuccessful() ){
                    response.toEntity(GetCountryResponse.class).doOnSuccess(
                            getCountryResponse -> {
                                System.out.println("success : "+ getCountryResponse.getBody().getCountry().getCapital());
                            }).subscribe();
                }
            })
            .doOnError( (Throwable error) -> {
                System.out.println( "getCountryResponse.error : "+ error );
            })
            .subscribe();

Solution

  • The Webclient's retrieve() method has better ways to handle error codes.

    I would do it like this:

    webClient.post()
                .uri( soapServiceUrl )
                .contentType(MediaType.TEXT_XML)
                //.body(Mono.just(req), String.class )
                .body( Mono.just(getCountryRequest) , GetCountryRequest.class  )
                .retrieve()
                .onStatus(
                  HttpStatus::isError,
                    clientResponse ->
                      clientResponse
                       //get the error response body as a string
                        .bodyToMono(String.class)
                        //flatmap the errorResponseBody into a new error signal
                        .flatMap(
                            errorResponseBody ->
                                Mono.error(
                                    new ResponseStatusException(
                                        clientResponse.statusCode(), 
                                          errorResponseBody))))
    
                //get success response as Mono<GetCountryResponse>
                .bodyToMono(GetCountryResponse.class)
                .doOnSuccess( (GetCountryResponse response) ->
                       System.out.println("success : " + 
                        response.getBody().getCountry().getCapital()))
                //Response errors will now be logged below
                .doOnError(ResponseStatusException.class, error -> {
                    System.out.println( "getCountryResponse.error : "+ error );
                })
                .subscribe();