7 ms·
Making GET requests have bodies as the norm would also handle this
by chronicler 10mo ago
Making GET requests have bodies as the norm would also handle this
- platzhirsch 10mo agoI might be misunderstanding something, but it seems the issue isn't really about whether GET can technically carry a body. The deeper concern is that HTTP methods have specific meanings, and mixing those signals can causes confusion and it's nice to have this semantic separation.
- Veserv 10mo agoThe problem is that they are not enforced. You can already have GET requests that modify state even though they are not supposed to. What you are actually doing when making a specific kind of request is assuming the actual properties match the documented properties and acting accordingly. A QUERY seems to be no more than a POST that documents it is idempotent. Furthermore, you should only QUERY a resource that has advertised it is idempotent via the “Accept-Query” header. You might as well name that the “Idempotent-Post” header and then you just issue a POST; exactly the same information and properties were expressed and you do not need a new request type to support it.
- happytoexplain 10mo agoI'm confused - wouldn't idempotent POST be PUT? Isn't the proposed QUERY for fetching semantics?
- Veserv 10mo agoThe existing mechanism to get QUERY semantics is a POST that encodes the “fetch parameters” in the body and the response contains the fetched values. You then out-of-band document that this specific use of a fetching POST is idempotent. This is literally expressed in the document in section 1: Introduction. They just want to take that POST request and replace the word POST with QUERY which also means the server is intended to assure the request is idempotent instead of needing that documented out-of-band.
- johncolanduoni 10mo agoFor some reason the RFC focuses on idempotency, but then says it's explicitly intended for enabling caching semantics. Caching a query that mutates visible state doesn't really make sense, and like you point out if you just want idempotent modifications PUT already has the relevant semantics. I guess we haven't learned our lesson from making the original HTTP semantics super squishy.
- dragonwriter 10mo ago> For some reason the RFC focuses on idempotency, It focuses on a bit more on safety, which is why every mention of it the proposed method having the "idempotent" property is immediately preceded (in most cases in the same sentence) by description of it having the "safe" property.
- pcthrowaway 10mo agoI think the idea is that POST creates a record (and in theory fails if that record already exists). I guess the commenter above is saying that if you inverted that (fail when the record doesn't exist, return the record if it does) it would be similar to QUERY? Not sure if I agree with that, but PUT's return semantics are a bit vague.. it often returns partial or combined records, or just a 200 OK (with or without a response body), or 204 No Content for unchanged records (with or without a response body) It's clear what POST returns, so... perhaps QUERY is more similar to it in that sense?
- LoganDark 10mo agoPUT is the idempotent one. POST typically performs an action; PUT just creates-or-updates.
- johncolanduoni 10mo agoWhatever the original intent was, POST definitely does not return a new record consistently in most actual APIs. It's frequently used for actions that don't conceptually create anything at all.
- Veserv 10mo agoNo, I was referencing the example in the article in literally the very first section showing and explaining how POST endpoints are used for fetching data when GET endpoints are too limited. This is literally their motivating impetus for the QUERY request type. When considered abstractly, POST is just a request body and a response body. This is obviously powerful enough to define any behavior you want; it is just a channel flowing a nearly arbitrary amount of opaque data between the client and server. However, this kind of sucks because it does not define or constrain the behavior of the client or the server. QUERY says that the server is intended to interpret the request body as fetch parameters and return a response body as the fetched data, and further guarantee that the fetch is safe/idempotent. This is very useful. My disagreement is that there is no good reason for the client request format to care. You should “POST” to a “QUERY” endpoint. The fact that this endpoint guarantees QUERY behavior is just part of the documented server interface in the same way that certain endpoints may not support PUT. This is a server constraint, not a client constraint so should not change the client transport format. Requiring a new Client request type to agree with a new Server endpoint type is just unnecessary and mixes up server versus client responsibility and interface design.
- deleted 10mo ago[deleted]
- dragonwriter 10mo agoEssentially correct, QUERY is safe, like GET, not merely idempotent, like PUT. Safety implies idempotence, but not vice versa.
- simonkagedal 10mo agoDoes “safe” here mean just “non-mutating”?
- dragonwriter 10mo agoNo, it doesn't just mean that (it does mean non-mutating from the point of view of the client and in regard to the target resource, but the essential meaning involves more than that and it is more subtle than simply “non-mutating”.) The specific definition is in the HTTP spec, and I don't think I can describe it more concisely without losing important information necessary for really understanding it. https://www.rfc-editor.org/rfc/rfc9110#section-9.2.1 https://www.rfc-editor.org/rfc/rfc9110#section-9.2.1
- paulddraper 10mo agoYes.
- cortesoft 10mo agoIt would be pretty impossible to actually ‘enforce’ that GETs don’t modify state. I am not sure if I would call the lack of enforcement a problem when it is more a simple fact about distributed systems; no specification can enforce what a service does outside of the what is returned in a response.
- Veserv 10mo agoThat is exactly my point. There is no reason to syntactically distinguish what is semantically non-distinguishable. The interpretation of a request is up to the server. There is no reason for the client to syntactically distinguish that the request body is for a POST vs QUERY; the request parameters and response have the same shape with the same serialization format. However, on the other side, a server does control interpretation, so it is responsible for documenting and enforcing how it will interpret. QUERY semantics vs generic POST semantics is a receive/server-side decision and thus should not be a syntactic element of client requests, merely a server description of endpoint semantics (“QUERY endpoint” meaning shorthand for POST endpoint with query semantics). edit: Thinking about it some more, there is one possible semantic difference which is that a transparent caching layer could use a syntactically different POST (i.e. QUERY) to know it should be allowed to cache the request-response. I do not know enough about caching layers to know how exactly they make fill/eviction choices to know if that is important.
- cortesoft 10mo ago> There is no reason to syntactically distinguish what is semantically non-distinguishable. The point is to have a standard, so you can more easily learn what an API is doing instead of having to start from scratch every time.
- notatoad 10mo agoHTTP semantics aren’t hard enforced but that only means something if you always control the client, server, and all the middle layers like proxies or CDNs that your traffic flows over. Your GET request can modify state. But if your request exceeds a browser’s timeout threshold, the browser will retry it. And then you get to spend a few days debugging why a certain notification is always getting sent three times (ask me how I know this) Similarly, you can put a body on your GET request in curl. But a browser can’t. And if you need to move your server behind cloudflare one day, that body is gonna get dropped.
- locknitpicker 10mo ago> A QUERY seems to be no more than a POST that documents it is idempotent. This is false. By design QUERY is both safe and idempotent. In the context of HTTP, safe means "read-only", whereas idempotent means that a method does not introduce changes on the server, and thus many requests have the same effect of posting a single request. The fact that the semantics of an operation is deemed safe has far-reaching implications in the design of any participant of a HTTP request, including firewalls, load balancers, proxies. > You might as well name that the “Idempotent-Post” header and then you just issue a POST; This is outright wrong, and completely ignores the semantics of a POST request. POST requests by design are neither safe not idempotent. You do not change that with random request headers.
- Veserv 10mo ago> POST requests by design are neither safe not idempotent. Outright wrong. You are allowed to handle POST requests in a safe and idempotent way. In fact, the existing usage of POST to query, the literal impetus for this proposal, has exactly that behavior. What you are not allowed to do is assume that any arbitrary POST request is safe and idempotent. Only a endpoint that is documented to support POST and that is documented to be idempotent and safe should be sent a POST with request body and expect a response body and be idempotent and safe. In comparison, only a endpoint that is documented to support QUERY (which implicitly is documented to be idempotent and safe) should be sent a QUERY with request body and expect a response body and be idempotent and safe. Do you not see how similar those two are? In fact, you could trivially make every endpoint that handles QUERY just do the same thing if it gets a POST. So why should the client have to care what request type it sends? Why make a new request type? Of course we should want to define a standardized QUERY server endpoint behavior and document whether a server endpoint has QUERY behavior on POST; that is valuable, but that should be left distinct from the client protocol and constraints. The only benefit I can see for the client to distinguish QUERY from POST is that it allows intermediate layers to know the request is expected to be idempotent and safe on the incoming edge. The outgoing edge is not benefitted because the server can easily tag things appropriately. I guess a cache can use that information to only begin allocating a cache entry if the client attempts a QUERY thus saving it from tentatively recording all requests on the chance that the server will say that the actual request that occurred is safe? And that is assuming that the cache does not coordinate with the server to just pre-know what endpoints are safe and idempotent. In that case all the cache would need to do is parse the location to verify if it matches a safe endpoint. So your benefit of adding a new request type is you get to “unga-bunga is QUERY” instead of doing some parsing and matching overhead. Seems like a weak benefit relative to the benefits of a simpler and more uniform client protocol.
- cortesoft 10mo agoIf you look at the summary table, the only difference between a GET and a QUERY is that the query can have a body. Other than that, they have the exact same characteristics and purpose, so there isn’t really a need to semantically separate them.
- locknitpicker 10mo ago> If you look at the summary table, the only difference between a GET and a QUERY is that the query can have a body. Other than that, they have the exact same characteristics and purpose, so there isn’t really a need to semantically separate them. This is outright false. RFC9110, which clarifies semantics of things like GET requests, is clear on how GET requests should not have request bodies because it both poses security issues and breaks how the web works. Just because your homemade HTTP API expects a GET request packs a request body, that does not mean any of the servers it hits between your client and your server will. Think about proxies, API gateways, load balancers, firewalls, etc. Some cloud providers outright strip request bodies from requests. The internet should not break just because someone didn't bothered to learn how HTTP works. The wise course of action is to create a new method with specific semantics that are clear and actionable without breaking the world.
- cortesoft 10mo agoI think you are confusing what I am saying. I am saying the rest of the semantics are the same, other than the body. If we are creating a new HTTP spec, we could give GET and QUERY be the same because they serve the same semantic purpose. Obviously you can’t just start putting bodies in GET requests, because it breaks the current spec.
- locknitpicker 10mo ago> I think you are confusing what I am saying. I am saying the rest of the semantics are the same, other than the body. This is fundamentally wrong. The semantics are not the same, regardless of whether there's even a request body or not. The semantics are completely different. One is safe and idempotent, whereas the other is neither safe nor idempotent. The presence of a body doesn't even register as a factor. > If we are creating a new HTTP spec Also wrong. It's all about specifying another HTTP verb. HTTP is already specified to support other verbs. > we could give GET and QUERY be the same because they serve the same semantic purpose. QUERY is a GET that is designed to pass query parameters in request bodies, which GET explicitly does not support. They are separate operations which just so happen to be both safe and idempotent.
- badbotty 10mo agoGET is a keep things simple stupid approach to caching. The URL is the cache key plus any headers touched by the vary header. Adding the requirement to vary on the body and understand the body content semantics brings in a whole lot of complexity that GET avoids.
- vlovich123 10mo agoI suspect the challenge would be all the middleware that assumes that get never had a body.
- ashu1461 10mo agoor get requests with query params already handles this in majority of the cases, unless the query size is too big (which ideally should not be the case since in the end it is a get request)
- bhawks 10mo agoThat ship sailed decades ago. Too much software and middleware expects GET to not have a body and who knows how itll break when you start sending one. Obviously you can do it today and it might work and then randomly break when the code between client and server changes. Adding a new http method is the only way to support something like this safely. If something in between doesn't know what to do with QUERY it can just respond with a 501. Fun fact - GET and HEAD are the only required methods one needs to implement to be an http server. It is a pretty low bar :)
- chronicler 10mo agoyou're right
- locknitpicker 10mo ago> Making GET requests have bodies as the norm would also handle this The RFC is pretty clear that no participant in a HTTP request is expected to even allow a GET request through. RFC 9110 even states quite clearly that it's even a potential request smuggling attack. Some major cloud providers provide API Gateway implementations that outright strip request bodies from GET requests. I think you are missing the whole point of proposing a new HTTP verb. Changing the semantics of a GET request is not an option because of both the security risks it presents and the fact that the infrastructure of the whole internet either is designed to reject these requests or outright breaks. See how GET requests are cached and how cache implementations don't discriminate GET requests based on it's request body.
- vbezhenar 10mo agoYeah, it works already, this RFC makes no sense.