Return the complete response using Spring WebClient
Asked Answered
F

3

5

I have the following code

public ClientResponse doGet(HttpServletRequest request, URI uri) {
    return webClient.get()
            .uri(uri.toASCIIString())
            .headers(headers -> headers.putAll(processRequest(request))
            .exchange()
            .block();
}

But when I try to return this ClientResponse through the RestController as follows,

@GetMapping
@ResponseBody
public ClientResponse doGet(HttpServletRequest request) {
    ClientResponse node = service.doGet(request);
    return node;
}

I get the following error:

org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class org.springframework.web.reactive.function.client.DefaultClientResponse

Basically, the ultimate goal I want is to return the actual response back to the invoker - including the headers, body, cookies etc.

I was thinking of using ResponseEntity like follows.

public ResponseEntity<JsonNode> doGet2(HttpServletRequest request, URI uri) {

    Mono<ClientResponse> clientResponse = webClient.get()
            .uri(uri.toASCIIString())
            .headers(headers -> headers.putAll(processRequest(request))
            .exchange();

    HttpHeaders headers = clientResponse.map(resp -> resp.headers().asHttpHeaders()).block();
    JsonNode body = clientResponse.flatMap(resp -> resp.bodyToMono(JsonNode.class)).block();

    ResponseEntity<JsonNode> jsonNode = ResponseEntity.ok().headers(headers).body(body);
    return jsonNode;
}

But this is again an overkill. Is there a way to return the response directly using WebClient instead of restructuring the response?

Fernandofernas answered 25/9, 2020 at 9:57 Comment(0)
F
9

ClientResponse's toEntity method converts it to a ResponseEntity<Mono> object. So I came up with the following.

public ResponseEntity<String> doGet2(HttpServletRequest request, URI uri) {
    ClientResponse clientResponse = webClient.get()
            .uri(uri.toASCIIString())
            .headers(headers -> headers.putAll(processRequest(request)))
            .exchange()
            .block();

    return clientResponse.toEntity(String.class).block();
}
Fernandofernas answered 25/9, 2020 at 14:5 Comment(4)
Seems not working, i got an error "block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-epoll-2"Unroof
@Unroof Yes am getting the same error. Did you find out the solution to this? How to read the client response and return it back?Bessel
@VikiCullen i am using another workaround like Flux<DataBuffer> as interceptor an print the content using doOnComplete()Unroof
.exchange() method is deprecated and not recommendedTrinl
C
3
  final ResponseEntity<String> response = webClient
            .post()
            .uri(uriBuilder -> uriBuilder.path("path").build())
            .accept(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromFormData(formData))
            .retrieve()
            .toEntity(String.class)
            .block();
Carisa answered 12/9, 2022 at 20:19 Comment(1)
Just delete the first "<", then this is a good answer. The main point is not to call bodyTo* but toEntity.Paulownia
S
1

Generally, when you return a pojo as responseBody, spring requires the class to have getters for the fields. Now, since you are not returning a class you own, you can't add them.
Other solution can be to add a library to your project that will convert the pojo into a json. this one can do the trick:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.0</version>
</dependency>
Sochi answered 25/9, 2020 at 10:7 Comment(1)
Actually I had added the jackson dependency and it had not fixed it.Fernandofernas

© 2022 - 2024 — McMap. All rights reserved.