Is it possible to include a request body in a GET request using Spring WebClient?
Asked Answered
A

2

12

I know sending a body with a GET request isn't the best idea but I'm trying to consume an existing API which requires it.

Sending a body with POST is straight-forward:

webClient.post()
        .uri("/employees")
        .body(Mono.just(empl), Employee.class)
        .retrieve()
        .bodyToMono(Employee.class);

It won't work with webClient.get() though, because while the post() method returns a WebClient.RequestBodyUriSpec, the get() method returns WebClient.RequestHeadersUriSpec<?>, which doesn't seem to allow any body definitions.

I've found a workaround for Spring RestTemplate here: RestTemplate get with body, but had no luck finding any for the new WebClient.

Acidulate answered 9/11, 2021 at 19:47 Comment(3)
~You cannot because HTTP doesn’t support it - as far as I know.~ I stand corrected - you can send a body with GET; although it’s a weird thing to do. Have you tried using .method(GET)?Soutache
@BoristheSpider's approach should work afaik (it's the same workaround that we may use if we send a CREATED response without a location header). But I have to agree with Boris that sending a body with a get - while not strictly forbidden - is highly discouraged not not best practice.Hosanna
It does work indeed! Thanks a lot @BoristheSpider. Idk how i didn't notice the generic .method().Acidulate
T
12

While the other responses are correct that you shouldn't use a body with a GET request, that is not helpful when you do not own, or cannot change the already existing method you are calling.

The problems is WebClient#get returns a WebClient.RequestHeadersUriSpec which does not provide a way for us to set the body.

WebClient#post returns a WebClient.RequestBodyUriSpec which does provide us a way to set the body but will cause us to use the wrong HTTP method, POST instead of GET.

Thankfully for us stuck in this situation there is WebClient#method which returns a WebClient.RequestBodyUriSpec and allows us to set the HTTP method.

webClient.method(HttpMethod.GET)
        .uri("/employees")
        .body(Mono.just(empl), Employee.class)
        .retrieve()
        .bodyToMono(Employee.class);

You may still run into issues in your testing libraries though...

Transsonic answered 29/12, 2021 at 12:36 Comment(1)
perfect answer !Maren
A
1

A GET reques has no body. It is forbidden (well, not forbidden, but not used at all) by the HTTP specification. You have two approaches here:

  • Do a POST. It is there just for that.
  • Use a query string and pass the data in that part of the URL.

Of course, you can attach the needed fields and pass a payload to the GET request, but it will probably be ignored, or worse, identified as an error and rejected by the server, before your served code has access to it. But if you are passing data to the server to do some processing with it, then POST is what you need to use.

Extracted from RFC-7231. HTTP 1.1. Semantics and code:

A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.

(markup is mine)

Reasons for this are, mainly, that a GET method must be idempotent, producing the same output for the same URL, if repeated. POST doesn't have these requirements, so POST is your friend.

Araroba answered 12/11, 2021 at 7:21 Comment(2)
I agree with the sentiment that using GET requests with a body is bad practice, and I wouldn't design my own APIs this way. However, as I described in the first sentence of my original question, the API I was using was expecting a GET with query details defined in the body. Sending a POST to the same endpoint would return an error. I'm also not sure if idempotence is THE reason why a GET cannot have a body. There's PUT which is also idempotent and commonly includes a payload.Acidulate
"A GET reques has no body. It is forbidden (well, not forbidden, but not used at all) by the HTTP specification." Please do not make a confusion between what you CAN do and what you SHOULD do. Bodies are really forbidden in HEAD requests, not GET requests. If you use a body, you SHOULD NOT use a GET and SHOULD use a POST instead.Hutt

© 2022 - 2024 — McMap. All rights reserved.