3022

I'm developing a new RESTful webservice for our application.

When doing a GET on certain entities, clients can request the contents of the entity. If they want to add some parameters (for example sorting a list) they can add these parameters in the query string.

Alternatively I want people to be able to specify these parameters in the request body. HTTP/1.1 does not seem to explicitly forbid this. This will allow them to specify more information, might make it easier to specify complex XML requests.

My questions:

  • Is this a good idea altogether?
  • Will HTTP clients have issues with using request bodies within a GET request?

https://www.rfc-editor.org/rfc/rfc2616

Community
  • 1
  • 1
Evert
  • 93,428
  • 18
  • 118
  • 189
  • 612
    The advantage is that allows easily sending XML or JSON request bodies, it doesn't have a length restriction and it's easier to encode (UTF-8). – Evert Jun 10 '09 at 21:51
  • 38
    If what you're after is a safe and idempotent method that allows request bodies, you may want to look at SEARCH, PROPFIND and REPORT. Of course not using GET and having a request body defeats caching more or less. – Julian Reschke Dec 06 '11 at 09:33
  • 3
    Whatever about whether the spec allows it, it goes against the very spirit of REST. – Jon Hanna Aug 17 '12 at 21:38
  • 3
    good luck with clients implementing request methods like SEARCH. You're much more likely to be able to do GET + Body. But Fiddler for one doesn't allow it, though most browser will (or have in the past) – fijiaaron Aug 30 '12 at 21:15
  • 303
    @fijiaaron: It's 3 years later, and since then I've gotten extensive experience writing webservices. It's basically all I have been doing for the last few years. I can safely say, it is indeed a very bad idea to add a body to a GET request. The top two answers stand like a rock. – Evert Aug 31 '12 at 00:34
  • 1
    I agree. It can be done if you control everything from client to server (but then why do you need a webservice). But if that's what someone wants, they can do it, and rather than say something can't be done, we can explain the pitfalls. I've run into similar problems and the best answer I've come up with is to use POST, and just don't tell Roy Fielding because it will make him cry. – fijiaaron Sep 01 '12 at 16:40
  • @fijiaaron: can't speak for him, but I would doubt that he would think pure REST is the be all and end-all. Pick the right tool for the job. He does seem to care a great deal about people mis-using the term REST though. – Evert Sep 01 '12 at 20:24
  • 3
    @Evert: Any chance you could share some details on the challenges you faced with GETs and sending content in the body? I'm writing my first API and I think I'm being lead down to using a GET + body approach. It'd be useful to have some real-world examples of some difficulties that were encountered and potential solutions. – Ellesedil May 01 '14 at 15:13
  • 38
    @Ellesedil: Simply put: Whatever advantages that exist to using GET over POST, exist because of how HTTP is designed. Those advantages no longer exist, when you violate the standard in this way. Therefore there's only one reason left to use GET + a request body instead of POST: Aesthetics. Don't sacrifice robust design over aesthetics. – Evert May 01 '14 at 16:24
  • 2
    This answer sums it up nicely by referring to the HTTP/1.1 spec - http://stackoverflow.com/a/15656853/244128 – maerics Aug 21 '14 at 14:36
  • 21
    To underline what Evert said: "it doesn't have a length restriction". If your GET with query parameters is breaking length restriction (of 2048), then what other choice is there other than to put the query string information in a json object, for example, in the body of the request. – Kieran Ryan May 17 '15 at 15:22
  • 1
    Chiming in, having recently built a Native Http Module in C++ for IIS8, I can say that OnReadEntity doesn't fire on Get Requests, only on posts, or I was having extreme difficulty getting to the body of a Get Request... – Ryan Mann Apr 03 '16 at 21:41
  • 1
    @Evert So in the end what do you end up doing? Encode JSON parameters as Base64? – beldaz Jul 15 '16 at 01:52
  • @JulianReschke Can you provide pointers to SEARCH etc.? They don't appear to be part of HTTP request methods (on wikipedia at least) – beldaz Jul 15 '16 at 02:02
  • 1
    @beldaz Wikipedia is irrelevant; see http://www.iana.org/assignments/http-methods/http-methods.xhtml – Julian Reschke Jul 15 '16 at 09:45
  • 4
    The OP has later expended his thoughts in an interesting [article](https://evertpot.com/dropbox-post-api/) that points to this very question. – Aurelio Jan 16 '19 at 11:52
  • 1
    @beldaz SEARCH is a WebDAV method. See RFC5323: [Web Distributed Authoring and Versioning (WebDAV) SEARCH](https://tools.ietf.org/html/rfc5323) – Suncat2000 Mar 12 '19 at 14:25
  • 9
    With advent of GDPR and what is allowed to be exposed (and thus logged) in the URL query, we had to rewrite our APIs to pass sensitive information in the request body and change GETs into POSTs. So, for example `GET http://host/customer?socialsecuritynumber={ssn}` became `POST http://host/customer/lookup` with the sensitive information sent in the body, which is excluded from external and internal logging – Stanislav Mar 18 '19 at 14:32
  • What is recommended if the request contains complex data? Should you use a POST to request data? – RayLoveless Jul 21 '21 at 15:32
  • Not a word about the security aspects of the url encoding of GET requests... I know of some examples where playing with the parameter string in such a GET "url" opened backdoors to data not meant for the public (CHAOS computer club showcased that). Next to being limited, unwieldy and ugly, it is also more prone for casual hacking. This is why I never understood, why the world prefers using URL encoding over putting query data into the GET body. – BitTickler Nov 18 '21 at 14:22
  • @BitTickler because putting it in the body is not standard. Use POST if you have this requirement. – Evert Nov 18 '21 at 16:23
  • @Evert It looks like a hack and probably was a hack, then proclaimed as a standard. – BitTickler Nov 18 '21 at 21:14
  • @BitTickler Quite the opposite. `GET` has a strong semantic meaning, and it's not 'a read operation'. It was a standard well before you tried to misuse it =). Why do you want to use `GET` ? – Evert Nov 18 '21 at 22:05
  • 2
    @Evert Sorry to disturb your piece of mind. I just don't think Letters, you receive should have written the message on the envelope. And that is what URL encoding does. Its a hack. Someone wanted to cache and use the URL string as a key. Someone wanted to misuse the address field on the letters envelope for the message itself. Ugly hack. – BitTickler Nov 19 '21 at 07:31
  • @BitTickler this is a good point, but also shows a misunderstanding what GET is meant for. You are not sending a letter; it's more like telling the server: 'give me the object with this name'. If you overload this to mean a generic read RPC-call, then _that_ is really the hack. You're not using this as intended. – Evert Nov 19 '21 at 18:10
  • @BitTickler that said, there are real use-cases for wanting a safe, idempotent HTTP request that carries a tons of parameters, and work is being done to define methods for this (`SEARCH` and `QUERY`). – Evert Nov 19 '21 at 18:11
  • It is so sad that something that would benefit extremely from ETag caching by both being likely to be the same response as last time and being a large response body, like a report, has to be something it can't cache. – doug65536 Nov 26 '21 at 21:51
  • 3
    @doug65536 One thing you could do today, is use the (upcoming) `QUERY` http method, require a request header that must be the (sha256?) hash of the request, and then reply with `Vary: Your-Hash-Header`. This ensures that clients that support caching `QUERY` will be storing different cache entries for different bodies. I think there's a standard in the works for body hashes, but can't find it right now. – Evert Nov 26 '21 at 22:35
  • 2
    OP has written a nice followup to this question: https://evertpot.com/get-request-bodies/ – below43 Feb 01 '22 at 00:55
  • In the light of all the information here, my approach will be including information about accepting a body with a `GET` request in my `OPTIONS` responses from the server side and adjust my request accordingly. The server could read this information from a configuration file with all the other information about it's environment or it can periodically send a get request to itself with a body in it. Caching should be solved by keeping a hash in the request uri or in a header. Proxy awareness should be the front end's responsibility. – toraman Mar 28 '22 at 05:49
  • @toraman that's a lot of workarounds just to achieve a non-standard, incorrect and likely still brittle solution. Why not do it right? – Evert Mar 30 '22 at 18:51
  • @Evert is it incorrect though? i don't see the point of adding extra strictness on top of what the specs say. The words `SHOULD`, `SHOULDN'T` etc. are defined, technical terms in these specs, they're not being passive aggressive when they say you `MAY` do something. The specs are clear, you can have a body but nobody has to take it into account. That's exactly what i am trying to comply with here. My reasons include but are not limited to being able to make the distinction between `true` and `"true"` or `false`, `null`, `"false"`, `undefined`, `""`, `{}` and `[]`. – toraman Mar 31 '22 at 10:46
  • @toraman have you read the article I wrote about this? I address it there. It's definitely confusing: https://evertpot.com/get-request-bodies/ . Regardless, why go through this pain when you can just use the `QUERY` method instead. It's perfect for this, and no weird workarounds with `OPTIONS` or risk of intermediates dropping the body. – Evert Mar 31 '22 at 19:42
  • I like your take on what the specs should mean to us, though I think they're doing a good job. `QUERY` is not nearly as widely supported as `GET` with a body. `fetch()` appears to be an exception to this but as far as `fetch()` is concerned a method named `GETBUTWITHABODY` is as valid as `QUERY`. I can't seem to find what browsers will cache a `QUERY` request's response but i don't think many will do. Besides I don't see many back end frameworks supporting it either. I would love to switch to `QUERY` but not yet. My workaround currently seems to be more reliable. – toraman Apr 03 '22 at 14:49
  • Where I take this usage useful is to hide the request params/details. With HTTPS request, body is encrypted. With GET request query params are send clear with the first line like the headers. Even RFC says it SHOULD be ignored, I think it is very useful for sending hidden request params. So, I say YES for your question "Is this a good idea altogether?" – Suphi ÇEVİKER Aug 06 '22 at 16:08
  • @SuphiÇEVİKER use `POST` or `QUERY`, not `GET` bodies. – Evert Aug 06 '22 at 16:38
  • @Evert, yes, as I mentioned on my comment, using HTTP method which allows request bodies. My answer is just for your question, not for the best case. Ofcourse, "you SHOULD" says RFC, and me either. Thanks for your comment. – Suphi ÇEVİKER Nov 19 '22 at 18:44

24 Answers24

2421

Roy Fielding's comment about including a body with a GET request.

Yes. In other words, any HTTP request message is allowed to contain a message body, and thus must parse messages with that in mind. Server semantics for GET, however, are restricted such that a body, if any, has no semantic meaning to the request. The requirements on parsing are separate from the requirements on method semantics.

So, yes, you can send a body with GET, and no, it is never useful to do so.

This is part of the layered design of HTTP/1.1 that will become clear again once the spec is partitioned (work in progress).

....Roy

Yes, you can send a request body with GET but it should not have any meaning. If you give it meaning by parsing it on the server and changing your response based on its contents, then you are ignoring this recommendation in the HTTP/1.1 spec, section 4.3:

...if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request.

And the description of the GET method in the HTTP/1.1 spec, section 9.3:

The GET method means retrieve whatever information ([...]) is identified by the Request-URI.

which states that the request-body is not part of the identification of the resource in a GET request, only the request URI.

Update

The RFC2616 referenced as "HTTP/1.1 spec" is now obsolete. In 2014 it was replaced by RFCs 7230-7237. Quote "the message-body SHOULD be ignored when handling the request" has been deleted. It's now just "Request message framing is independent of method semantics, even if the method doesn't define any use for a message body" The 2nd quote "The GET method means retrieve whatever information ... is identified by the Request-URI" was deleted. - From a comment

From the HTTP 1.1 2014 Spec:

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.

Community
  • 1
  • 1
Paul Morgan
  • 31,226
  • 3
  • 24
  • 27
  • 11
    Which server will ignore it? – fijiaaron Aug 30 '12 at 21:27
  • 1
    Any idea why this is part of the "server semantics for GET"? Is it some cacheing/proxying issue? – Sam Jul 17 '13 at 03:12
  • 108
    Caching / proxying are the two things you're most likely to break, yes. "Semantics" is just another way of saying "the way people who make other components will expect other components to operate". If you violate semantics, you're more likely to see things break in places where people wrote things that expected you to be honoring those semantics. – Stuart P. Bentley Aug 18 '13 at 01:33
  • 10
    It gives a headache when server silently ignores the body or any part of the request. Either it should parse it, or complain about it somehow. – Dmitri Zaitsev May 07 '14 at 07:45
  • Dmitri, I think ignoring it aligns with Jon Postel's advice to "Be liberal in what you accept" (RFC 1122). – Paul Morgan May 08 '14 at 13:21
  • For complicated search, maybe RESTful is not a suitable solution for you. I've tried developing my own protocol using POST requests exclusively. Every request contains one JSON body, with a top level directive in it. I have only one URL which accepts all requests, and then dispatches them to corresponding controllers according to that directive. – Aetherus Mar 17 '15 at 07:12
  • 2
    Aetherus, that can work but now you have routing detail in your body payload. That's a protocol that a client has to understand. IMHO you've complicated the interface for no benefit. – Paul Morgan Mar 17 '15 at 10:05
  • 183
    Elasticsearch is a fairly major product that utilises HTTP request bodies in GET. According to their manual whether a HTTP request should support having a body or not is undefined. I'm personally not comfortable with populating a GET request body, but they seem to have a different opinion and they must know what they're doing. https://www.elastic.co/guide/en/elasticsearch/guide/current/_empty_search.html – GordonM Oct 09 '15 at 16:22
  • 2
    @Sam From the HTTP/1.1 spec: *if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request*. The `GET` method specifies no semantics for request bodies, so servers SHOULD ignore them. – Emil Lundberg Dec 10 '15 at 10:52
  • 37
    @iwein giving GET request bodies meaning is in fact *not* a violation of the spec. [HTTP/1.1](https://tools.ietf.org/html/rfc2616#section-4.3) specifies that servers SHOULD ignore the body, but [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) specifies that implementers are allowed to ignore "SHOULD" clauses if they have good reason to do so. Rather, a client *does* violate the spec if it assumes that changing the GET body will *not* change the response. – Emil Lundberg Dec 10 '15 at 11:03
  • 1
    @EmilLundberg I think I understand your argument and while hard to debunk, it's conclusion contradicts with the given quote by Roy Fielding. I'd suggest an edit that uses 'not following' than 'violating' to avoid this discussion entirely. – iwein Dec 10 '15 at 12:56
  • 144
    The RFC2616 referenced as "HTTP/1.1 spec" is now obsolete. In 2014 it was replaced by RFCs 7230-7237. Quote "_the message-body SHOULD be ignored when handling the request_" has been [deleted](https://tools.ietf.org/html/rfc7230#section-3.3). It's now just "_Request message framing is independent of method semantics, even if the method doesn't define any use for a message body_" The 2nd quote "_The GET method means retrieve whatever information ... is identified by the Request-URI_" was [deleted](https://tools.ietf.org/html/rfc7231#section-4.3.1). So, I suggest to edit the answer @Jarl – Artem Nakonechny Nov 04 '16 at 21:47
  • 4
    @GordonM alas, clearly they don't. This answer is correct, it violates the semantics of the GET request to return a response based on any data in the request body. – Nicholas Shanks Jan 19 '17 at 16:52
  • 46
    I know that it's an old thread - I stumbled upon it. @Artem Nakonechny is technically right but the [new spec](https://tools.ietf.org/html/rfc7231#section-4.3.1) says *"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."* So it's still not a really good idea if can be avoided. – fastcatch Sep 29 '17 at 13:39
  • 3
    Fastcatch is correct, @Artem Nakonechny even when you are technically correct you can read the [RFC7231](https://tools.ietf.org/html/rfc7231#section-4.3.1) saying that: **sending a payload body on a GET request might cause some existing implementations to reject the request** – Luis Armando Mar 23 '18 at 14:47
  • 6
    Let's say you want to get a list of entities in one call. (1,4,21, ... , 100027001). Well the max length of a URL and query string is 2083 characters. You can increase that on your server but clients might enforce it. So how are you supposed to execute your query? Easy, you call GET with the list of Ids in the body: GetByIds(List ids). Also, what if your URL parameter has a query string over-sized for any other reason? You should put the query string in the body of the GET call. If you look at the Odata spec, it can't be fully implemented without a GET with a body. – Rhyous Apr 12 '19 at 15:06
  • 5
    PostMan also recently started allow GET in the body for testing. – Rhyous Apr 12 '19 at 15:09
  • An interesting implication of this: https://blogs.dropbox.com/developers/2015/03/limitations-of-the-get-method-in-http/ – Anamika Modi May 20 '19 at 15:43
  • 8
    @LuisArmando The new RFC means that if you send an HTTP GET with a payload body to an old application, this can refuse your request if it follows the old RFC specifications. But if you are creating a new application and you follow the RFC 7231, the GET method can accept a payload body and this is fine. – Alessandro C Jul 08 '19 at 07:02
  • Anyone knows what CloudFlare does with GET body? – iElectric Aug 15 '19 at 10:15
  • 3
    I am reading these answers because of Elastic Search queries. I guess I am not the only one @GordonM – NewestStackOverflowUser Aug 30 '19 at 07:19
  • 12
    I disagree with `it is never useful to do so`. When I want to `Get` a resource I often need to supply parameters, a lot more then just an Id, so I always create a Request JSON object specific to my needs, and I always end up using `Post` instead of `Get` because of this. So I do a `Post` request to `Get` a resource (I know I know) – Luke T O'Brien Oct 02 '19 at 21:05
  • The alternative to being html liberal is strong contracts and committees which led to the WS standards and OSI stack ..which certainly did not get as the far more liberal http , Rest and tcp .. Data however is different you need to validate strongly when accepting / generating data but once created you need to accept it and best effort to be Robust. – user1496062 Nov 11 '19 at 04:12
  • 2
    So what's the recommendation? Is it within the best practices to pass a body with a get request? – Aditya Patil Mar 23 '20 at 16:46
  • 4
    @AdityaPatil I think the conclusion is that you CAN do it, even if you don't necessarily should. At worst you can just use a post instead. – MasterOfTwo Apr 02 '20 at 14:28
  • 1
    I agree with the comments, but what is the alternative? Use another HTTP instead, even though it's related to getting data from the server? – Lelo Jun 19 '20 at 15:09
  • 3
    I think the alternative is that you should prefer to use GET with uri/query params for retrieval and only use GET with a request body when/if you hit the limitations of doing that. Very rarely have I needed to do so. But even in that case, I would suggest that a GET with a request body is better than POST for retrieval. At least the GET accurately identifies the purpose of the request. – c.dunlap Oct 07 '20 at 13:32
  • 2
    `even though it's related to getting data from the server?` - The semantic purpose of GET is not an arbitrary read-only operation. It's getting a representation of the resource identified by the URI. If you need a body for a read operation, it just doesn't fit GET request semantics, because you are no longer just fetching the representation of the URI. You might like the up and coming `SEARCH` method though. – Evert Dec 10 '20 at 17:42
  • @Evert as mentionned by artem-nakonechny in a previous comment, GET isn't about "retrieve whatever information ... is identified by the Request-URI" anymore, it's been deleted (https://tools.ietf.org/html/rfc7231#section-4.3.1). – ymajoros Sep 29 '21 at 08:11
  • 1
    What is the answer? The body is not recommended for a GET request? – Pingpong Oct 19 '21 at 14:27
  • 3
    `and no, it is never useful to do so.` This is just wrong. Like, really really wrong. Not all get request parameters can even fit in a the maximum size of a url. In these cases, you need a body. There are cases when a get request can pass an arbitrary length parameter. Really frustrating to see this as a top answer – ICW Feb 17 '22 at 16:02
  • 3
    This is an example of a spec telling you not to do something, yet not providing a realistic alternative. There may be use cases that require complex payloads to be requested (e.g. a list of attributes to return) that would be unwieldy to fit in the URL. The only recourse is to put such data in the request body. – Darren Apr 22 '22 at 17:26
  • 1
    I am using Body in Get request on software & mobile aplications since a decade and everything is good! Just browsers have this issue.. Waiting for the upcoming HTTP QUERY Method IETF https://datatracker.ietf.org/doc/draft-ietf-httpbis-safe-method-w-body – G Clovs Jul 23 '22 at 13:43
  • 1
    Where I take this usage useful is to hide the request params/details. With HTTPS request, body is encrypted. With GET request query params are send clear with the first line like the headers. Even RFC says it SHOULD be ignored, I think it is very useful for sending hidden request params. – Suphi ÇEVİKER Aug 06 '22 at 16:07
374

While you can do that, insofar as it isn't explicitly precluded by the HTTP specification, I would suggest avoiding it simply because people don't expect things to work that way. There are many phases in an HTTP request chain and while they "mostly" conform to the HTTP spec, the only thing you're assured is that they will behave as traditionally used by web browsers. (I'm thinking of things like transparent proxies, accelerators, A/V toolkits, etc.)

This is the spirit behind the Robustness Principle roughly "be liberal in what you accept, and conservative in what you send", you don't want to push the boundaries of a specification without good reason.

However, if you have a good reason, go for it.

caskey
  • 12,305
  • 2
  • 26
  • 27
  • 278
    The Robustness Principle is flawed. If you are liberal in what you accept, you will get crap, if you have any success in terms of adoption, just because you accept crap. That will make it harder for you to evolve your interface. Just look at HTML. That's the reboustness principle in action. – Evgeniy Berezovsky Aug 09 '11 at 01:43
  • 37
    I think the success and breadth of adoption (and abuse) of the protocols speaks to the value of the robustness principle. – caskey Aug 15 '11 at 03:46
  • 51
    Have you ever tried parsing real HTML? It's not feasible to implement it yourself, that's why almost everyone - including the really big players like Google (Chrome) and Apple (Safari), did not do it but relied on existing implementations (in the end they all relied on KDE's KHTML). That reuse is of course nice, but have you tried displaying html in a .net application? It's a nightmare, as you either have to embed an - unmanaged - IE (or similar) component, with its issues and crashes, or you use the available (on codeplex) managed component that doesn't even allow you to select text. – Evgeniy Berezovsky Sep 02 '11 at 14:10
  • 1
    The HTTP spec only 'allows' this insofar as it is not explicitly forbidden and any intermediate servers (e.g. proxies) are expected to retain message-body parts in requests they are forwarding. That said, it's still not something people would expect. PUT and POST exist to provide the correct semantic commands for those cases. – caskey Jan 26 '13 at 01:36
  • 2
    @AbhijeetPatel AJAX requests don't send body data along with a GET request, because the [W3C XMLHttpRequest specification](http://www.w3.org/TR/XMLHttpRequest/#the-send()-method) doesn't allow it (which is no explicit contradiction to the HTTP specification). – Torben Jun 27 '13 at 13:19
  • 13
    Not only does the HTTP spec allow body data with GET request, but this is also common practice: The popular ElasticSearch engine's _search API recommends GET requests with the query attached in a JSON body. As a concession to incomplete HTTP client implementations, it also allows POST requests here. – Christian Pietsch Oct 25 '13 at 11:52
  • 8
    @ChristianPietsch, it is common practice today. Four years ago it was not. While the spec explicitly allows a client to optionally include (MAY) an entity in a request (section 7), the meaning of MAY is defined in RFC2119 and a (crappy) proxy server could be spec compliant while stripping off entities in GET requests, specifically as long as it doesn't crash, it can provide 'reduced functionality' by forwarding the request headers and not the included entity. Likewise there are a host of rules about what version changes MUST/MAY/SHOULD be made when proxying among different protocol levels. – caskey Oct 28 '13 at 21:49
  • 2
    @user437899 The .NET Framework will throw an exception if you attempt to send a body with a GET request. – Sam Harwell Jan 23 '14 at 15:32
  • 4
    One could then argue that the .NET Framework implementation is incorrect. – floum Jul 20 '18 at 15:10
  • I am using Body in Get request on software & mobile aplications since a decade now and everything is good! Just browsers have still this issue.. internet explorer is gone guys!.. we need to move on XD – G Clovs Jul 23 '22 at 13:01
242

You will likely encounter problems if you ever try to take advantage of caching. Proxies are not going to look in the GET body to see if the parameters have an impact on the response.

Naman
  • 27,789
  • 26
  • 218
  • 353
Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
  • 15
    Using ETag/Last-Modified header fields help in this way: when a "conditional GET" is used, the proxies/caches can act on this information. – jldupont Jan 15 '10 at 11:42
  • 5
    @jldupont Caches use the presence of validators to know whether a stale response can be re-validated, however, they are not used as part of the primary or secondary cache key. – Darrel Miller Mar 26 '14 at 14:42
  • 15
    You could fix that with a checksum of the body in a query parameter – Adrian May Jan 03 '20 at 14:33
  • 1
    For caching just add hash of body to url! :) – hex Feb 11 '22 at 15:51
94

Elasticsearch accepts GET requests with a body. It even seems that this is the preferred way: Elasticsearch guide

Some client libraries (like the Ruby driver) can log the cry command to stdout in development mode and it is using this syntax extensively.

Rodrigo García
  • 1,357
  • 15
  • 26
jlecour
  • 2,905
  • 1
  • 25
  • 24
  • 6
    Was wondering why Elasticsearch allows this. That means this query to count all documents with payload to a GET request `curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }'` is equivalent to including the payload as `source` param: `curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'` – arun Dec 11 '14 at 14:31
  • 61
    Complex queries can hit the http header max length. – s.Daniel Jan 07 '15 at 17:45
  • 12
    It was reading the elasticsearch documentation that took me to this question as I thought it was considered bad practice to include a body – PatrickWalker Jan 19 '16 at 13:59
  • 1
    It doesn't even need to be a complex query. Even a simple scroll can return a very long scroll_id(in a cluster with many shards), which will lead to overrunning the maximum url length if added there. – Brent Hronik Jul 27 '16 at 19:49
  • 30
    Elasticsearch supports the same request using POST. They only chose to allow a body in a GET because they felt a GET is more semantically correct than a POST when it comes to querying data. Its funny that Elasticsearch is mentioned so much in this thread. I would not use one example (albeit from a popular product) as a reason to follow the practice. – dso Jul 01 '17 at 20:11
  • @DSO I feel like their arguement is correct, it is a search and GET, it happened to have a lot of parameters that it cant fit in the URL. In my mind, caching implementations should consider the body also. I always felt the encoding of params in URL for a get request is cumbersome and just passing the body would have nicer always. But then there is the issue that you cant use browser to modify such requests in the URL bar – rubyprince Aug 11 '22 at 19:59
91

Neither restclient nor REST console support this but curl does.

The HTTP specification says in section 4.3

A message-body MUST NOT be included in a request if the specification of the request method (section 5.1.1) does not allow sending an entity-body in requests.

Section 5.1.1 redirects us to section 9.x for the various methods. None of them explicitly prohibit the inclusion of a message body. However...

Section 5.2 says

The exact resource identified by an Internet request is determined by examining both the Request-URI and the Host header field.

and Section 9.3 says

The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.

Which together suggest that when processing a GET request, a server is not required to examine anything other that the Request-URI and Host header field.

In summary, the HTTP spec doesn't prevent you from sending a message-body with GET but there is sufficient ambiguity that it wouldn't surprise me if it was not supported by all servers.

Dave Durbin
  • 3,562
  • 23
  • 33
  • 2
    Paw also has the option to support GET requests with bodies but it must be enabled in the settings. – s.Daniel Jan 07 '15 at 18:14
  • "The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI." Then, is it technically illegal/wrong to have a GET endpoint that gets all entities? E.g. `GET /contacts/100/addresses` returns a collection of addresses for the person with `id=100`. – Josh M. Jul 07 '16 at 19:21
  • 1
    The rest-assured Java library for testing REST APIs does not support GET request with a body. Apache HttpClient doesn't support it either. – Paulo Merson Sep 05 '16 at 18:33
  • Django also supports parsing a GET body – Bruno Finger Mar 21 '19 at 12:13
  • jmeter also does. – Mahesh C. Regmi Jun 17 '21 at 12:06
  • @JoshM. I think in HTTP spec language an address is an entity and a list of addresses is an entity too. – Eneko Jan 21 '22 at 11:27
80

GET, with a body!?

Specification-wise you could, but, it's not a good idea to do so injudiciously, as we shall see.

RFC 7231 §4.3.1 states that a body "has no defined semantics", but that's not to say it is forbidden. If you attach a body to the request and what your server/app makes out of it is up to you. The RFC goes on to state that GET can be "a programmatic view on various database records". Obviously such view is many times tailored by a large number of input parameters, which are not always convenient or even safe to put in the query component of the request-target.

The good: I like the verbiage. It's clear that one read/get a resource without any observable side-effects on the server (the method is "safe"), and, the request can be repeated with the same intended effect regardless of the outcome of the first request (the method is "idempotent").

The bad: An early draft of HTTP/1.1 forbade GET to have a body, and - allegedly - some implementations will even up until today drop the body, ignore the body or reject the message. For example, a dumb HTTP cache may construct a cache key out of the request-target only, being oblivious to the presence or content of a body. An even dumber server could be so ignorant that it treats the body as a new request, which effectively is called "request smuggling" (which is the act of sending "a request to one device without the other device being aware of it" - source).

Due to what I believe is primarily a concern with inoperability amongst implementations, work in progress suggests to categorize a GET body as a "SHOULD NOT", "unless [the request] is made directly to an origin server that has previously indicated, in or out of band, that such a request has a purpose and will be adequately supported" (emphasis mine).

The fix: There's a few hacks that can be employed for some of the problems with this approach. For example, body-unaware caches can indirectly become body-aware simply by appending a hash derived from the body to the query component, or disable caching altogether by responding a cache-control: no-cache header from the server.

Alas when it comes to the request chain, one is often not in control of- or even aware, of all present and future HTTP intermediaries and how they will deal with a GET body. That's why this approach must be considered generally unreliable.

But POST, is not idempotent!

POST is an alternative. The POST request usually includes a message body (just for the record, body is not a requirement, see RFC 7230 §3.3.2). The very first use case example from RFC 7231 (§4.3.3) is "providing a block of data [...] to a data-handling process". So just like GET with a body, what happens with the body on the back-end side is up to you.

The good: Perhaps a more common method to apply when one wish to send a request body, for whatever purpose, and so, will likely yield the least amount of noise from your team members (some may still falsely believe that POST must create a resource).

Also, what we often pass parameters to is a search function operating upon constantly evolving data, and a POST response is only cacheable if explicit freshness information is provided in the response.

The bad: POST requests are not defined as idempotent, leading to request retry hesitancy. For example, on page reload, browsers are unwilling to resubmit an HTML form without prompting the user with a nonreadable cryptic message.

The fix: Well, just because POST is not defined to be idempotent doesn't mean it mustn't be. Indeed, RFC 7230 §6.3.1 writes: "a user agent that knows (through design or configuration) that a POST request to a given resource is safe can repeat that request automatically". So, unless your client is an HTML form, this is probably not a real problem.

QUERY is the holy grail

There's a proposal for a new method QUERY which does define semantics for a message body and defines the method as idempotent. See this.

Edit: As a side-note, I stumbled into this StackOverflow question after having discovered a codebase where they solely used PUT requests for server-side search functions. This were their idea to include a body with parameters and also be idempotent. Alas the problem with PUT is that the request body has very precise semantics. Specifically, the PUT "requests that the state of the target resource be created or replaced with the state [in the body]" (RFC 7231 §4.3.4). Clearly, this excludes PUT as a viable option.

JohnLBevan
  • 22,735
  • 13
  • 96
  • 178
Martin Andersson
  • 18,072
  • 9
  • 87
  • 115
  • 1
    GET bodies will is upgraded to a 'SHOULD NOT' in the next revision of the HTTP spec. No defined semantics does not mean 'you can decide what the semantics' are, it means in this case: 'it shouldn't alter the semantics of the request'. It's not on you that this is confusing, I think it was poorly written in the spec. The intent was that the presence of a body should not break implementations, nothing more. – Evert Nov 29 '21 at 19:21
  • Note that the 'no defined semantics' line is only mentioned for `GET`, not methods like `POST` where it's widely accepted that how the server interprets the body is up to the server. Everything about `POST` and `QUERY` is right though! – Evert Nov 29 '21 at 19:22
  • 1
    I do not believe you or me can make any authoritative claims what "no defined semantics" mean. We can only take the specification at face value, and the spec could not give a well-defined meaning to the GET body, but was also smart enough to not forbid the body just because this limited set of authors at that time and place couldn't anticipate a use case. As I am sure both of us can agree to by now the practice does have at least one use case - thank you HTTP guys! – Martin Andersson Nov 30 '21 at 10:33
  • Unless something is outright forbidden in the spec, well, then it isn't. Compare a GET body with some of my other remarks. Just because the POST request is defined as not idempotent, it doesn't have to be not idempotent. It only means that clients can not make that assumption. Just because POST usually creates a resource, it doesn't have to. POST usually has a body, it doesn't have to. I do not believe being religious is a good thing. For example, I don't think we would be having this discussion right now if many HTTP implementations out there wasn't being stupid about the GET body. – Martin Andersson Nov 30 '21 at 10:37
  • I do agree that we should never change semantics! And, moving parameters from the query string to the body doesn't change the GET semantics, it's just a detail. So my expression was clumsy, I thank you for pointing that out. I made an edit. See if you're okay with the new version =) – Martin Andersson Nov 30 '21 at 10:37
  • I googled [RFC 7540](https://datatracker.ietf.org/doc/html/rfc7540), can't find that a GET "SHOULD NOT" include a body. Can you provide a reference please? – Martin Andersson Nov 30 '21 at 10:38
  • 2
    "legacy software written hundreds of years ago may drop the body or otherwise ignore it" — AFAIK this includes **every current browser**. – Quentin Nov 30 '21 at 10:55
  • 1
    "Can you provide a reference please?" - https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#rfc.section.9.3.1.p.6 – Quentin Nov 30 '21 at 10:58
  • Okay, super! Thank you for the link. I incorporated the revision into my answer which I updated quite extensively to be honest. I hope I made it clear that "generally" the GET-with-body solution, although legit as far as the specification is concerned, is still not the best alternative. I am very happy for both of your feedback! Please do let me know if I can improve the answer even more =) – Martin Andersson Nov 30 '21 at 16:41
  • @MartinAndersson I wrote more about this issue here: https://evertpot.com/get-request-bodies/, hopefully better explaining too why GET should never have a body. – Evert Feb 01 '22 at 17:34
  • 1
    Thank you Evert! I read the article, very well written, and humorous! I don't think many people would disagree with you regarding why one should *not* include a GET body. But I still can not agree with statements like "body is obviously not allowed". Because it is obviously allowed lol. The quote you used yourself is spot on: "A client SHOULD NOT generate content in a GET request unless it is made directly to an origin server that has previously indicated, in or out of band, that such a request has a purpose and will be adequately supported". – Martin Andersson Feb 02 '22 at 11:14
  • "a user agent that knows (through design or configuration) that a POST request to a given resource is safe can repeat that request automatically" An issue with that is, a centralized retry mechanism (in a load balancer for example) would need a list of idempotent POST's. A simple rule that all GETs are retryable is much more practical. – Bampfer Nov 09 '22 at 16:18
  • #1 Having a middleman do POST retries sounds complex and unmaintainable. Keen to hear why anyone would ever want to do such a thing. #2 GET is idempotent, thus, "retryable". This is not a "rule" per se; it's specified as such. – Martin Andersson Dec 02 '22 at 19:36
42

You can either send a GET with a body or send a POST and give up RESTish religiosity (it's not so bad, 5 years ago there was only one member of that faith -- his comments linked above).

Neither are great decisions, but sending a GET body may prevent problems for some clients -- and some servers.

Doing a POST might have obstacles with some RESTish frameworks.

Julian Reschke suggested above using a non-standard HTTP header like "SEARCH" which could be an elegant solution, except that it's even less likely to be supported.

It might be most productive to list clients that can and cannot do each of the above.

Clients that cannot send a GET with body (that I know of):

  • XmlHTTPRequest Fiddler

Clients that can send a GET with body:

  • most browsers

Servers & libraries that can retrieve a body from GET:

  • Apache
  • PHP

Servers (and proxies) that strip a body from GET:

  • ?
fijiaaron
  • 5,015
  • 3
  • 35
  • 28
  • 4
    Squid 3.1.6 also strips GET bodies when Content-Length is 0 or not set, and otherwise sends back a HTTP 411 Length Required even though length is set – rkok Mar 06 '14 at 09:14
  • 4
    Fiddler will, but it warns you. – toddmo Aug 05 '15 at 21:44
  • Are you saying that a `SEARCH` method would possibly break along the way? If proxies don't understand a method, they are expected to pass it through as is, so I'm not too sure why you think it would break anything... – Alexis Wilke Dec 07 '18 at 20:03
  • @fijiaaron would love to see this list updated. I'm trying to find a library in nodeJS that allows this, so far none. – tinker Jan 26 '21 at 04:59
  • @tinker Try fastify – SILENT Oct 18 '21 at 23:08
  • _"most browsers"_... in testing, no modern browser allows sending a GET request body. `XMLHttpRequest` ignores it and `fetch()` will throw an error at you – Phil Jun 09 '22 at 08:53
  • This is ancient so I don't know why I'm commenting, but just so we're clear... Amazon API Gateway doesn't just hate GET with a body, it violently objects to any attempt to do so. – John O Jan 23 '23 at 21:28
41

What you're trying to achieve has been done for a long time with a much more common method, and one that doesn't rely on using a payload with GET.

You can simply build your specific search mediatype, or if you want to be more RESTful, use something like OpenSearch, and POST the request to the URI the server instructed, say /search. The server can then generate the search result or build the final URI and redirect using a 303.

This has the advantage of following the traditional PRG method, helps cache intermediaries cache the results, etc.

That said, URIs are encoded anyway for anything that is not ASCII, and so are application/x-www-form-urlencoded and multipart/form-data. I'd recommend using this rather than creating yet another custom json format if your intention is to support ReSTful scenarios.

dat
  • 1,580
  • 1
  • 21
  • 30
SerialSeb
  • 6,701
  • 24
  • 28
  • 5
    *You can simply build your specific search mediatype* Could you elaborate? – Piotr Dobrogost Sep 28 '11 at 19:45
  • 3
    By that I was saying that you could create a media type called application/vnd.myCompany.search+json which would contain the kind of search template you want a client to issue, and the client could then send that as a POST. As I've highlighted, there's already a media type for that and it's called OpenSearch, reusing an existing media type should be chosen over the custom route when you can implement your scenario with existing standards. – SerialSeb Oct 03 '11 at 11:47
  • 18
    That's clever, but overly complex, and inefficient. Now you have to send a POST with your search criteria, get a URI as a response back from your POST, then send a GET with the search criteria URI to the server for it to the GET the criteria and send the result back to you. (Except that including a URI in a URI is technically impossible because you can't send something that can be up to 255 characters within something that can be no more than 255 characters -- so you have to use a partial identifer and your server then needs to know how to resolve the URI for your POSTed search criteria.) – fijiaaron Aug 30 '12 at 21:26
35

I put this question to the IETF HTTP WG. The comment from Roy Fielding (author of http/1.1 document in 1998) was that

"... an implementation would be broken to do anything other than to parse and discard that body if received"

RFC 7231 (HTTPbis) states:

"A payload within a GET request message has no defined semantics;"

It seems clear now that the intention was that semantic meaning on GET request bodies is prohibited, which means that the request body can't be used to affect the result.

There are proxies out there that will definitely break your request in various ways if you include a body on GET.

So in summary, don't do it.

Martin
  • 2,573
  • 28
  • 22
Adrien
  • 1,061
  • 8
  • 11
  • For a documented REST API, you may very well know that there are no proxies in between the client and server, and sending a JSON body may be a clearer API than encoding the same details in a query string. – Mark Stosberg May 27 '22 at 15:12
25

From RFC 2616, section 4.3, "Message Body":

A server SHOULD read and forward a message-body on any request; if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request.

That is, servers should always read any provided request body from the network (check Content-Length or read a chunked body, etc). Also, proxies should forward any such request body they receive. Then, if the RFC defines semantics for the body for the given method, the server can actually use the request body in generating a response. However, if the RFC does not define semantics for the body, then the server should ignore it.

This is in line with the quote from Fielding above.

Section 9.3, "GET", describes the semantics of the GET method, and doesn't mention request bodies. Therefore, a server should ignore any request body it receives on a GET request.

Community
  • 1
  • 1
izrik
  • 918
  • 2
  • 9
  • 20
  • [Section 9.5](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5), "POST", also doesn't mention request bodies, so this logic is flawed. – CarLuva Jun 20 '14 at 13:40
  • 10
    @CarLuva The POST section says "The POST method is used to request that the origin server accept the entity enclosed..." The [entity body](http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2) section says "The entity-body is obtained from the message-body..." Therefore, the POST section does mention message body, although indirectly by referencing the entity body which is carried by the message body of the POST request. – frederickf Aug 08 '14 at 23:14
20

Which server will ignore it? – fijiaaron Aug 30 '12 at 21:27

Google for instance is doing worse than ignoring it, it will consider it an error!

Try it yourself with a simple netcat:

$ netcat www.google.com 80
GET / HTTP/1.1
Host: www.google.com
Content-length: 6

1234

(the 1234 content is followed by CR-LF, so that is a total of 6 bytes)

and you will get:

HTTP/1.1 400 Bad Request
Server: GFE/2.0
(....)
Error 400 (Bad Request)
400. That’s an error.
Your client has issued a malformed or illegal request. That’s all we know.

You do also get 400 Bad Request from Bing, Apple, etc... which are served by AkamaiGhost.

So I wouldn't advise using GET requests with a body entity.

user941239
  • 865
  • 8
  • 5
  • 90
    This example is pointless because usually when people are going to add body to `GET` requests, it's because their own custom server are able to handle it. The question thus is whether the other "moving parts" (browsers, caches, etc) will work properly. – Pacerier Apr 19 '16 at 01:56
  • 14
    This is a bad requests because your payload isn't expected (or sensible) for a `GET` *on that particular endpoint* -- it has nothing to do with the use of `GET` in the general case. A random payload could break a `POST` just as easily, and return the same `400 Bad Request`, if the contents were not in a format that made sense in the context of the specific request. – Brent Bradburn Sep 22 '18 at 16:13
  • And not just *on that endpoint* as a whole, but rather *on that specific URL*. – Lawrence Dol Feb 05 '19 at 21:42
  • 4
    This is irrelevant because it's just Google's server implementation at that URL. So it makes no sense to the question – Joel Duckworth Apr 22 '19 at 23:21
  • for me it was useful, as i was trying to use firebase functions with a get request + body, and this error can be very cryptic and hard to understand. – scrimau Nov 05 '19 at 09:40
  • 1
    @Pacerier this might have been mostly true 4 years ago. Now that Google Cloud is more of a thing, more people are likely to run into Google's conventions. I deployed a "server of my own" to accept a GET request body. Deployed the containerized server through Google Cloud's Run service and the service returns a 400 for requests with a body even though the container returns a useful response when deployed locally. – chishaku Jul 09 '20 at 08:19
  • Google Cloud HTTPS Loadbalancer will return the request. So if you deploy your own software in GCP and expose it using Google HTTPS Loadbalancer you will run in HTTP GET with body return 400. – Eugene S. Jun 04 '21 at 14:32
  • Some versions of WinGate I know would treat it as an error. I don't know about other proxies or proxy appliances. There are a lot of them. – Adrien Dec 05 '21 at 02:36
15

According to XMLHttpRequest, it's not valid. From the standard:

4.5.6 The send() method

client . send([body = null])

Initiates the request. The optional argument provides the request body. The argument is ignored if request method is GET or HEAD.

Throws an InvalidStateError exception if either state is not opened or the send() flag is set.

The send(body) method must run these steps:

  1. If state is not opened, throw an InvalidStateError exception.
  2. If the send() flag is set, throw an InvalidStateError exception.
  3. If the request method is GET or HEAD, set body to null.
  4. If body is null, go to the next step.

Although, I don't think it should because GET request might need big body content.

So, if you rely on XMLHttpRequest of a browser, it's likely it won't work.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
Rafael Sales
  • 326
  • 5
  • 8
  • 1
    downvoted due to the fact that XMLHttpRequest is an implementation. It might not reflect the actual specification it is supposed to implement. – floum Jul 20 '18 at 15:01
  • 20
    Downvote above is wrong, if some implementations don't support sending a body with a GET, then that may be a reason not to do it, irrespective of the specification. I actually ran into this exact problem in a cross-platform product I'm working on - only the platform using XMLHttpRequest failed to send the get. – pjcard Oct 10 '18 at 10:29
11

If you really want to send cachable JSON/XML body to web application the only reasonable place to put your data is query string encoded with RFC4648: Base 64 Encoding with URL and Filename Safe Alphabet. Of course you could just urlencode JSON and put is in URL param's value, but Base64 gives smaller result. Keep in mind that there are URL size restrictions, see What is the maximum length of a URL in different browsers? .

You may think that Base64's padding = character may be bad for URL's param value, however it seems not - see this discussion: http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html . However you shouldn't put encoded data without param name because encoded string with padding will be interpreted as param key with empty value. I would use something like ?_b64=<encodeddata>.

Community
  • 1
  • 1
gertas
  • 16,869
  • 1
  • 76
  • 58
  • I think this is a pretty bad idea :) But if I were to do something like this, I would instead use a custom HTTP header (and make sure that I always send back Vary: in the response). – Evert Feb 18 '13 at 16:25
  • Bad or not but doable :) With data in header there is similar problem with data size, see http://stackoverflow.com/questions/686217/maximum-on-http-header-values . However thanks for mentioning `Vary` header, I wasn't aware of it's real potential. – gertas Feb 18 '13 at 21:36
9

You have a list of options which are far better than using a request body with GET.

Let' assume you have categories and items for each category. Both to be identified by an id ("catid" / "itemid" for the sake of this example). You want to sort according to another parameter "sortby" in a specific "order". You want to pass parameters for "sortby" and "order":

You can:

  1. Use query strings, e.g. example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
  2. Use mod_rewrite (or similar) for paths: example.com/category/{catid}/item/{itemid}/{sortby}/{order}
  3. Use individual HTTP headers you pass with the request
  4. Use a different method, e.g. POST, to retrieve a resource.

All have their downsides, but are far better than using a GET with a body.

Xenonite
  • 1,823
  • 4
  • 26
  • 39
9

I wouldn't advise this, it goes against standard practices, and doesn't offer that much in return. You want to keep the body for content, not options.

cloudhead
  • 15,253
  • 6
  • 42
  • 37
5

I'm upset that REST as protocol doesn't support OOP and Get method is proof. As a solution, you can serialize your a DTO to JSON and then create a query string. On server side you'll able to deserialize the query string to the DTO.

Take a look on:

Message based approach can help you to solve Get method restriction. You'll able to send any DTO as with request body

Nelibur web service framework provides functionality which you can use

var client = new JsonServiceClient(Settings.Default.ServiceAddress);
var request = new GetClientRequest
    {
        Id = new Guid("2217239b0e-b35b-4d32-95c7-5db43e2bd573")
    };
var response = client.Get<GetClientRequest, ClientResponse>(request);

as you can see, the GetClientRequest was encoded to the following query string

http://localhost/clients/GetWithResponse?type=GetClientRequest&data=%7B%22Id%22:%2217239b0e-b35b-4d32-95c7-5db43e2bd573%22%7D
nomail
  • 635
  • 6
  • 21
GSerjo
  • 4,725
  • 1
  • 36
  • 55
  • 11
    You should just use POST. If there is a method name in the url, you are violating the fundamental rest design. This is RPC, use POST. – Evert Feb 10 '14 at 15:40
  • 3
    I don't think that is a big deal, we have more problems during development with RESTful url (i.e. orders/1). As for me, something wrong with Get method, it's incompatible with OOP. And who care how url is look like :) But with message based approach we can create stable remote interface and it's really important. P.S. it's not RPC, it's message based – GSerjo Feb 10 '14 at 17:41
  • 6
    I think you're missing the whole point of REST. When you say, who cares what the url looks like, well REST cares, a lot. And why would REST be compatible with OOP? – shmish111 Dec 18 '15 at 13:53
  • I don't see how REST could support or not support OOP. – toraman Mar 28 '22 at 05:27
5

What about nonconforming base64 encoded headers? "SOMETHINGAPP-PARAMS:sdfSD45fdg45/aS"

Length restrictions hm. Can't you make your POST handling distinguish between the meanings? If you want simple parameters like sorting, I don't see why this would be a problem. I guess it's certainty you're worried about.

chaz
  • 568
  • 1
  • 8
  • 22
  • You can send any parameters you want with the `x-` prefix, any limits on the length of headers would entirely be a server arbitrary limit. – Chris Marisic Jun 02 '15 at 21:15
5

Even if a popular tool use this, as cited frequently on this page, I think it is still quite a bad idea, being too exotic, despite not forbidden by the spec.

Many intermediate infrastructures may just reject such requests.

By example, forget about using some of the available CDN in front of your web site, like this one:

If a viewer GET request includes a body, CloudFront returns an HTTP status code 403 (Forbidden) to the viewer.

And yes, your client libraries may also not support emitting such requests, as reported in this comment.

Frédéric
  • 9,364
  • 3
  • 62
  • 112
4

IMHO you could just send the JSON encoded (ie. encodeURIComponent) in the URL, this way you do not violate the HTTP specs and get your JSON to the server.

Jon49
  • 4,444
  • 4
  • 36
  • 73
EthraZa
  • 388
  • 5
  • 9
4

For example, it works with Curl, Apache and PHP.

PHP file:

<?php
echo $_SERVER['REQUEST_METHOD'] . PHP_EOL;
echo file_get_contents('php://input') . PHP_EOL;

Console command:

$ curl -X GET -H "Content-Type: application/json" -d '{"the": "body"}' 'http://localhost/test/get.php'

Output:

GET
{"the": "body"}
Nick
  • 9,735
  • 7
  • 59
  • 89
  • Fun experiment! PHP will only read in `$_POST` when the body is sent with a POST request and `application/x-www-form-urlencoded`. That means the body is ignored in a `GET` request. In this case: `$_GET` and `$_POST` are very misleading anyway at this point. So better use `php://input` – Martin Muzatko Dec 13 '18 at 14:49
4

If you want to allow a GET request with a body, a way is to support POST request with header "X-HTTP-Method-Override: GET". It is described here : https://en.wikipedia.org/wiki/List_of_HTTP_header_fields. This header means that while the method is POST, the request should be treated as if it is a GET. Body is allowed for POST, so you're sure nobody willl drop the payload of your GET requests.

This header is oftenly used to make PATCH or HEAD requests through some proxies that do not recognize those methods and replace them by GET (always fun to debug!).

Christophe Quintard
  • 1,858
  • 1
  • 22
  • 30
0

An idea on an old question:

Add the full content on the body, and a short hash of the body on the querystring, so caching won't be a problem (the hash will change if body content is changed) and you'll be able to send tons of data when needed :)

Daniel
  • 1,287
  • 12
  • 12
  • Not really, there is a limitation on query string size in most of the clients and servers. – bongo Jun 24 '22 at 13:14
  • I meant a short hash on the querystring, and then the tons of data on the request body. So if the body data changes, the short hash on the querystring changes too and invalidates caches. – Daniel Aug 24 '22 at 11:11
0

Sending data in the request body of GET API is not recommended by HTTP specification but there might be scenarios where using POST, PUT, or PATCH APIs are not suitable to use.

For instance, Elasticsearch sends a request body with GET API as the payload it is sent in the request body is quite complex and is not appropriate to send by query params in GET API.

But in most cases, we shouldn't send data in the request body with GET API as it is expected that there will be no request body in GET API and might be ignored by the API handling client.

  • The fact that ElasticSearch does this doesn't mean anyone else should. It's still a bad idea. – Evert Jul 19 '23 at 15:54
  • Totally agrees with you. I am also of the opinion to not send the request body in GET API. That's what I have written in my answer. I just have explained that we can send (Just like Elasticsearch is using) but we shouldn't send the request body in GET API (As per HTTP specifications). – Prabhsharan Sandhu Jul 21 '23 at 05:01
-6

Create a Requestfactory class

import java.net.URI;

import javax.annotation.PostConstruct;

import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
public class RequestFactory {
    private RestTemplate restTemplate = new RestTemplate();

    @PostConstruct
    public void init() {
        this.restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestWithBodyFactory());
    }

    private static final class HttpComponentsClientHttpRequestWithBodyFactory extends HttpComponentsClientHttpRequestFactory {
        @Override
        protected HttpUriRequest createHttpUriRequest(HttpMethod httpMethod, URI uri) {
            if (httpMethod == HttpMethod.GET) {
                return new HttpGetRequestWithEntity(uri);
            }
            return super.createHttpUriRequest(httpMethod, uri);
        }
    }

    private static final class HttpGetRequestWithEntity extends HttpEntityEnclosingRequestBase {
        public HttpGetRequestWithEntity(final URI uri) {
            super.setURI(uri);
        }

        @Override
        public String getMethod() {
            return HttpMethod.GET.name();
        }
    }

    public RestTemplate getRestTemplate() {
        return restTemplate;
    }
}

and @Autowired where ever you require and use, Here is one sample code GET request with RequestBody

 @RestController
 @RequestMapping("/v1/API")
public class APIServiceController {
    
    @Autowired
    private RequestFactory requestFactory;
    

    @RequestMapping(method = RequestMethod.GET, path = "/getData")
    public ResponseEntity<APIResponse> getLicenses(@RequestBody APIRequest2 APIRequest){
        APIResponse response = new APIResponse();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        Gson gson = new Gson();
        try {
            StringBuilder createPartUrl = new StringBuilder(PART_URL).append(PART_URL2);
            
            HttpEntity<String> entity = new HttpEntity<String>(gson.toJson(APIRequest),headers);
            ResponseEntity<APIResponse> storeViewResponse = requestFactory.getRestTemplate().exchange(createPartUrl.toString(), HttpMethod.GET, entity, APIResponse.class); //.getForObject(createLicenseUrl.toString(), APIResponse.class, entity);
    
            if(storeViewResponse.hasBody()) {
                response = storeViewResponse.getBody();
            }
            return new ResponseEntity<APIResponse>(response, HttpStatus.OK);
        }catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<APIResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
        }
        
    }
}
Bhaskara Arani
  • 1,556
  • 1
  • 26
  • 44