HTTP QUERY Method reached Proposed Standard on 2025-01-07
Posted by DraxusLuck@reddit | programming | View on Reddit | 153 comments
Posted by DraxusLuck@reddit | programming | View on Reddit | 153 comments
BenchOk2878@reddit
is it just GET with body?
castro12321@reddit
Kind of. I see it more as a response to the needs of developers over the last 2 decades.
Previously, you either used the GET method and used url parameters, which (as explained in this document) is not always possible.
Or, alternatively, you used the POST method to send more nuanced queries. By many, this approach is considered heresy. Mostly (besides ideological reasons) due to the fact that POSTs do not guarantee idempotency or allow for caching.
baseketball@reddit
Idempotency is something guaranteed by your implementation, not the HTTP method type. Just specifying GET on the request as a client doesn't guarantee that whatever API you're calling is idempotent. People still need to document their API behavior.
FrankBattaglia@reddit
https://httpwg.org/specs/rfc9110.html#rfc.section.9.2.1
https://httpwg.org/specs/rfc9110.html#rfc.section.9.2.2
GET is idempotent according to the spec. If your GET is not idempotent, your implementation is wrong.
Blue_Moon_Lake@reddit
It should be, but people doing things they shouldn't is not unheard of.
FrankBattaglia@reddit
I wouldn't expect an API to document every way in which it follows a spec -- I would only expect documentation for where it does not follow the spec.
E.g., if your GET is idempotent, you don't need to document that -- it's expected. If your GET is not idempotent, you certainly need to document that.
Blue_Moon_Lake@reddit
Cache systems between you and the server will expect GET to be idempotent though.
FrankBattaglia@reddit
Your use of "though" implies disagreement but I don't see any.
Blue_Moon_Lake@reddit
A disagreement that GET could be non-idempotent as long as documented.
FrankBattaglia@reddit
Ah, that wasn't my intent. It's still wrong and as you said will break assumptions of intermediaries. I was just replying to the idea that an API needs to document when GET is idempotent (it doesn't IMHO). On the other hand, if your implementation breaks the spec, you need to document that (but that doesn't make it okay).
baseketball@reddit
That's my point. Not every HTTP API is RESTful. As an API consumer, know what you're calling, don't just assume everyone is going to implement something according to spec because there is no mechanism within the HTTP spec itself to enforce idempotence.
PeacefulHavoc@reddit
True. There are many APIs with hidden behavior on GET requests. One could argue that if the API registers access logs and audit data, it's not really idempotent.
FrankBattaglia@reddit
https://httpwg.org/specs/rfc9110.html#idempotent.methods
tryx@reddit
None of those are observable behavior to an API user, so we treat that as idempotent.
FrankBattaglia@reddit
GET being idempotent isn't a REST thing -- it's an HTTP thing. Caching, CORS, etc. are built on that assumption.
vytah@reddit
Almost no HTTP API is RESTful.
https://htmx.org/essays/how-did-rest-come-to-mean-the-opposite-of-rest/
JoJoJet-@reddit
Hold up, if DELETE is supposed to be idempotent does that mean it's incorrect to return a 404 for something that's already been deleted?
FrankBattaglia@reddit
No. Idempotency does not guarantee the response will always be the same. See e.g. https://developer.mozilla.org/en-US/docs/Glossary/Idempotent
ArsanL@reddit
Correct. In that case you should return 204 (No Content). See https://httpwg.org/specs/rfc9110.html#DELETE
JoJoJet-@reddit
Huh that seems strange. If someone tries to delete something that never existed in the first place, or something they don't have access to, are you supposed to "lie" and return 204 as well?
john16384@reddit
Access checks come first, they don't affect idempotency.
And yes, deleting something that never existed is a 2xx response -- the goal is or was achieved: the resource is not or no longer available. Whether it ever existed is irrelevant.
JoJoJet-@reddit
This makes sense in a way but it kind of feels like failing silently. For example, if a consumer of my API tries to delete something with the wrong ID it'll act like it succeeded even though there was an error with their request.
john16384@reddit
There is no error. It could be a repeated command (allowed because idempotent), or someone else just deleted it. Reporting an error will just confuse the caller when everything went right.
JoJoJet-@reddit
I understand that. I'm saying if the caller genuinely did have an error in their code that else them to use the wrong ID, they wouldn't know my because my endpoint returned a 2xx even though their request was garbage
wPatriot@reddit
If that's the kind of error you're getting, anything is fair game. If the wrong ID does exist, it'll just (without warning) delete the record associated with that ID.
john16384@reddit
It is not the API's responsibility to point out mistakes (in this case it can't even distinguish if it was a mistake or just a repeated call, by a proxy for example, which DELETE explicitly allows).
API's only point out mistakes if they can't understand the request, but that's not the case here.
So yeah, it might be nice to say "are you sure you meant to delete something that didn't exist?" but that's just second guessing. It may be completely intentional or a harmless race condition.
cowancore@reddit
It seems strange because retuning 404 is likely correct as well. It's a bit hard to interpret, but the spec linked above has a definition for idempotency, and it says nothing about returning the same response. The spec says the intended effect on server of running the same request multiple times should be the same as running it once. A response returned is not an effect on server state, but an effect on client at best. The effect on server of a delete request is that an entity will not exist after firing the request. Mozilla docs do interpret it that way and say a 404 response is OK for DELETE on the page about idempotency. From a clients perspective both 204 and 404 could be interpreted as "whatever I wanted to delete is gone".
vytah@reddit
It says:
For deleting things that never existed or the user doesn't have access to, I'd base the response on information leakage potential. Return 403 only if you don't leak the information whether the resource exists if it belongs to someone else and the user doesn't necessarily know it. But usually the user knows it, for example if user named elonmusk tries bruteforcing private filenames of user billgates, then trying to delete each of the URLs like /files/billgates/epsteinguestlist.pdf, /files/billgates/jetfuelbills.xlsx etc. should obviously return 403, as it's clear that whether those files exist is not elonmusk's business and returning 403 doesn't give him any new information.
TheRealKidkudi@reddit
IMO 404 is more appropriate for a resource that the client shouldn’t know about AKA “this resource is not found for you”. As noted on MDN:
I guess you could send a 403 for everything, but IMO calling everything Forbidden is not correct. 403 is for endpoints that you may know exist but you may not access, e.g. another user’s public data or data in your organization that you’re authorized to GET but not POST/PUT
plumarr@reddit
And Mozilla say 404 : https://developer.mozilla.org/en-US/docs/Glossary/Idempotent
plumarr@reddit
If you take idempotent as "the same query will always return thesame effecté" then this part of the spec is probably not in line with most use cases and will be ignored. Simply imagine a GET method that return the current balance of an account. You don't want it to always return the same value.
But it seems that the definition of idempotent is a bit strange in the spec :
I really don't understand it. Does two queries with the same parameter must return the same result ?
FrankBattaglia@reddit
Consider:
You can call the
idempotent
function over and over again, and if you use the same parameters it will always have the same effect as if you had called it once. On the other hand, every time you callNOT_idempotent
, even with the same parameters, the state on the server will change.Now consider another function:
If we call
the responses will be:
{ value: 5 }, { value: 5, external: 'ex' }
This still satisfies the idempotent requirements, because the effect of the idempotent call isn't changed even though the response might be different.
Does that help?
Tordek@reddit
You don't return effects; you return results. You cause effects.
GET is safe, meaning GET should not cause effects. Calling GET twice should probably return the same results, since doing nothing twice should be equivalent to doing nothing once.
No, there is no such requirement. What it says is that a GET should not cause state to change, but since systems exist in real life, it's possible for one GET to succeed and the following one to fail due to a db connection failure, or simply that you can do GET/DELETE/GET and get different results.
The point of GET being idempotent is that you're allowed to GET anything and expect to not cause stuff to break, that way you can have, e.g., pre-fetching.
It's not about what value GET returns to the client, but in fact the opposite: "you may GET (or DELETE or PUT) as many times as you want"; retrying is not "dangerous".
Destring@reddit
This is such a purist take. Standards are informed by use cases. Wrong according to what? The standard?
If it is correct according to your business requirements then it is correct period.
Booty_Bumping@reddit
Somewhere out there, there is some server where a single GET request from a search engine crawler will delete the entire database... and the developer considers it a feature.
castro12321@reddit
Yes, but I assume to work with competent people who follow the standard unless it's absolutely necessary otherwise.
baseketball@reddit
I can't assume anything about third party APIs that I don't control.
Captain_Cowboy@reddit
You obviously can, or you'd be starting all new protocol work by pulling out a multimeter.
Vimda@reddit
Middleware boxes *will* assume behaviors in your application based on the method, which means your app *will* break if you put it behind one that makes those assumptions and your app violates them
PeacefulHavoc@reddit
I am curious about caching QUERY requests efficiently. Having CDNs parse the request body to create the cache key is slower and more expensive than what they do with URI and headers for GET requests, and the RFC explicitly says that stripping semantic differences is required before creating the key. Considering that some queries may be "fetch me this list of 10K entities by ID", caching QUERY requests should cost way more.
lookmeat@reddit
Cacheable doesn't mean it has to be cached or that it's the only benefit.
It's idempotent and read only, so this helps a lot with no just API design but strategy. Did your QUERY fail? Just send it again automatically. You can't really do that with POST requests, and GET have limits because they aren't meant for this.
Blue_Moon_Lake@reddit
Why would you parse the body instead of hashing it?
CryptoHorologist@reddit
Normalization would be my guess.
Blue_Moon_Lake@reddit
Normalization should already have happened when sending it.
PeacefulHavoc@reddit
That's not what happens though. Clients shouldn't have to worry about whitespace, field order and semantically equivalent representations (e.g. null vs absent field).
Hashing bytes from a body would mean fewer hits and a lot more entries in the cache. That might be where the overhead is smaller, but proper GET caching normalizes query parameters in the URI and header order.
Blue_Moon_Lake@reddit
They should.
If you want them not to, give them a client package that does it for them.
castro12321@reddit
This is a very interesting and thoughtful consideration! You're right that parsing the body will influence the response latency.
The question is... is it worth it? I believe it's probably worth it for majority of cases. And for the remaining few percent like your unique case, we'll probably fallback to POSTs again and wait another decade or 2 for alternative.
You might want to ask this question directly to the proposal's authors to see if they already have a solution for this.
PeacefulHavoc@reddit
It will probably need to be a deliberate decision with some benchmarks. Regardless, caching is optional... so semantically it would be better to avoid using POST and just using a "live" QUERY request.
throwaway490215@reddit
I'm not sure i follow.
You're worried about the costs of creating a key for a HTTP QUERY request?
If so: hashing a request is orders of magnitude less costly than what we spend on encryption, and Interpreting/normalizing is optional - its a cache after all.
I doubt many systems are going to bother, or if you know the specific request format you could simply cut off a few lines instead of running a full parser.
PeacefulHavoc@reddit
Others did a better job than I could in the replies, and I agree in general with your points.
My point was that caching QUERY requests is much harder than whatever we are used to nowadays, and I believe most of the APIs won't bother doing it, either because it would require tweaking the cache key function or because it is expensive (billing-wise).
Client-side caching on the other hand shouldn't be a problem. I was so focused on CDNs that I disregarded that part. This could be the perfect use case.
castro12321@reddit
Not the person you asked, but I believe the answer depends on the context of the business the solution is running in.
In most cases, like you suggested, the overhead will be minimal in comparison to other parts of the processing pipeline and "I doubt many systems are going to bother". But we're talking about the proposal as a whole and it's nice to consider more exotic scenarios to ensure that the original idea is sound because some software will actually implement and need those features.
For example, you mentioned that normalization is optional. Sure, it might not mean much if you have a few dozen entries. But if you work on any serious project, then the normalization might save companies a lot of money by not having duplicate entries.
For example, ignoring obvious boring whitespace formatting issue, let's talk about more interesting cases. Is the encoding important? Or is the order of object keys important - Is { foo: 1, bar: 2 } different that { bar: 2, foo: 1 } ?
"you could simply cut off a few lines". Could you elaborate more with an example?
throwaway490215@reddit
I'm mostly thinking of situations where you control the majority of clients and can expect/enforce a certain request format, but your requests might hold some client dependent data.
You can just tell your cache-keying function to skip any line starting with
^\tunique_user_or_request*
and sort the rest.I'm not saying this is a good idea, I'm just saying somebody is bound to do it.
As a whole i think its better to approach the normalization problem as both created and solved by the dataformat you pick. Ir shouldn't be a big consideration in this context except as a note that naive JSON isn't going to be optimal.
bwainfweeze@reddit
GET only has one Content-Type for the query parameters, no Content-Language, and substantially one Content-Encoding (url-encoded)
This spec invites at a minimum three Content-Encodings, and potentially Content Languages
No the more I think about it the less I like it.
apf6@reddit
Caching is always something that API designers have to think about. If the request is complex enough that a developer would pick QUERY instead of GET, then there’s a good chance that it shouldn’t be cached. The current state of the art (cramming a ton of data into the GET URL) often creates real world situations where caching at the HTTP layer is pointless anyway.
PeacefulHavoc@reddit
I agree that not all requests should be cached, but as an API user, I'd rather use a single way to query stuff, so I would only use QUERY. Some queries could be _give me the first 5 records with the type = A. That should be easy to cache.
Now that I think about it, caching only small requests (by Content-Length) and without compression (no Content-Encoding) would be a good compromise.
Luolong@reddit
Yeah, but would you want to cache QUERY responses?
pickle9977@reddit
I don’t understand why you think just becuse an RFC specifies it that you would rely on that over much more relevant documentation for the specific service you are calling.
Everything is implementation dependent….
castro12321@reddit
What's the purpose of saying "this service exposes a REST API" if it doesn't follow the spec?
Sure, I'm going to read the documentation to make sure there's nothing written in fine print, but more often than not vendors don't specify such details. Have you ever seen API doc specifying that "GET /v1/person is idempotent"?
pickle9977@reddit
Because 99.999% of supposedly “idempotent” operations don’t actually function as idempotent. It’s a big word most people use to sound smart and make themselves think their APIs are solid.
Implementing truly idempotent mutating operations in a highly distributed environment is so far beyond what most engineers are capable of, most can’t even understand why their supposed idempotent operations aren’t.
Also REST is an architectural pattern it provides no contracts for implementations, in fact it doesn’t even require use of http and the associated verbs for implementation, you could implement a REST api using a proprietary protocol over UDP.
Pushing further on that the http spec does it actually require idempotency for any operation, methods “can” and “should” where “should” is recommended not must
castro12321@reddit
I guess we are both right but from different perspectives.
I'm talking from the point of "your regular business" for which the less time you spend developing the better,
and you are talking from more strict academic or highly-sensitive domain's point of view which cannot afford mistakes.
Your "99.999% idempotent operations is not really idempotent" is something I'd only expect a purist to say. For most "regular" software it works good enough.
You could say that 99.999999% SLA is not enough and software is not reliable because there is going to be 0.0005 seconds of downtime per year. Similar vibes.
So for me the point of following any guidelines (like the RFC) is that I can assume at least a few things (baseline) and talk to the vendor using the same jargon.
"Implementing truly idempotent mutating operations in a highly distributed environment is so far beyond what most engineers are capable of"
- Honestly... If so few can manage to do it correctly and the world still functions... Maybe it's not that important for most businesses?
Unless people lives depend on your work (for most most software the answer is false), you can probably make some assumptions and still be fine 99% of the time. If it's really important then I'll make sure to check.
Sure, we can be very strict and the reality is far more nuanced. To be *really* sure if operation is idempotent you'd have to audit vendor's API code yourself because people are incompetent. This kinda defeats the point, right?
I'm just assuming that APIs are written according to the RFC unless it's explicitly written otherwise in documentation. I'm not sending rockets into space or anywhere else.
IrrerPolterer@reddit
Thanks for the explanation! Really helpful stuff
macca321@reddit
There's a school of thought that you could not unreasonably use a query in the range header. But it was never going to take off
tonyp7@reddit
Maybe the standard did not officially support it but nothing is stopping you from adding a body to a GET query.
Empanatacion@reddit
Some tools pedantically disallow it. The bigger issue is with caching, though. Shoehorning your parameters into the query string will let caching be correctly managed (especially regarding expiration). Putting your parameters in the body means you can't cache anymore because your differing requests look the same. At which point, changing it to a POST is at least explicit about the limitation.
In practice, we've always just pushed the caching back one layer, but it does mean your CDN can't do it for you.
REST can get weirdly religious.
modernkennnern@reddit
Basically, but that's exactly what we've needed. Query parameters are severely limited in many ways, and PUT/DELETE makes very little sense for something that just reads data.
Worth_Trust_3825@reddit
Could've just added optional body to the get request then.
Kendos-Kenlen@reddit
The main reason js to ensure it’s easy to distinguish and know if QUERY is supported. This way, you just have to check if this verb is supported by your software / library, while with GET you can’t know if they comply with the standard.
Another reason is to clearly express what it does. I mean, if we wanted to spare verbs, we would only work with GET and POST. No need for PATCH and PUT since POST also takes a body and can do the job, and no need of DELETE since a GET on a dedicated endpoint does the same.
With QUERY any software know it’s a read only operation, that can be cached (POST / PATCH / PUT / DELETE should never be cached) and that have a body which contains the request criteria, compare to a GET which define itself by the URL and query parameters only.
Uristqwerty@reddit
If your software has been updated to understand QUERY at all, then it could as easily have been updated to accept GET bodies. To me, QUERY as a separate request type would be primarily for the benefit of humans rather than machines.
Lonsdale1086@reddit
It could, but you wouldn't be able to tell without digging into the docs.
Uristqwerty@reddit
Bad docs will exist either way, and you still need to read them to see how standards-compliant the software is attempting to be, what sort of extensions they specify as part of their supported behaviour contract versus being incidental implementation details that may change. You still need to test that the behaviour you depend upon is upheld, ideally in an automated manner if you ever intend to update dependencies.
I'll repeat myself, the primary benefit is for humans, not machines. In this case, you hope that an unsupported HTTP verb gives a better error message in the logs than an unexpected GET body, but that is by no means guaranteed or even likely just because someone wrote a standard about it.
Blue_Moon_Lake@reddit
It used to be the case, but then they removed it for fallacious reasons.
Basically, they said that some implementations of things like proxy and cache systems might not work with GET+body so they forbade it retro-actively.
Worth_Trust_3825@reddit
Makes sense. Supporting a new verb for those caches would take just as much effort to implement and update.
Blue_Moon_Lake@reddit
I don't see how it's the standard that must change to support erroneous or incomplete implementations.
If they allowed GET + body all along and just decided to plan an update to split GET and QUERY later one it would have made more sense.
bwainfweeze@reddit
I would highly recommend if you’re a regular ES user that you file a request to stop doing that in favor of QUERY.
Worth_Trust_3825@reddit
I'd rather file a request to move away from GET, PATCH, PUT, in favor of using POST only.
bwainfweeze@reddit
You don’t work on caching much do you?
Worth_Trust_3825@reddit
Caches are configurable.
hstern@reddit
It’s idempotent
Dunge@reddit
Can you ELI5 what does "idempotent" mean in this context? I fail to grasp the difference with a POST
TheWix@reddit
It means the system behaves the same no matter how many calls you make. For example, if a POST call is used to create a user and you call it twice then it is likely to succeed and create the user the first time, but fail the second time.
Dunge@reddit
Ok, but that's just as a convention right? Because right now, nothing prevents me on the server side app to create a user on a GET method, or return a static document from a POST method..
Does QUERY change something functionally or is it just a convention that web admins should follow "you should be idempotent".
Akthrawn17@reddit
It is not convention, it is the published standard. If the developers decide to follow the standard or not is a different question.
These were put as standards so all clients and servers could work together. If your server creates a user on GET, but is only used by one client that understands that, then no issues. If your server needs to be used by many different clients, it probably will become an issue.
Blue_Moon_Lake@reddit
Funny you say that, because they retro-actively forbade GET to have a body out of concern that people were not following the standard correctly.
AquaWolfGuy@reddit
Proxies and other middleware might make assumptions that break things.
But for a more concrete example, there's form submission in web browsers. There are ways to work around these issues using redirects or JavaScript. But without these workarounds, if you submit a form that just uses a normal POST request and then press the refresh button in the browser, you'll get a warning that says something like
with the options to "Cancel" or "Resend". If instead you navigate to another page and then press the back button in the browser to go back to the result page, you might get a page that says "Document Expired" with a "Try Again" button, which will give the same warning if you press it.
From the browser's perspective, it doesn't know whether a POST request is something that's safe to retry, like a search query, or unsafe, like placing an order or posting a comment. So it needs to ask if you really want to send the request again. With a QUERY request, the browser knows it's safe to try again automatically.
dontquestionmyaction@reddit
Nothing stops you from doing dumb stuff.
If you do so however, you WILL eventually run into issues. GET is assumed to have no side effects and is often cached by default.
Dunge@reddit
Yeah thanks I get it. I was just trying to find out if that QUERY verb actually enforced some things at the protocol level. But it seems like it's just a string for web server to act on, and if I'm not mistaken it's also the case for every other verbs.
quentech@reddit
How would the protocol enforce that your application handles the request in an idempotent manner?
dontquestionmyaction@reddit
You can do whatever you want with HTTP, it has basically no real guardrails.
bananahead@reddit
I’m not sure what “just a convention” means but your stuff will break in weird and unexpected ways if you don’t follow it. Your app may be running on a network with a transparent caching proxy that you don’t even know about, and it will assume you’re following the spec.
TheWix@reddit
It is a convention for RESTful services. You can do whatever you want to the state of the server on GET, despite GET being marked 'safe' (which is different than idempotent).
Alikont@reddit
ELI5: idempotent means that it doesn't matter if you press button one time, or smash it 100 times, the result is the same.
GET by standard says that the state of the system should not be modified during request, so a lot of software can safely do a prefetch on GET urls or retry on failure without fear of accidentally deleting something or creating multiple records.
simoncox@reddit
Not strictly true, the result can change. There should be no side effects of issuing the request more than once though (aside from performance impacts of course).
For example, a GET request for the current time will return different values, but requesting the current time multiple times doesn't change the system.
If you care about not seeing a time that's too stale, then the response cache headers can influence whether the response should be cached or for how long it should be.
BenchOk2878@reddit
GET is idempotent.
painhippo@reddit
Yes but post isn't. So it covers the gap, is what he meant.
Sethcran@reddit
Isn't this just a convention? Afaik, there's no mechanism (perhaps besides caching and the associated bugs you'll get) enforcing an idempotent get or a non-idempotent post.
A dev can write an idempotent post endpoint easily enough and serve the proper cache headers.
bwainfweeze@reddit
Devs can and do write GET requests with side effects and then learn the hard way when a spider finds a way in last the front page.
Oh look a spider traversed all the ‘delete’ links in your website. Whups.
bananahead@reddit
Isn’t…everything…just a convention?
If you control both ends and don’t care about standards you can do whatever you want, but even in that case you are asking for trouble by running something that’s almost HTTP but not quite.
Sethcran@reddit
I hear you, but also don't think it's as applicable as you'd think.
There's various software that will have to support the new verb that are not really end user code. Web servers, cdns, etc.
So to those things, they need to implement the spec, but idempotency isn't really part of it.
The application code that runs on top of these it's more convention than spec. Because a user can't really call your API with just knowledge of this spec. They also have to know some specifics of your API. So to that end, it's almost like this is pulled up a level higher than its implementation.
It's not that I disagree with any of this to be clear, it just feels slightly out of place as a core reason for the difference. Having a body and some other things makes more sense for why it's being implemented.
bananahead@reddit
As a practical example, there are still transparent caching proxies out there and they don’t need to know your application code, but they do need to know which HTTP verbs are idempotent.
painhippo@reddit
Yes, you are right.
But baking something into the standard ensures forward compatibility!
TheNakedGnome@reddit
But wouldn't it be easier/better to just allow a body with a GET?
painhippo@reddit
I don't think so. To ensure backward compatibility, it's much easier to add something to the standard than to retrofit.
splettnet@reddit
That's a breaking change as existing implementations may rely on the standard stating they can disregard the body. I know there's at least one server that strips it out and doesn't pass it along downstream. It's better to extend the standard rather than modify its existing API.
This gives them time to implement the extended standard rather than have an ambiguous implementation that may or may not disregard the body.
aloha2436@reddit
Why would it be easier? You still have to update every implementation, and changing the meaning of something that already exists and is already used at the largest scale possible has its own pitfalls. I think it's easier to just make a new method and let users migrate over at their own pace.
_meegoo_@reddit
There is nothing that can stop you from doing it right now. Except, of course, the fact that some software might break if you do it. But modifying the standard will not fix that.
Blue_Moon_Lake@reddit
Yes, we're finally getting it back under a different name.
GET with body was allowed, but prevented it in
fetch()
then retro-actively changed the standard. Reason given is that there's possibly badly coded implementations that would not know what to do with the body of a GET request.baseketball@reddit
Looks like it. It doesn't matter for practical purposes. It's basically for the cult of Roy Fielding to feel good about not using POST for GET type requests.
Destring@reddit
This proposal fundamentally misunderstands the role of HTTP methods. Their main argument is that using POST for queries “isn’t readily apparent” that you’re doing a safe, idempotent operation. But you can’t encode every semantic intent into HTTP methods - that’s what API specifications are for!
If we followed this logic, we’d need new HTTP methods for every possible semantic contract: VALIDATE, CALCULATE, ANALYZE, etc. That’s absurd. This is exactly why we have OpenAPI/Swagger specs and similar tools - to document these semantic contracts at the appropriate layer of abstraction.
The authors are trying to solve a documentation problem by adding complexity to the HTTP spec itself. That’s the wrong approach. We don’t need a new HTTP method just because POST isn’t “semantically pure” enough for queries. Sometimes pragmatic solutions (like using POST) are better than theoretical purity.
/rant
sharlos@reddit
How else do you suggest something like graphql make a query to the server that is idempotent and cacheable? GET doesn't support body content, and POST can't be cached.
Destring@reddit
That I’m downvoted and questions like this just paints me a clear picture of the actual expertise of this sub.
The argument doesn’t really hold up, especially if you actually read RFC 7231 Section 4.3.3. POST responses are explicitly allowed to be cached if you set the right cache control headers, it’s just not the default behavior.
For GraphQL there are already several solid solutions:
Put smaller queries in the URL as GET requests
Use a query ID system where the actual query lives on the server
Persisted queries
Modern CDNs can handle POST caching
But here’s the real problem , QUERY doesn’t even fix the caching issue. It handwaves with “just normalize the request bodies for cache keys.” Anyone who’s worked with query normalization knows what a mess that is.
Look at these two queries that mean the same thing:
How do you normalize that? And that’s just GraphQL - now imagine doing that for every query language out there. Plus every server will implement it differently.
This solves nothing and and application level concerns to the protocol. There’s a reason why it’s been more than half a decade in proposed status
bwainfweeze@reddit
This is going to be a fucking headache and at least three CERT advisories. Forward proxies will have to be upgraded to even hope to support this:
2.4. Caching
The response to a QUERY method is cacheable; a cache MAY use it to satisfy subsequent QUERY requests as per Section 4 of [HTTP-CACHING]).
The cache key for a query (see Section 2 of [HTTP-CACHING]) MUST incorporate the request content. When doing so, caches SHOULD first normalize request content to remove semantically insignificant differences, thereby improving cache efficiency, by:
Removing content encoding(s)
Normalizing based upon knowledge of format conventions, as indicated by the any media type suffix in the request's Content- Type field (e.g., "+json")
Normalizing based upon knowledge of the semantics of the content itself, as indicated by the request's Content-Type field.
Note that any such normalization is performed solely for the purpose of generating a cache key; it does not change the request itself.
gjionergqwebrlkbjg@reddit
And the format conventions are not specified, so you'll have a bunch of different behaviors.
bwainfweeze@reddit
All of this on what should be a machine with a relatively dumb nginx/traefik/haproxy + KV store or squid. This is gonna be a headache. And the more I think of it the more I understand why it’s being proposed in 2025 and not 2005.
davidalayachew@reddit
Hypothetical question then -- assuming that caching is going to get shipped with this, no matter what, how would you propose it to be done? Just don't interpret anything and assume the whole body+endpoint is the key, as is?
It makes sense to me, and would completely eliminate any ambiguity. Anyone who wants something more specialized can opt out of standard caching behaviour and implement it their own way. Or go back to doing POST.
After all, I had assumed that the entire point of these HTTP Methods was to give people a bunch of out-of-the-box benefits if their API calls aligned with a pre-existing method. If it doesn't align, pick one that does.
bwainfweeze@reddit
So much if this is asking the wrong questions I barely know where to start.
Go back to POST? What about GET? If you’ve already rolled your own edge/CDN services to make caching work over POST then I guess you add QUERY. But you’re already off in the tall weeds so you’re gonna do what you’re gonna do. Caching is supposed to be for GETs.
davidalayachew@reddit
Correct, but that goes back to the whole "GET bodies shouldn't be considered." My assumption is that, since the body is now being considered for QUERY, the caching behaviour might reflect that, whereas it might not for GET.
bwainfweeze@reddit
Yeah and I don’t think they explain it. The existing Vary header isn’t really equipped to handle it.
davidalayachew@reddit
Oh wow. You're right, they don't.
I sort of assumed that that was going to be the case. I couldn't see any reason not to. But you are right, nowhere is that said explicitly. Weird that they would focus on the cache decoding but not the cache key make up. I am starting to understand your distaste to this feature more.
quentech@reddit
Failing would break shit that's expected to work. An implementation would have to be crazy to do that, and if they do no one will use it if they have any choice.
gjionergqwebrlkbjg@reddit
Why not specify it though? It's one sentence. Failing to determine or parse the format, the body should be treated as stream of bytes. (I guess this is ambiguous too in a way, but better than nothing).
modeless@reddit
This seems like a bad idea? Random caches are going to cache these responses by introspecting the query and discarding anything they deem "insignificant" by their own judgement? Sounds like a recipe for difficult to debug caching issues.
rooktakesqueen@reddit
It just means if I make a request for
/api/posts
with content-typeapplication/json
and the body{"after":123, "limit":10, "foo":"bar"}
and the service I'm querying knows that onlyafter
andlimit
are meaningful for this endpoint, it can removefoo
while normalizing. Thus, I will get the cached results for{"after":123, "limit":10}
.Your caching layer isn't going to make that decision on its own, whoever is defining the API needs to
Vidyogamasta@reddit
I think it's more like-
If you have one request with
and one request as
the whitespace will result in technically different strings. "Normalizing" implies turning them into literally the same string value for comparison, even if they came in slightly different, as long as they semantically mean the same thing.
Sure, that could also mean discarding irrelevant fields, but I think that goes beyond the most basic understanding of normalization.
quentech@reddit
That is not what that means.
What it does mean is, for example, is removing extraneous whitespace when it doesn't change the meaning of the content according to that content's rules (JSON, XML, etc.)
For JSON I expect that would also mean the order of keys is considered irrelevant and they will be sorted before hashing.
forgottenHedgehog@reddit
But can or renifer "key": null? IMO it leaves too much to interpretation.
scruffles360@reddit
Sounds like that should be refined before approval, but I feel like the intention is useful. For example all graphql queries could use this method making them catchable without extra frameworks.
DmitriRussian@reddit
Why is it bad? If you know what the structure of the content is, you can normalize well.
If you append a bunch of crap at the end of the query you could keep busting the cache, which is horrible.
shgysk8zer0@reddit
I haven't the time to read it now. Does anyone know if it supports multipart form data or just URL encoding?
Smooth_Detective@reddit
Finally GraphQL stans will stop sending post requests.
cosmic-parsley@reddit
Thank fuck, lack of caching has always been one of the biggest drawbacks of GQL.
ICanHazTehCookie@reddit
It's available, just implemented at the GQL server and client layers rather than HTTP. Not that that's better. But I don't think HTTP caching could fulfill all the same use cases. For example your query can hit the cache if the data it requests has already been cached from other queries. And updating data in the cache will automagically reflect in all queries that read that section.
trevg_123@reddit
I don’t see it mentioned in the doc but I believe this should mean the body can be encrypted.
This is pretty notable because GET URL strings are plaintext and can be seen by everybody that the request passes through, hence why sensitive information should only be POSTed. So if QUERY provides a canonical way to keep GET-like requests protected while allowing for caching (post-TLS of course) and significantly longer bodies, that is a great win.
Anybody else ever struggle with how arrays and dictionaries get serialized to URL parameters? And then you need to just do things manually because your backend and frontend libraries have different ideas about how it should be done? And then you spend way more time than necessary debugging something because the filters in the URL string aren’t human readable? Yeah, me too.
Pls merge.
jkrejcha3@reddit
It's worth noting that POST data is not much different in this regard, that's why we use TLS at all (barring like I guess
?password=hunter2
showing up in someone's browser history), since it encrypts the URL (except domain name) and all of the other parts of a request in transit.FabianPaus@reddit
Sounds great! Does anybody know whether we can use the QUERY method without any changes in the infrastructure? Or is this something that needs to be adopted over many years in different infrastructure components?
Atulin@reddit
Depends. Technically, you could make anything listen for
BUNGA
method requests, and similarly send aBUNGA
request from mostly anywhere.If it's calling a plain ASP.NET Core API with
fetch()
? Changes should be minimal. If you have a reverse proxy, an API gateway, the FORTRAN client uses some weird library to send requests and is hidden behind a proxy... you'll have some work to do.NoInkling@reddit
We're gonna be back to putting a
_method
parameter or header in POST requests, just like what happened with PATCH.anengineerandacat@reddit
Really depends on the infrastructure... that said for my organization since it'll likely be an unknown HTTP method it'll get blocked by our firewall or the edge routing won't map it correctly to our application stack.
It'll be a few years I suspect before we can reliably use it in production but there are definitely a lot of cases for it (was literally have a discussion with a coworker a few weeks back about why a team was using a POST instead of a GET for a search query).
Our org guidelines generally indicate that GET's should not be used when sensitive information is concerned or PII information has to be passed in, mostly because the path and relevant query parameters will often show up in logs whereas the body-content of POST's will not so there is a risk that a data-leak could compromise the business.
So we send such requests down as POST's typically even though it's not exactly the proper usage of it.
bwainfweeze@reddit
A brief scan did not turn up an issue nor a PR for this in the nginx GitHub project.
gjionergqwebrlkbjg@reddit
PATCH is from 2010 and there are still cases where I've been asked for a fallback because it's not supported everywhere.
PeacefulHavoc@reddit
It shouldn't take long. Many web frameworks handle methods as strings, and the ones who don't should be able to update quickly. CDNs, API gateways and proxies may block or fail with unknown methods, but even in the worst case scenario it should be a quick fix. The rest of the infrastructure should not be able to see which method you're using (because of TLS).
lmaydev@reddit
It totally depends on the software you're using.
For example you can easily implement this now in aspnetcore by creating a few custom attributes.
But it will break swashbuckle as they have a hard coded list of verbs.
So it just comes down to implementation.
DrBix@reddit
About damned time!
Illustrious_Dark9449@reddit
Adding a new HTTP Method, have we ever done this before? I can only imagine a very long process for all the load balances and web proxies (IIS, Nginx, Apache) to start supporting this on the server-side, client-wise it would be relatively easy.
For practical purposes there is no benefit to this besides the semantics - also GET requests with a Body payload can be made provided the client and server supports that madness!
JasonLovesDoggo@reddit
PATCH was added in 2010
Illustrious_Dark9449@reddit
Yeah heard about that one, haven’t used it or seen any APIs utilising it yet - might be my industry only
jasie3k@reddit
It's pretty handy with Json Patch spec, which allows you to send only partial updates that can fully modify the resource and be stored and replayed with event sourcing.
JasonLovesDoggo@reddit
The best example that I I've used it for was my implementation of the TUS protocol (resumable file uploads) which relies heavily on it.
pretzelnecklace@reddit
Publish and immediately CORS safe list the verb.
bareweb@reddit
Think I’ll keep moving graphql-wards
bwainfweeze@reddit
I don’t see why the two would be mutually exclusive.
And neither of them seem to solve the problem of canonicalizing the params so that multiple query builders generate the same cache key.
bareweb@reddit
On the first point I suggest it’s just workload to support two paradigms for essentially the same use- querying. I’d guess some data is more suited to reasoning about as a graph than others.
On the second point I’m totally in agreement.
Snoo_57113@reddit
Nice!, another method to disable after the next security audit.
shoot_your_eye_out@reddit
This will really help with RESTful design a lot. QUERY api/v1/widgets makes it really clear what that api is doing. I like it.