Nothing in the existing spec prevents GET from having a body, though there isn't currently a semantic meaning to it.
This would fit perfectly, be more compatible and result in a simpler spec and protocol.
So much so that I added support for it to my own server and client libraries. Which means that adding support for QUERY will be trivial (yay!)
As an aside, I also support DELETE with a body.
If the params for the search are so many or so big that they don't fit in a single url, how could you use that as a cache key?
Right now you can:
* Pass the arguments as parameters
* Pass them on the request body. I personally done it on apis for games in unity/ios/android for almost a decade). Other products like Elasticsearch count on that as part of the core product.
* Semantically create searches in the server with POST /search
In the previous two examples, you can return a redirect to the search results (like /searches/33) with perfect caching/indexing, and delegate to the server the cache algorithms.
With things like Vary, Etags, Conditional fetchs, Content-Encoding, Content-Type, Cache-Control, Expires that the spec barely grasp, adding a huge body is something that a cache server/cdn will not implement.
So again. What is this spec solving?
The way many caching systems work, by hashing the body and using the hash as the cache key.
New and clearly distinct type of requests, new practices.
It isn't just the size of the request that makes people not want to put them in the query string, it's use of the query string over decades.
I think the horse has bolted here. With HTTP/2 (and often without), URLs can be _very_ long.
Hash
But you wouldn't for QUERY?
This is backwards compatible and in many cases will just work since GET with body is already syntactically valid.
And just like with POST, whether or not this is actually the case in a given API, depends entirely on the server-side implementation.
Look, I get it. We want to make rules. Rules are good. Rules define things.
But in a world where so many "REST APIs" are actually "RESTful" or REST-ish, or "actually about as REST as a Pelican, but we really liked the sound of the acronym", I wonder if adding one more rule to the pile is really going to substantially change anything.
A majority of APIs don't even use all of the existing HTTP verbs, or HTTP response codes for that matter. And every API is free to make up their own rules. I had the dubious pleasure of consuming APIs that required GET with both a body and urlparams, and which returned 200 on error, but with an `{error: {...}}` object in the body. The crown jewel so far, was an authentication system that had me send credentials as multipart/form-data, with a PUT request (because you inPUT the credentials, see? Not a joke, that was the rationale given to me by the dev who made it.)
That you cannot rely on consistency is not a reason to have none at all.
Destructive actions can and are also hidden behind a GET. When such an endpoint gets called indiscriminately by the rest of the internet it usually becomes the faulty implementation's problem.
Presumably the same would be true for QUERY.
Those are 2 very big if's.
> That you cannot rely on consistency is not a reason to have none at all.
I want consistency. I stated as much in my post: "Rules are good." I'm just not convinced adding more rules to a collection of rules that already isn't consistently applied in the wild, will give me more consistency.
That is because there are essentially only 3 verbs in HTTP: GET, POST, and OPTIONS (needed for CORS). All the others are (from a protocol POV) rebranded POST or very specialized (like TRACE or HEAD).
This new method in particular is meant to be useful for proxies, so that they can cache more without risking breaking old stuff
Semantically, it's an error that the frontend can handle and shouldn't show up as "unexpected error" in network logs. Many people treat HTTP error codes as exceptions / real infrastructure problems.
I mean, we build rich clients. You can't simply auth with a user/password header when you get a 401/403 and your browser shows an alert. It's not 2003 anymore.
No it isn't. Semantically `200 OK` means a request was successful. That isn't me saying that, that's the RFC:
https://datatracker.ietf.org/doc/html/rfc1945#section-9.2
The semantically correct message to signal to the frontend that the error originated on its side, and thus has to be fixed by it, is a 4xx response, period.
https://datatracker.ietf.org/doc/html/rfc1945#section-9.4
> Many people treat HTTP error codes as exceptions / real infrastructure problems.
Doesn't change the fact that they aren't exceptional. A != 2xx response code is not an exceptional occurrence. As soon as I talk to a networked process, especially one that I don't control, I am talking to unreliability, and being able to deal with that is normal program operation, not an exception.
> I mean, we build rich clients. You can't simply auth with a user/password header when you get a 401/403 and your browser shows an alert. It's not 2003 anymore.
So?
What exactly does the auth method I'm using have to do with the server using semantically correct return codes?
Luckily, I also consume a lot of good APIs in my code. Guess what they send back when my client messes up something during OAuth. Hint: It's not `HTTP/200 OK`
You can't pre-fetch a POST request, or re-try after a timeout. Because you have to consider that the POST request could have unintended consequences if sent too many times.
You just document that that POST endpoint doesn't actually modify data.
A great example of this are OpenAI completions.
> You can just handle your POST request idempotently
You actually can't though, and you don't usually have to look far to run into a case where this gives the wrong behavior. Better to just have a separate verb.
It may sound cool and efficient on paper, just trim the whitespace and sort all json dictionaries right? But in practice it adds too much complexity, eventually implementations of this semantics will start to drift between cache and real backend. Case in point: SAML XML signatures.
This is how one creates a cache poisoning vulnerability. If a request is normalized as a cache key, use the normalized request when sending to the backend also. If you don’t trust that process you shouldn’t trust it as the cache key either.
Proxies should be dumb, just hash the raw string for the cache key.
This is no different than how any other caching proxy is expected to operate given a set of inputs. It's never been up to the proxy to interpret if the queries "name=joe%20user" and "first=joe&last=user" are the same, it just passes the input along to its upstream and then locally stores the result, assuming that the same input will occur again and save a trip to upstream.
I don't mind caching, but please make it deterministic.
namely, urls are finite, bodies are infinite
Or will the QUERY method end up with the same fate as GraphQL - wherein it's more effective and "secure" in a server-to-server setup and the client only deals with REST.
I don’t think anyone suggests we all open our databases to the web; but if you choose to do so, or if you happen to work on a modern database, like Elasticsearch or CouchDB, which accept queries via HTTP, now there’s a better way to implement queries in regard to caching.
That being said: I’ve been wondering for a long time what a backend API could look like that used SQL instead of JSON as the query format - not to pass it to the database verbatim, but with an application layer that speaks SQL, applies business logic, queries the database, and responds in SQL. That would save a lot of reinvented wheels in terms of filtering, ordering, joining, and so on, and give developers a query language they already know. And suddenly, having a QUERY method available sounds useful, too :)
https://stackoverflow.com/questions/978061/http-get-with-req...
When designing an API, and if spec compliance is not key, I wonder if client-compliance would become the issue (clients refusing to emit a GET body).
That's wrong. A lot of people just don't understand the difference between SHOULD and MUST when reading standards. The standard just says that you shouldn't rely on servers accepting it unless they tell you.
Thinking, will it be possible to send HTTP/1.1 QUERY requests? HTTP/2 QUERY requests?
Or will it be for HTTP/3 or something even higher?
Well the examples given in the document seems to indicate that it will be possible to use with HTTP/1.1 even
QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: example/query
Accept: text/csv
select surname, givenname, email limit 10By "support", do you mean "will not crash on encountering an unexpected verb"?
WEBDAV and CALDAV rely on a slew of new HTTP verbs; but IME only specialized servers actually support these verbs, in the sense of knowing what to do with them. There's an addon module for Apache that supports WEBDAV, but the logic to support CALDAV is insanely complicated, and nearly all implementations rely on a real database server.
In mine, I was just caching raw sql queries, so it was literally just text/sql encoding, the query in the body, some metadata in headers, and a sqlalchemy engine to execute the query.
It's basically a way to get around the non-idempotency of POST and URI limitations of GET.
But - are you asking the server to create/update a resource (POST and PATCH semantics), or are you asking the server to provide you a _view_ of a resource? I'm thinking of query languages like GraphQL and jq here, where a client is making a potentially complex request for a view of the data returned in a structure which is most efficient for them.
The client isn't intending to _modify_ that data in any way, but it is asking for a potentially computationally expensive view of that data.
The way we've done it so far is to either: 1. Cram that complex filtering and view-building into the GET request URI (brittle, not guaranteed URI will function correctly past ~2,000 characters, not clearly defined maximum limit to request URI length in specs) 2. Send the query in a POST request - which works, and is almost what we want, but semantically feels a bit icky, because a query is more cacheable than your average POST, see below:
> caching etc may not make sense.
Perhaps you have a large and complex but static dataset _which will never change_ which nevertheless has many ways of filtering it -- all of which would benefit greatly from e.g. CDN caching.
I'm in two minds here. I half agree with you that POST works fine as the wording of the RFC spec is general enough that what we want to do with QUERY works with it fine as-is. But then I also see how _de-facto_ REST API design conventions have worked against this and treat POST as "create a new resource everytime", and trying to stuff endpoints that go "filter and restructure the responses to my specification" alongside feels.... wrong.
(There is of course the argument that you shouldn't be mixing and matching 'strictly' 'RESTful' patterns with other patterns like the GraphQL one which does away with some of the REST HTTP method semantics in favour of defining the operation type in the request data itself, and of course both of these things are patterns which happen to use HTTP and don't need to influence HTTP spec itself...... But still.... I really want that QUERY lol)
There’s also an option to use the following semantics (with a number of nice bonuses):
POST /resource/views
{some definition of response structure and allowed parameters}
GET /resource?view=…¶ms=…
The whole idea of GraphQL revolves around the possibility of client to query the whole graph of the persistent model. This idea itself is questionable for many reasons - coupling, security etc. In many cases where I have seen it, classic REST with HAL (client-server) or plain old SQL (server-server) would be more than enough.Here's a great post on it- https://httptoolkit.com/blog/http-search-method/ and earlier HN thread- https://news.ycombinator.com/item?id=36095032