<form action="..." method="query">
This would avoid the annoying re-submission warnings you're getting if you refresh a page that was returned by a POST form submission, since QUERY is required to be idempotent.There is a separate issue for QUERY: https://github.com/whatwg/html/issues/12594
In other words, right now if a human wants to DELETE a widget, the human has click on an HTML form to `POST /widgets/123/delete` - i.e. use an incorrect verb on an incorrect URL/object - or use some other workaround like smuggling a special `_method=DELETE` variable. This is unnatural and semantically incorrect, resulting in ugly hacks that break HTTP-level expectations like idempotency; and it also requires additional app-level logic to process.
Meanwhile a machine is allowed to simply `DELETE /widgets/123` because their interface to HTTP is not clicking on HTML forms.
We humans could converse with websites in semantically correct HTTP, have clean URLs in which both REST APIs and human-facing URLs are identical without hacks, and require no extra app/framework logic, if HTML forms simply allowed all (human-relevant) HTTP verbs.
QUERY on the other hand makes sense for cases where the request doesn't cause any state changes on the server, and there is no resource to redirect to.
If we can do QUERY forms, it would be an ideal time to add JSON encoding for forms.
If method=QUERY were added, there would be a new variety of this weirdness.
Even imagining a QUERY with a large JSON filtering structure, or say an image input as request body, it feels extremely odd to include the request body as part of the cache key. It also implies an unbounded and user-controlled cache key, with the only really meaningful general caching strategy being bitwise compare of the request body (or a hash), which in a hostile scenario implies cache busting would be trivial.
This invokes multiple semantic oddities in one go with obvious difficulties for a very niche use case. If I'm writing a service that needs complex filtering or complex input like an image, any form of caching (e.g. individual data columns of a join, or embeddings keyed by perceptual hashes of a decoded image input) is going to be far away from the HTTP layer and certainly unrelated to the exact bit representation of the request on the wire.
Why even bother trying to capture this in a generic way?
I would be far more inclined to try and capture this caching semantic as a new header for POST. Something like "Vary: request-body" or similar. Perfectly backwards compatible and perfectly ignorable for all but the 0.1% of CDN use cases where the behaviour might turn out useful
The query part of GET's URI is also barely bounded in practice and user-controlled, and is indeed used as part of the cache key (because it's a part of URI), so I am not sure why you raise this objection at all.
I've found some sites that tack on a session ID and if you try to tamper with the URL in any way, it sends you back to "Page 1" really annoys me lol at that point let me skip to any page with your web UI.
It feels very pointless and there is no drawback of just using POST
I guess it's about resolving the odd semantics of using POST which is not idempotent and thus allowing easier control flow of caches and retrys.
Your perspective is 100% correct if you think at the application-layer, but with a dedicated method, you can have that behaviour out-of-the-box out of your HTTP infrastructure (whether it's at your hyperscaler's router or your apache/nginx/browser whatever) and stop implementing yourself the post-as-a-query edge case.
Seems the spec puts this as a MAY. I think I doubt it will be implemented in generic ways, except perhaps for urlencoded payloads. After all you cannot normalize in general without knowing the query language. At the backend it does not matter, may as well cache one level deeper based on the parsed input irrespective of QUERY or not.
Even if the spec says that different representations are equivalent, it's quite common for applications to treat them differently. For example field ordering in json objects is supposed to not matter, but some serializers care if a type discriminator is the first field.
Exemple:
``` QUERY /search HTTP/1.1 Content-Type: application/json
{ "filters": { "region": "asia", "status": "active" }, "sort": "created_at", "limit": 500 } ```
can answer
``` HTTP/1.1 303 See Other Location: /queries/results/f3a9c1d7 ```
And then you can access later `/queries/results/f3a9c1d7` using a pure GET call, and cache this instead
This is basically a GET request that can have a body. I've found myself in need of that more than once when I did not want huge URLs with encoded data showing up in logs. Using POST request there is not appropriate because it signals data could be modified (i.e. cannot be sent to read-only instances). I guess modifying the spec to allow GET to have a body would pose too many problems.
Realistically, systems for the public internet will use a secure hash as the cache key so it'll always be the same size. The cache key already includes a URL that can be very long, and an arbitrary set of header values.
But I think this would make it better - QUERY before POST means different request types, not just the same with a safety flag.
While the concern is valid, caching is entirely optional at query level, therefore it is totally valid to cache only certain "filters".
/?hash=123456789
Location: /search/?queryHash=SOMECDNHASH
The browser can then cache that Location and the next time convert that same QUERY /search/ into GET /search/?queryHash=SOMECDNHASH.Sure, it is more work for your webserver to compute that and potentially the browser to cache it's knowledge of that QUERY, but it potentially gives you an advantage in keeping things like CDN edge caches generally aware of client/browser caches in a way that can be performance optimized.
There is one interesting variant though, which uses state: The client sends a QUERY containing the full query, and the server returns a url usable with GET with which this query can be triggered in the future. Similar to prepared statements in SQL databases.
Using QUERY for GraphQL queries (not mutations) would be a good match. These only read data, but are sometimes bigger than the url length limit.
I still don’t get how idempotency can typically be ensured without state. It very much depends on data model and application design. Even side effects like using a user’s lookup quota need to be handled at a higher layer than HTTP (I think?).
But what the Query method really targets are things like a graphql query that can be multiple kb for a single query, but only reads data. Sure, it might count against rate limits, trigger logs, etc. But at a conceptual level resubmitting the same query should give the same result (if the data didn't change). And since you are only reading data, resubmitting is safe
Well, how is "GET /index.html HTTP/1.1" made idempotent in practice without (additional) state?
If it's not actually idempotent but you're telling the browser it is, of course you may cause bugs. Same as GET.
> A QUERY request from user agents implementing Cross-Origin Resource Sharing (CORS) will require a "preflight" request, as QUERY does not belong to the set of CORS-safelisted methods (see [FETCH]).
Unlike POST, however, the method is explicitly safe and idempotent, allowing
functions like caching and automatic retries to operate.
Essentially, it's for things that are inherently safe/idempotent already (e.g. search or indeed, anything that you don't mind being retried) but require a lot of data passed in the request.I've been sending request body along GET method for years now
Generally not a great idea. With some http implementations this is not even possible (for example, fetch)
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/U...
> You cannot include a body with GET requests
And transparent caching might result in weird issues.
you can do all kinds of nonstandard stuff if you control the server, the client, and any steps in between. the point of standards is for when you don't control it all.
put your server behind a managed load balancer or a caching proxy, and your get requests with bodies aren't going to do so well anymore.
When it's your client talking to your server you can obviously do whatever you want - it doesn't cause problems until you want to involve third-party code, such as a reverse proxy (such as nginx) or a CDN. This includes proxies your customers may be using.
You've never heard of BEEP? Well, that's why.
https://manifold.markets/CollectedOverSpread/when-will-rfc-1...
https://mailarchive.ietf.org/arch/msg/tools-discuss/EpoQcVt_...
RFC #s are issued sometime before publication, so they can come out out of order. I would expect 9999, 10001, etc. to show up eventually.
just wow, people seem to be having too much money it seems for them to bet over when RFC's are gonna get released.
This isn't even one of the worst offenders on prediction market or even comparable to it but I am just amazed (in a negative manner, surprised? its just strange) by the depth on what people actually bet on these markets.
So of 10008 is the first one after 10000, that date is the one to bet on.
We do have humans brainstorming about such things, but this feels like something LLMs might be good at.
QUERY has the advantage of getting default behaviour from most proxies (which at least is well behaved even if inefficient). If there are any proxies that just drop QUERY requests, at least they won't silently mangle the request.
This is the same way that instead of improving how HTTP 301 was specified, HTTP 308 was created. It's a pragmatic move.
i actually agree with you, i don't comprehend why we're adding anything to HTTP like this, it is basically already deprecated. The modern API is WebTransport, if you want to make caching better for WebTransport, do it there.
Also, anyone using these servers is not currently putting params in GET body because doing so wouldn't work.
Those that oversee evolving standards seem to take extreme cautious to not rock the boat, and so more and more gotchas for the sake of backwards-compatibility keep getting added to the mountain of random details new devs have to learn. Which will soon include the difference between a GET and a QUERY I guess.
I think the name is confusing because the term 'query' is already used to refer to http requests in general.
Just the title of the RFC confused me.
In what circles is this the case? I sometimes colloquially refer to a GET request as a query, but definitely not so on a POST, PUT or DELETE.
Edit: ah, they declare QUERY as "safe" meaning no side effects, for cacheability. My mistake.
HTTP is transfer protocol. It should not ever imply anything at the business level.
Yes REST made it's worst mistake out if it by giving a meaning to the verb.
Yes proxies rule how the body is re-interpreted in spite of the will of the sender (wtf).
But the original RFC states clearly that any verb can be used. This is how WebDav normalised its own.
But playing fancy by introducing a change that all HTTP implementation will have to honor is a very bad and irrational choice.
What I meant was a tangent: the HTTP was designed with a strong assumption that the application implementing it (the web server) would be the one providing the logic. Hence all the RFC terminology "should", "must", targeted at the implementor.
But very quickly, the logic was deferred to a layer on top (PHP,...) which would focus on the business aspect. The wiring was strong but the contract intent is loose (the requirements on the transport do not apply to the function).
Different layers, different people involved. What survived are the more or less conventions about it, which for the ease and limitations imposed by the protocol layer, led to infinite discussions about GET having a body or not.
The whole question arises because there is this clash between transport and logic that is wired on top, not built-in.
So while indeed, introducing QUERY solves a protocol gap, the people designing the business method never cared (or even knew) about that gap in the first place. This was another people's job to try to reconcile the two.
That's why I'm saying that digging into the initial assumption that the implementor of the HTTP is bound to business-level contraints is not reflecting the reality that has been going on since the early days of the dynamic web.
Having a standard way to do pagination would be extremely useful. If we could add an items (or similar) range header type that would be excellent!
For example, in the HEAD response (and the QUERY response):
accept-ranges: items
items-length: 342
In the QUERY request: Range: items=0-9I like that we now have a way to not being forced to define Resources when we want to query. It always felt like I was missing something that there could be an infinite, defined-on-the-fly number of Resources for a "part" of a given Resource. Do I really want to define "all cats that sleep more than 20 hours a day and like sunbeams and want to eat breakfast at 3 am" as a Resource? (ok, we all know that is actually the full set of cats). I'm ok that you want to define that as a Resource but in my system, it makes more sense that Cats is the Resource and I just need some accepted way to query.
I like the implementation (again, as just a guy that programs). I don't see how it could have done it better or simpler which probably hides the complexity of getting there.
I also especially appreciate how the spec is written. Opening a spec, I wonder how far I'll get before I don't know what the heck they're talking about (and, again, as just a guy that programs). I don't think it's easy to write a spec that is complete and approachable like this. Really appreciate that.
I thought it wouldn't be a terrible idea to open up the GET method to contain a body but according to the original spec the GET body is to be ignored completely. There's also caching which would break because the important bit of the request would live in the stripped body.
Due to the need of bodies in requests, everyone uses POST and streaming results often use the text/event-stream protocol for responses. But this is technically a bad fit because no state is actually changing and because EventSource can only use GET for some obstinate reason. So many APIs reimplement the functionality with their own parser
I’ve enjoyed the combination with Range headers for paging, despite this tidbit:
> It is expected that these built-in features will be used instead of HTTP Range Requests
Using the QUERY request as the definition of a set, and Range to retrieve subsets seems very natural.
Why is that better than a longer URL?
Semantically it identifies the resource. And it must be included in the cache key.
True, not everything supports long URLs. But not everything supports QUERY either, so it’s an absurd argument.
Edit: refute or agree, please.