Search code examples
springspring-bootspring-webclient

Return List<String> from Spring WebClient's onStatus response


Using Spring's WebClient I make a call to a remote system. If the remote system answers with HTTP 422, then it also returns a list of strings in its response body which I would like to return as a List<String>.

This is my current code, but the IDE tells me:

Required type: Mono<? extends Throwable>
Provided: Mono<List<String>>
no instance(s) of type variable(s) exist so that List<String> conforms to Throwable

Is it possible to achieve what I'm looking for?

webClient
  .post()
  .uri("/validation/{reference}", reference)
  .body(Mono.just(request), ValidationRequest.class)
  .retrieve()
  .onStatus(HttpStatus.UNPROCESSABLE_ENTITY, response -> {
      // extract response body as List<String> and return it...
      return response.bodyToMono(new ParameterizedTypeReference<List<String>>() {});
  })
  .block();

Solution

  • The error is correct as onStatus needs to return an object of type Mono<? extends Throwable>. Instead of that method, you can use the onErrorResume method to handle exceptions of type WebClientResponseException differently, as in check if the status code is 422 and if so, parse the response body into a List<String>. The code could look something like below:

    ObjectMapper objectMapper = new ObjectMapper(); 
    webClient
      .post()
      .uri("/validation/{reference}", reference)
      .body(Mono.just(request), ValidationRequest.class)
      .retrieve()
      .bodyToMono(new ParameterizedTypeReference<List<String>>() {})
      .onErrorResume(WebClientResponseException.class, ex -> {
            try {
                return ex.getRawStatusCode() == 422 ? 
                        Mono.just(objectMapper.readValue(ex.getResponseBodyAsString(), new TypeReference<List<String>>() {})) : 
                            Mono.error(ex);
            } catch (JsonProcessingException jsonException) {
                return Mono.error(jsonException);
            }
        })
      .block();