41

Isn't it against REST-style approach to pass a request body together with GET request?

For instance to filter some information in Elasticsearch

curl localhost:9200/megacorp/employee/_search -d '{"query" : {"filtered" : {"filter" : {"range" : {"age" : { "gt" : 30 }}},"query" : {"match" : {"last_name" : "smith"}}}}}'

some tools are even designed to avoid request body in GET request (like postman)

lospejos
  • 1,976
  • 3
  • 19
  • 35
yurko
  • 1,502
  • 1
  • 13
  • 14
  • See this answer which might help: http://stackoverflow.com/questions/34795053/es-keeps-returning-every-document/34796014#34796014 – Val Apr 29 '16 at 13:35
  • Detailed answer about GET and Body - https://stackoverflow.com/a/8502004/1589840 – serhiisavruk Jul 04 '17 at 10:21
  • @yurko how would you feel about changing your accepted answer? I worry that the accepted answer is going to mislead developers in the future to do the wrong thing. – Evert Jul 21 '18 at 17:37

3 Answers3

25

From the RFC:

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.

In other words, it's not forbidden, but it's undefined behavior and should be avoided. HTTP clients, servers and proxies are free to drop the body and this would not go against the standard. It's absolutely a bad practice.

Further text from the HTTPBis working group (the group working on HTTP and related standards):

Finally, note that while HTTP allows GET requests to have a body syntactically, this is done only to allow parsers to be generic; as per RFC7231, Section 4.3.1, a body on a GET has no meaning, and will be either ignored or rejected by generic HTTP software.

source

Community
  • 1
  • 1
Evert
  • 93,428
  • 18
  • 118
  • 189
  • Is GET _search?q=foo correct? Yes. Then why would you change the semantic when you want to pass foo as a json body? It's a search call for both at the end. I'm not posting something to the server to change its state. I'm just requesting something from the server, whatever the way I'm passing parameters. – dadoonet Jun 15 '18 at 09:40
  • 1
    @dadoonet because the appearance of a body with GET, while not 'invalid' should not have a semantic meaning to the request. In other words, it should be ignored. Whether or not you agree with this, this is absolutely the intent of the protocol. – Evert Jun 15 '18 at 17:44
  • 2
    I could go into details why I think this is a actually good design, but I think for the purpose of this discussion it's better to stick to the raw facts. The HTTP working group clearly states that generic HTTP software will ignore or reject bodies. Therefore, elasticsearch's implementation relies on non standard behavior. Any compliant HTTP proxies and caches will misbehave in conjunction with elasticache because they tend to be compliant. – Evert Jun 15 '18 at 17:50
  • The source link to HTTPBis is now broken, Also a new replacement RFC 9110 exists, and it appears to acknowledge GET with body is possible, but still does not recommend generally and mentions possibility of smuggling attack if you do so: https://www.rfc-editor.org/rfc/rfc9110#section-9.3.1-6 – Ryan May 22 '23 at 19:05
17

No. It's not.

In REST, using POST to query does not make sense. POST is supposed to modify the server. When searching you obviously don't modify the server.

GET applies here very well.

For example, what would be the difference of running a search with:

GET /_search?q=foo

vs

GET /_search
{
  "query": {
    "query_string": {
      "query" : "foo"
    }
  }
}

In both cases, you'd like to "GET" back some results. You don't mean to change any state on the server side.

That's why I think GET is totally applicable here wether you are passing the query within the URI or using a body.

That being said, we are aware that some languages and tools don't allow that. Although the RFC does not mention that you can't have a body with GET.

So elasticsearch supports also POST.

This:

curl -XPOST localhost:9200/megacorp/employee/_search -d '{"query" : {"filtered" : {"filter" : {"range" : {"age" : { "gt" : 30 }}},"query" : {"match" : {"last_name" : "smith"}}}}}'

Will work the same way.

dadoonet
  • 14,109
  • 3
  • 42
  • 49
  • 14
    If you claim that sending a get request with body is RESTful, so how do you explain [this](https://stackoverflow.com/a/983458/1057791)? – BornToCode Jun 29 '17 at 07:32
  • 10
    -1 That is why it's chaos with all this interpretation. If the semantics would be ignored, why would there be a need for so many request types. RESTful APIs should not take into consideration a body in their GET endpoints. Elastic stack is just hacky and not mature, alot of work to do on it (like most new open source projects, nothing wrong with that, time to make it better). If there was no body in GET, there was no need for a POST endpoint alternative ... This is why it's chaos, no conventions. I actually am for leaving the path in the url to decide, but REST was designed to use HTTP semanti – Geo C. Aug 01 '17 at 10:11
  • 1
    One HTTP request type to rule them all, the best way and most flexible in my opinion,and leave flexibility for those who implement and use the protocol , throught the url. this way there will be no obscurity with some endpoints (what exactly they are doing). I'm not really a fan of REST. I am a fan of simplicity & flexibility & of things that are easy to understand at the first sight – Geo C. Aug 01 '17 at 10:17
  • 5
    This answer is definitely incorrect. See my answer for sources. – Evert Jun 15 '18 at 07:37
  • 1
    except that Window.fetch does not allow a GET request to include a body – Zach Smith Mar 25 '20 at 14:57
  • That's why I said "So elasticsearch supports also POST." – dadoonet Mar 26 '20 at 15:06
  • @GeoC. You actually meant "If there was a body in GET, there was no need for a POST endpoint alternative" (without the word **no**) which means, if someone is allowed to provide a request body in Elasticsearch's GET endpoint and Elasticsearch's server will read the request body instead of ignoring it, a POST endpoint will be unnecessary, didn't you? – blackr1234 Sep 20 '21 at 02:09
  • I meant that because not all the clients are supporting `GET` with a body, Elasticsearch added the support for `POST` for APIs which are not changing the state of the server. Like `GET /_search` can be also called with `POST /_search`. Kibana for example transforms all GET with body calls to POST with body calls because the browser does not allow GET with body. – dadoonet Sep 20 '21 at 12:06
  • How did this get upvotes - it is not correct. POST is not required to modify anything. Please read read the HTTP RFC - “ Providing a block of data, such as the result of submitting a form, to a data-handling process” which is what search is. GET with body is not forbidden but it’s wrong here and in general. You would use GET possibly if you needed some caching behaviors but what do you vary on if there is a body? – Pawel Zieminski Dec 30 '21 at 22:07
  • "what would be the difference of running a search with" ... the difference is, that the answer may be cached, based on the GET line, independend of the body. Therefore a request with a different body may receive the same (now unfitting) response. – Thomas Schütt Jun 07 '23 at 09:29
3

You can use query parameter in an ElasticSearch GET request: just add source=query_string_body&source_content_type='application/json'

The url will look like the following:

http://localhost:9200/index/_search/?source_content_type=application/json&source={"query":{"match_all":{}}}

ref: https://discuss.elastic.co/t/query-elasticsearch-from-browser-webservice/129697

Paulo Merson
  • 13,270
  • 8
  • 79
  • 72
王信凱
  • 453
  • 3
  • 9