[HN Gopher] The HTTP Query Method
___________________________________________________________________
The HTTP Query Method
Author : Ivoah
Score : 253 points
Date : 2025-11-26 12:57 UTC (4 days ago)
(HTM) web link (www.ietf.org)
(TXT) w3m dump (www.ietf.org)
| chronicler wrote:
| Making GET requests have bodies as the norm would also handle
| this
| platzhirsch wrote:
| I 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 wrote:
| The 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 wrote:
| I'm confused - wouldn't idempotent POST be PUT? Isn't the
| proposed QUERY for fetching semantics?
| Veserv wrote:
| The 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 wrote:
| For 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 wrote:
| > 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 wrote:
| I 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?
| johncolanduoni wrote:
| Whatever 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.
| LoganDark wrote:
| PUT is the idempotent one. POST typically performs an
| action; PUT just creates-or-updates.
| Veserv wrote:
| No, 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.
| happytoexplain wrote:
| I'm not following how this is different from not even
| using HTTP verbs. We didn't define them because it's the
| only possible way to declare client intent. They're
| cognitively useful for setting expectations,
| organization, announcing abilities, separation of
| concerns, etc. The fact that POST is today sometimes used
| in practice as a safe+idempotent query (i.e. a GET with a
| body) seems like the black sheep violating those useful
| qualities.
| Veserv wrote:
| Client _intent_ is distinct from server _interpretation_.
| Distinguishing these is important when defining protocols
| /interfaces.
|
| A client can blindly PUT a endpoint that does not support
| PUT, only GET. In the cold connection case where does
| this fail? The client succeeds at serializing the
| message, the client succeeds at sending it, the message
| gets successfully received, and only upon examining the
| message itself does the server know it should not follow
| the client intent. This is the same behavior as if the
| client sent garbled nonsense.
|
| The key here is that it is the server demanding certain
| message structures. The client is free to send whatever,
| it just only succeeds if it sends something the server
| will accept. The server distinguishes, but to the client
| it is no different from sending any other opaque blob of
| data. This is thus just a server-constraint, the endpoint
| is GET-only. To use this website/HTTP interface, the
| client needs to know that.
|
| It will need to know to format the message correctly, but
| that derives from knowledge of the documented server
| interface. If you had just a direct connection with no
| intermediary participants, then you could trivially swap
| out HTTP for any other transport protocol without a loss
| of functionality or behavior. That points to there being
| no reason to syntactically distinguish on the client to
| server leg of the transport protocol. However, you still
| have GET endpoint behavior since that is actually
| preserved across transport changes, so that is the
| important class of behavior to define.
|
| The opposing point here is that if you do have
| intermediarys then they may care about the message format
| and you may need to syntactically distinguish them. I
| suspect this is less beneficial than a simpler and more
| flexible, yet precise transport format.
|
| Basically, we should prefer simple, flexible transport
| formats and push interpretation (and thus behavior) out
| to the endpoints which actually have enough context to
| know the true properties of what they are doing.
| ahtihn wrote:
| > The fact that this endpoint guarantees QUERY behavior
| is just part of the documented server interface
|
| And how do you communicate this behavior to the client
| (and any other infrastructure in-between) in a machine-
| readable way?
| dragonwriter wrote:
| Essentially correct, QUERY is _safe_ , like GET, not
| merely _idempotent_ , like PUT. Safety implies
| idempotence, but not vice versa.
| simonkagedal wrote:
| Does "safe" here mean just "non-mutating"?
| dragonwriter wrote:
| No, 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
| paulddraper wrote:
| Yes.
| cortesoft wrote:
| It 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 wrote:
| That 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 wrote:
| > 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 wrote:
| HTTP 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 wrote:
| > 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 wrote:
| > 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.
| locknitpicker wrote:
| > Outright wrong. You are allowed to handle POST requests
| in a safe and idempotent way.
|
| You clearly have no idea about what you are discussing.
| The definition of HTTP verb semantics clearly defines the
| concept of safe and idempotent methods. You should
| seriously learn about the concept before commenting on
| discussions on semantics. If that's too much work, RFC
| 9110 clearly and unambiguously states that only the GET,
| HEAD, OPTIONS, and TRACE methods are defined to be safe.
| Not POST.
|
| It's completely irrelevant if you somehow implemented a
| POST method that neither changes the state of the server
| nor returns the same response whether you invoke it once
| or many times. All participants in a HTTP request adhere
| to HTTP's semantics, and thus POST requests are treated
| as unsafe and non-idempotent by all participants. That
| affects things like caching, firewalls, even security
| scanners. The HTTP specs determine how all participants
| handle requests, not just the weekend warrior stuff
| someone chose to write in a weekend.
| Veserv wrote:
| You clearly do not understand protocol/interface design.
|
| The behavior and constraints of a generic interface is a
| lower bound on the behavior and upper bound on the
| assumable constraints by all direct participants when
| handled in general. This is POST in general. This is the
| weakest usage.
|
| A specialized interface may enhance behavior or tighten
| constraints further. This is actually using POST to
| achieve some website-specific end. You can not actually
| use a website/reason about usage in anything other than a
| read-only fashion without knowing what the endpoints
| actually do and when to issue requests at which endpoint.
|
| Indirect or intermediary participants should maintain
| behavior and constraints at the lower of the level of
| specialization they are aware of and the participants
| they are between. If you are designing a generic
| intermediary, then you do not have access to or knowledge
| about the specialized interfaces, so are less able to
| leverage specialized behavior or constraints. In HTTP,
| various headers serve the purpose of communicating
| various classes of common interface specializations so
| someone can write more powerful generic intermediarys.
| However, you could always write a specific intermediary
| or handler if you control portions of the chain, which
| people do all the time.
|
| This applies across all classes of software interfaces
| and protocols not just websites using HTTP. But I guess
| HTTP is just such a special snowflake that it is beyond
| learning good practice from other fields.
| cortesoft wrote:
| 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.
| locknitpicker wrote:
| > 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 wrote:
| I 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.
| badbotty wrote:
| GET 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 wrote:
| I suspect the challenge would be all the middleware that
| assumes that get never had a body.
| ashu1461 wrote:
| or 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 wrote:
| That 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 wrote:
| you're right
| locknitpicker wrote:
| > 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 wrote:
| Yeah, it works already, this RFC makes no sense.
| fijiaarone wrote:
| We already have POST, PUT, and PATCH that do the exact same
| thing. Why not have another version of GET that looks the same as
| POST and is subject to personal interpretation.
|
| FYI: QUERY is for GET requests where the query string make the
| URL too long. It does this by sending a body like POST.
|
| In the past, POST meant you were sending a body, and GET meant
| you received a body. And the people got religious about a
| pseudoacronym called REST.
| johncolanduoni wrote:
| Apart from the sectarian conflicts about what REST means,
| having a HTTP method that proxies can cache like a GET but
| allows bodies is pretty useful from a purely practical
| standpoint. You can do this with POST, but it requires proxy-
| specific configuration.
| cortesoft wrote:
| The point of the HTTP verbs is to communicate expected
| behavior. While a server could treat POST, PUT, and PATCH the
| same, the point of having the verbs at all is to give a
| standard way to signal clients what is going to happen. While a
| server can ignore the expectation, it doesn't mean the
| expectation isn't valuable; it allows conforming implementers
| to communicate what is happening using standard language.
| newscracker wrote:
| A couple of quick observations and comments after skimming
| through this (some of these are mentioned or hinted at in the
| RFC).
|
| With HTTPS used almost everywhere, using this QUERY method (when
| standardized) could prevent bookmarking specific "GET" URLs if
| the developers thoughtlessly replace GET everywhere with QUERY.
|
| One of the advantages of GET is the direct visibility, which
| makes modifications simple and easy for almost anyone (end users,
| testers, etc.).
|
| The larger question I have is who will choose to adopt it sooner,
| with web servers, web application frameworks and web browsers in
| the mix.
| arp242 wrote:
| The situations where I've wished for GET to be able to have a
| (typically JSON) body were all in situations where the request
| isn't "user visible" in the first place. That is: API calls,
| SPA apps, ajax requests, that sort of thing. Not something
| people are really supposed to bookmark or call directly.
|
| If today you're doing some JS-fu to make an ajax GET request
| then you already need to do something to have permalinks (if
| desired).
|
| Completely worth bringing up and thinking about, but unless I'm
| missing something I don't think a QUERY verb will change all
| that much here?
| flakes wrote:
| > unless I'm missing something I don't think a QUERY verb
| will change all that much here?
|
| The semantics are important. GET APIs are expected to be
| safe, idempotent, and cache-friendly. When you are unable to
| use GET for technical reasons and move to POST, suddenly none
| of the infrastructure (like routers, gateways, or generic
| http libs) can make these assumptions about your API. For
| example, many tools will not attempt to put retry logic
| around POST calls, because they cannot be sure that retrying
| is safe.
|
| Having the QUERY verb allows us to overcome the technical
| limitations of GET without having to drop the safety
| expectations.
| badbotty wrote:
| I like the safety aspect of QUERY. Having CDNs cache based
| off the semantics of the content might be a hard ask. I
| wonder if this might lead to a standards based query
| language being designed and a push for CDNs to support it.
| Otherwise you probably need to implement your own edge
| processing of the request and cache handling for any
| content type you care to handle.
| arp242 wrote:
| Yes, I understand that. I'm just commenting on the
| "bookmarkable" aspect here, obviously.
| vbezhenar wrote:
| You can just use body with GET. QUERY is redundant.
| flakes wrote:
| You can, and that is mentioned in RFC 9110... along with
| the cons for doing so.
|
| > Although request message framing is independent of the
| method used, content received in a GET request has no
| generally defined semantics, cannot alter the meaning or
| target of the request, and might lead some
| implementations to reject the request and close the
| connection because of its potential as a request
| smuggling attack (Section 11.2 of [HTTP/1.1]). 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. An origin
| server SHOULD NOT rely on private agreements to receive
| content, since participants in HTTP communication are
| often unaware of intermediaries along the request chain.
|
| QUERY is a new option to help avoid some of those
| downsides.
|
| https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.1
| locknitpicker wrote:
| > With HTTPS used almost everywhere, using this QUERY method
| (when standardized) could prevent bookmarking specific "GET"
| URLs if the developers thoughtlessly replace GET everywhere
| with QUERY.
|
| You're bothering about non-issues. Bookmarks support GET
| requests, not any other verb. Like it has always been, if you
| need to support bookmarks then you implement bookmarkeable URLs
| to be used with GET requests.
|
| Also, your far-fetched example failed to account for the fact
| that nowadays POST requests are used to query.
| jchw wrote:
| Yes! This sounds like a great idea to me. It does have some
| trade-offs, but I think we would've been better off with this
| than ever having put queries in the URL in the first place.
| Rather, if it made enough sense to have some data in the URL
| itself, it would be better if it could actually be _in the path_
| , to distinguish it as a distinct resource. I think there are
| many reasons why this didn't work out that way but I also think
| those reasons are mostly historical. I would prefer things like
| /map/<lat>/<long>/, for example. I don't want to go as far as to
| say that query parameters were entirely a mistake, but there's
| nothing they do that couldn't be done otherwise, they just offer
| a convenient place to delineate unstructured data in a URL that
| you could then copy around. Sometimes moving that to the path
| would be awkward (unstructured path elements does exist on the
| web, but it's weird to do) but often times it would just be
| better to not have it at all. Don't need UTM codes in my URLs in
| the first place, and I don't think every single parameter on the
| page should be in the URL. (If you really wanted to pass someone
| a saved search full of complex queries, it would be less
| cumbersome to have a specific URL for saved searches anyhow, in
| my opinion.)
|
| Obviously query parameters are not going anywhere, but if this
| achieves enough adoption there is a future down the road where we
| can stop using POST for any query that wants a payload, without
| needing to change every single HTTP client in the world. (Many of
| them can already understand custom methods and treat them
| basically like posts.)
| stephenr wrote:
| > I would prefer things like /map/<lat>/<long>/, for example.
|
| PathInfo is a thing you can absolutely use.
| jchw wrote:
| Most web application servers have already equipped to be able
| to easily parse parameters out of the URL path for many
| years, of course, it's definitely nothing new, it's just that
| historically, people reached for URL query parameters for
| this sort of thing. After all, making a request with query
| parameters is basically built into the browser; you can do it
| with <form> and anchor links with no JS needed.
|
| Presumably, because of that, many pages will continue to use
| query parameters for the foreseeable future. I think that's
| fine, but at least for APIs, the QUERY method could
| eventually be a very nice thing to have.
| llIIllIIllIIl wrote:
| How does one share the search results with the url to the page
| with this query method?
| gridlocdev wrote:
| I can't wait for QUERY to become an official RFC.
|
| It's felt quite awkward to tiptoe around the existing spec when
| building features that retrieve data; we've had to either use
| POST to keep sensitive filter criteria out of http logs or just
| create a usually massive URL-encoded query string.
| resonious wrote:
| Very timely as I just recently ended up with a URL query string
| so big that CloudFront rejected the request before it even hit
| my server.. Ended up switching that endpoint to POST. Would've
| liked QUERY for that!
| bruce511 wrote:
| I have come across systems that use GET but with a payload
| like POST.
|
| This allows the GET to bypass the 4k URL limit.
|
| It's not a common pattern, and QUERY is a nice way to
| differentiate it (and, I suspect will be more compatible with
| Middleware).
|
| I have a suspicion that quite a few servers support this
| pattern (as does my own) but not many programmers are aware
| of it, so it's very infrequently used.
| LudwigNagasena wrote:
| Sending a GET request with a body is just asking for all
| sorts of weird caching and processing issues.
| hnlmorg wrote:
| I get the GPs suggestion is non-conventional but I don't
| see why it would cause caching issues.
|
| If you're sending over TLS (and there's little reason why
| you shouldn't these day) then you can limit these caching
| issues to the user agent and infra you host.
|
| Caching is also generally managed via HTTP headers, and
| you also have control over them.
|
| Processing might be a bigger issue, but again, it's just
| any hosting infrastructure you need to be concerned about
| and you have ownership over those.
|
| I'd imagine using this hack would make debugging harder.
| Likewise for using any off-the-shelf frameworks that
| expect things to confirm to a Swagger/OpenAPI definition.
|
| Supplementing query strings with HTTP headers might be a
| more reliable interim hack. But there's definitely not a
| perfect solution here.
| bruce511 wrote:
| To be clear, it's less of a "suggestion" and more of a
| report of something I've come across in the wild.
|
| And as much as it may disregard the RFC, that's not a
| convincing argument for the customer who is looking to
| interact with a specific server that requires it.
| LudwigNagasena wrote:
| Cache in web middleware like Apache or nginx by default
| ignores GET request body, which may lead to bugs and
| security vulnerabilities.
| hnlmorg wrote:
| But as I said, you control that infra.
|
| I don't think it's unreasonable to expect your sysadmins,
| devops, platform engineers, or whatever title you choose
| to give them, to set up these services correctly, given
| it's their job to do so and there's a plethora of
| security risks involved.
|
| If you can't trust them to do that little, then you're
| fuck regardless of whether you decide to send payloads as
| GET bodies.
|
| And there isn't any good reason not to contract pen
| testers to check over everything afterwards.
| LudwigNagasena wrote:
| > I don't think it's unreasonable to expect your
| sysadmins, devops, platform engineers, or whatever title
| you choose to give them, to set up these services
| correctly, given it's their job to do so and there's a
| plethora of security risks involved.
|
| Exactly, and the correct way to setup GET requests is to
| ignore their bodies for caching purposes because they
| aren't expected to exist: "content received in a GET
| request has no generally defined semantics, cannot alter
| the meaning or target of the request, and might lead some
| implementations to reject the request and close the
| connection because of its potential as a request
| smuggling attack" (RFC 9110)
|
| > And there isn't any good reason not to contract pen
| testers to check over everything afterwards.
|
| I am pretty sure our SecOps and Infra Ops and code
| standards committee will check it and declare that GET
| bodies is a hard no.
| hnlmorg wrote:
| > Exactly, and the correct way to setup GET requests is
| to ignore their bodies for caching purposes because they
| aren't expected to exist
|
| No. The correct way to set up this infra is the way that
| works for a particular problem while still being secure.
|
| If you're so inflexible as an engineer that you cannot
| set up caching correctly for a specific edge case because
| it breaks you're preferred assumptions, then you're not a
| very good engineer.
|
| > and might lead some implementations to reject the
| request and close the connection because of its potential
| as a request smuggling attack"
|
| Once again, you have control over the implementations you
| use in your infra.
|
| Also It's not a RSA if the request is supposed to contain
| a payload in the body.
|
| > I am pretty sure our SecOps and Infra Ops and code
| standards committee will check it and declare that GET
| bodies is a hard no.
|
| I wouldn't be so sure. I've worked with a plethora of
| different infosec folk from those who will mandate that
| PostgreSQL needs to use non-standard ports because of
| mandating strict compliance with NIST, even for low risk
| reports. To others that have been fine with some pretty
| massive deviations from traditionally recommended best
| practices.
|
| The good infosec guys, and good platform engineers too,
| don't look at things in black and white like you are.
| They build up a risk assessment and judge each deviation
| on its own merit. Thus GET body payloads might make sense
| in some specific scenarios.
|
| This doesn't mean that everyone should do it nor that
| it's a good idea outside of those niche circumstances.
| But it does mean that you shouldn't hold on to these
| rigid rules like gospel truths. Sometimes the most
| pragmatic solution is the unconditional one.
|
| That all said, I can't think of any specific circumstance
| where you'd want to do this kind of hack. But that
| doesn't mean that reasonable circumstances would never
| exist.
| LudwigNagasena wrote:
| There is no secure notion of "correctly" that goes both
| directly against specs and de facto standards. I am
| struggling to even imagine how one could make an L7
| balancer that should take into account possibilities that
| someone would go against HTTP spec and still get their
| request served securely and timely. I personally don't
| even know which L7 balancer my company uses and how it
| would cache GET requests with bodies, because I don't
| have to waste time on such things.
|
| Running PostgreSQL on any non-privileged port is a
| feature, not a deviation from a standard. If you want to
| run PostgreSQL on a port under 1024 now that would be
| security vulnerability as it requires root access.
|
| There is no reason to "build up a risk assessment and
| judge each deviation on its own merit" unless it is an
| unavoidable technical limitation. Just don't make your
| life harder for no reason.
| hnlmorg wrote:
| > There is no secure notion of "correctly" that goes both
| directly against specs and de facto standards.
|
| That's clearly not true. You're now just exaggerating to
| make a point.
|
| > I am struggling to even imagine how one could make an
| L7 balancer that should take into account possibilities
| that someone would go against HTTP spec and still get
| their request served securely and timely
|
| You don't need application-layer support to load balance
| HTTP traffic securely and timely.
|
| > Running PostgreSQL on any non-privileged port is a
| feature, not a deviation from a standard. If you want to
| run PostgreSQL on a port under 1024 now that would be
| security vulnerability as it requires root access.
|
| I didn't say PostgreSQL listening port was a standard. I
| was using that as an example to show the range of
| different risk appetites I've worked to.
|
| Though I would argue that PostgreSQL has a _de facto_
| standard port number. And thus by your own reasoning,
| running that on a different port would be "insecure" -
| which clearly is BS (as in this rebuttal). Hence why I
| called your "de facto" comment an exaggeration.
|
| > There is no reason to "build up a risk assessment and
| judge each deviation on its own merit" unless it is an
| unavoidable technical limitation.
|
| ...but we are talking about this as a theoretical,
| unavoidable technical limitation. At no point was anyone
| suggesting this should be the normal way to send GET
| requests.
|
| Hence why i said you're looking at this far too black and
| white.
|
| My point was just that it is technically possible when
| you said it wasn't. But "technically possible" !=
| "sensible idea under normal conditions"
| everforward wrote:
| I work as an SRE and would fight tooth and nail against
| this. Not because I can't do it, but because it's a
| terrible idea.
|
| For one, you're wrong about TLS meaning only your infra
| and the client matter. Some big corps install a root CA
| on everyone's laptop and MITM all HTTP/S traffic. The one
| I saw was Bluecoat, no idea if it follows your expected
| out-of-spec behavior or not.
|
| For two, this is likely to become incredibly limiting at
| some point and require a bunch of work to re-validate or
| re-implement. If you move to AWS, do ELBs support this?
| If security wants you to use Envoy for a service mesh, is
| it going to support this? I don't pick all the tools we
| use, so there's a good chance corporate mandates
| something incompatible with this.
|
| You would need very good answers to why this is the only
| solution and is a mandatory feature. Why can't we cache
| server side, or implement our own caching in the front
| end for POST requests? I can't think of any situations
| where I would rather maintain what is practically a very
| similar fork of HTTP than implement my own caching.
| hnlmorg wrote:
| > Not because I can't do it, but because it's a terrible
| idea.
|
| To be clear, I'm not advocating it as a solution either.
| I'm just saying all the arguments being made for why this
| wouldn't work are solvable. Just like you've said there
| that it's doable.
|
| > Some big corps install a root CA on everyone's laptop
| and MITM all HTTP/S traffic.
|
| I did actually consider this problem too but I've not
| seen this practice in a number of years now. Though that
| might be more luck on my part than a change in industry
| trends.
|
| > this is likely to become incredibly limiting at some
| point and require a bunch of work to re-validate or re-
| implement.
|
| I would imagine if you were forced into a position where
| you'd need to do this, you'd be able to address those
| underlying limitations when you come to the stage that
| you're re-implementing parts of the wider application.
|
| > If you move to AWS, do ELBs support this?
|
| Yes they do. I've actually had to solve similar problems
| quite a few times in AWS over the years when working on
| broadcast systems, and later, medical systems: UDP
| protocols, non-standard HTTP traffic, client
| certificates, etc. Usually, the answer is an NLB rather
| than ALB.
|
| > You would need very good answers to why this is the
| only solution and is a mandatory feature.
|
| Indeed
| locknitpicker wrote:
| > I have come across systems that use GET but with a
| payload like POST.
|
| I think that violates the HTTP spec. RFC 9110 is very clear
| that content sent in a GET request cannot be used.
|
| Even if both clients and servers are somehow implemented to
| ignore HTTP specs and still send and receive content in GET
| requests, the RFC specs are very clear that participants in
| HTTP connections, such as proxies, are not aware of this
| abuse and can and often do strip request bodies. These are
| not hypotheticals.
| virtue3 wrote:
| I think graphQL as a byproduct of some serious shenanigans.
|
| "Your GraphQL HTTP server must handle the HTTP POST method
| for query and mutation operations, and may also accept the
| GET method for query operations."
|
| Supporting body in the get request was an odd requirement
| for something I had to code up with another engineer.
| girvo wrote:
| And the whole GET/POST difference matters for GraphQL at
| scale: we saved a _truckload_ of money by switching our
| main GraphQL gateway requests to GET wherever possible.
| bostik wrote:
| Elasticsearch comes to mind.[0]
|
| The docs state that is query is in the URL parameters, that
| will be used.I remember that a few years back it wasn't as
| easy - you HAD to send the query in the GET requests body.
| (Or it could have been that I had a monster queries that
| didn't fit through the URL character limits.)
|
| 0: https://www.elastic.co/docs/api/doc/elasticsearch/operat
| ion/...
| jtbaker wrote:
| > you HAD to send the query in the GET requests body.
|
| I remember this pain, circa 2021 perhaps?
| akvadrako wrote:
| Servers can support it but not browsers.
| chrisandchris wrote:
| There's nothing holding you back implementing the QUERY method
| right now - HTTP methods are standardized, but not limited to
| the standard. Obsviously it depends how proxies/servers/etc.
| might handle uncommon methods.
| immibis wrote:
| But that's the point, isn't it? Browsers, proxies and servers
| always assume POST isn't idempotent. When the user presses F5
| the browser asks if they want to do the thing again. You
| can't prevent that without making it more complicated (e.g.
| send the request from JavaScript).
| locknitpicker wrote:
| > There's nothing holding you back implementing the QUERY
| method right now - HTTP methods are standardized, but not
| limited to the standard.
|
| I think this comment is terribly naive. Technically you can
| write your own service to support verbs like LOL or FUBAR,
| but in practice your service is not only expected to be
| broken when passing requests through other participants you
| do not control but also it requires far more development work
| to integrate with existing standards. Take for example CORS.
| If a HTTP method is not deemed safe then client requests need
| to go through the unsafe flow with preflight requests and the
| like. Forget support for caching too, and good luck having
| your requests pass through proxies.
|
| So what exactly did you achieved by using non-standard verbs?
|
| If you chose to go the ignorant backwards incompatible way,
| you are better off not using HTTP at all and just go with
| some random messaging/RPC protocol.
| nine_k wrote:
| I won't be so strict. Even though a homebrew implementation
| won't be widely interoperable, an experience of its active
| development and use in a limited environment (e.g. within a
| company) would be valuable both to inform the RFC and to
| serve an example implementation.
| carlosneves wrote:
| And oftentimes some endpoints simply hit the max URL length
| limit and need a proper body. I thought we ought to already be
| using this method. Seems quite fitting for fulfilling GETs with
| bodies.
| ahoka wrote:
| Maybe send the body in a close envelope as some software might
| also write the request body contents to disk or log it.
| hamasho wrote:
| First impression was "umm... I don't even use SEARCH yet." Then
| realize this is actually SEARCH method but renamed and more
| generalized.
| gbear605 wrote:
| At this point I'm infamous in my company for complaining about
| how something should have been done with a QUERY verb but it
| hasn't been approved yet.
|
| The cases tend to look like this: - An endpoint was implemented
| as a GET endpoint, since it's for getting data, with the search
| terms in the query parameters. The search term got too long,
| breaking a critical behavior in production environments. - An
| endpoint was implemented as a POST endpoint, despite it being an
| idempotent query for data, since the request body is too large to
| fit in query parameters. New employees repeatedly come in and are
| confused why it's not a GET endpoint, or why it doesn't modify
| anything.
| thayne wrote:
| Also cases where a GET makes more sense, but there is concern
| about sensitive data in query parameters getting exposed in
| logs, so POST is used instead.
| venturecruelty wrote:
| You can always configure your HTTP logger to not log query
| parameters.
| ghxst wrote:
| From a security perspective it is best to assume everything
| in a GET query is public, it's not always your server logs
| that you have to worry about, it could also be logs on the
| clients system (as an example).
| tempest_ wrote:
| A POST could be viewed as creating a "search" which, once given
| an ID could be retrieved later with a GET.
|
| I know this densest really work with ad-hock and cheap queries
| but it does for more expensive / report style ones.
| JodieBenitez wrote:
| And here I am, using JSON-RPC 1.0 over HTTP for internal APIs,
| skipping all these debates.
| idbehold wrote:
| You also miss out on standardized HTTP caching mechanisms
| since those don't work with POST requests.
| andyferris wrote:
| Does anyone know what blocks something like this being accepted?
| I've had my eye on this for ages and have had to work around its
| lack multiple times, so just curious what the hold up could be.
| 8organicbits wrote:
| You can check the mailing list for the current discussion.
|
| https://lists.w3.org/Archives/Public/ietf-http-wg/
|
| There's also some tracking on GitHub.
|
| https://github.com/httpwg/http-extensions/issues?q=label%3Aq...
| 8cvor6j844qw_d6 wrote:
| For the experienced devs. May I ask why would one use POST for
| everything?
|
| I encountered a codebase with only POST for all operations, given
| my lack of knowledge in this area, I am not sure why one would
| choose POST only over the standard set of GET, PUT, POST, DELETE,
| etc.
| julianlam wrote:
| If you encounter a shop that uses POST for everything then they
| are probably a shop that doesn't know that verbs other than GET
| and POST exist.
|
| ... and they don't use GET everywhere because one time Google
| scraped that endpoint and dropped the production database.
| nhumrich wrote:
| I prefer POST for everything. The main reason why is because
| HTTP verbs don't match cleanly to every operation. And it leads
| to a lot of bike shedding around the exceptions. POST for
| everything, on the other hand, forces you to put the "method"
| in the request outside of HTTP semantics, which allows you to
| "just use" whatever verb makes sense rather than trying to map
| it to the limited ones available.
| gaigalas wrote:
| GET: I want to see stuff.
|
| POST: I want to change stuff.
|
| I don't know how this style cannot match cleanly any
| architecture.
|
| It's not supposed to be a map to CRUD, it's a bunch of
| building blocks for manipulating state over a network.
| Zambyte wrote:
| What if the stuff you want to see can't be encoded in a
| URL?
| gaigalas wrote:
| I'm assuming the case here is lots of query params. Stuff
| like `?foo=bar&lorem=ipsum...`.
|
| Most likely, you would benefit from making a cirurgical
| mini-resource on the server.
|
| Introduce `/report/{id}`, and make it into a POST.
|
| The user POSTs to `/report`, and the answer is 201
| (Created) or 202 (Accepted), with a `Location:
| /report/123` (generated short id). The thing you changed
| on the server, is that now that long list have a short
| id. Just that.
|
| Then, the user `GET /report/123` (auto redirect). It all
| happens within the same socket (keep-alive) and it has
| almost zero overhead (one refresh without this probably
| has thousands of times more overhead than the redirect).
|
| By doing that, it seems that you are wasting stuff, but
| you're not.
|
| Now the user doesn't have to transfer huge amounts of
| query data when GETing the results again, cache layers
| will have an easier time, and you can even use that mini-
| resource as a shortcut to solve things like racing
| conditions (two users doing the same humongous query at
| the same time).
|
| Realistically, unless you're some query-by-image type of
| thing (trying to search images that match an existing
| one), you'll never actually have to face URL limits. If
| you are one of those cases, then you probably already
| have other architectural constraints that would justify
| introducing the extra intermediate resource.
| 8cvor6j844qw_d6 wrote:
| Hmm... sort of like an intermediate page?
|
| That would explain a some of the design decisions. I had
| to do work on a old codebase and am studying it.
|
| Thank you and the others too for the input.
| themafia wrote:
| PATCH: I want to change stuff.
| gaigalas wrote:
| PATCH: I want to change stuff in a predictable way.
|
| --
|
| PUT: I want to replace stuff.
|
| DELETE: I don't want anyone to GET that stuff anymore.
|
| HEAD: I want to peak at how stuff is shown.
|
| OPTIONS: I want to know what I can do with stuff.
|
| --
|
| COPY: I want to copy stuff (WebDav)
|
| MOVE: I want to move stuff (WebDav)
|
| MKCOL: I want a new sublevel of stuff (WebDav)
|
| PROPFIND: I want to list stuff (WebDav)
|
| PROPPATCH: I want to mass change stuff (WebDav)
|
| LOCK: I want to control who METHODs stuff.
|
| UNLOCK: I want to remove control over who METHODs stuff.
|
| --
|
| All of those are actually optional. It is okay to use
| POST[0]. GET and POST with proper hypermedia (media types
| and links) is all 99% of apps need.
|
| [0]: https://roy.gbiv.com/untangled/2009/it-is-okay-to-
| use-post
| LudwigNagasena wrote:
| Consistency, simplicity, RPC semantics.
| RedShift1 wrote:
| The default for GraphQL queries is POST so maybe they were
| using that.
| zvrba wrote:
| Because with POST you have a RPC (remote procedure call) with
| arbitrary semantics and HTTPS is just a convenient transport.
|
| That's also why I only use a couple of status codes: Ok,
| Created, NoContent, BadRequest, Forbidden, Unauthorized an
| InternalServerError (the latter two generated automatically by
| the framework).
|
| GET, PUT, DELTE, etc. seem to be tailored towards entities, but
| as soon as the endpoint is not an "entity", the semantics get
| vague and break down.
| iberator wrote:
| It was safer in some sense before TLS. No data in URL.
| leloctai wrote:
| As inefficient as encoding everything into the URI is, I really
| enjoy being able to bookmark and share specific filter
| configuration. More than one I've seen some sites with UI so bad,
| that manually editing the url is the easiest way to get it to do
| what i want.
| itopaloglu83 wrote:
| Okay, I'm a little confused, the HTTP already supports 8000
| octets, and some are having issues because they have too many
| filters?
|
| Looking at the logs I see that most of the long URI traffic is
| due to UTM and other tracking related codes, which are mainly a
| way to work around 3rd party cookie blocks.
|
| I must be missing something, because it sounds like to goal is
| to have longer URI without the need for encoding URL
| parameters, but without using POST.
| paulddraper wrote:
| Yes.
|
| Suppose you have one filter but it has a few hundred twenty-
| character values.
| nrhrjrjrjtntbt wrote:
| Cough Splunk
|
| Also another case is as a dev you are dealing with guids all
| day and it can be fast to swap guids around in the browser bar
| vs. ui steps.
| locknitpicker wrote:
| > As inefficient as encoding everything into the URI is, I
| really enjoy being able to bookmark and share specific filter
| configuration.
|
| That is perfectly fine. Sites that support path- and query-
| based filters are already designed specifically to have filters
| embedded in links, which are GET requests. The QUERY method is
| something more in line of a GraphQL style of query that isn't
| held back by the semantics of a POST request. GraphQL didn't
| invented this API style. If GraphQL-style APIs didn't affected
| how WebApps implemented links, QUERY methods won't.
| clickety_clack wrote:
| It's rare that I have a project that justifies the full DDD
| treatment, but one of the great ideas from it that stuck with me
| was command/query separation, where you separate out queries,
| which can be mangled agglomerations of objects for reporting and
| lists, from commands, which drive your business logic.
|
| I love the idea of a separate verb. It always felt like get is
| just not quite enough.
| tough wrote:
| CQRS
| slim wrote:
| I anticipate this will be used by UI frameworks to transmit a
| very long list of item ids selected by the user using check
| boxes. Which will cause suffering to the backend devs dealing
| with relational databases
| culi wrote:
| What do you mean by that? What's wrong with a simple
| WHERE id IN (id1, id2, id3, ...);
| zzq1015 wrote:
| PSA: When posting an RFC or (especially) an RFC-draft, please use
| the IETF Datatracker URL.
|
| For example, this one is: https://datatracker.ietf.org/doc/draft-
| ietf-httpbis-safe-met...
|
| The best way to view an RFC, IMHO, is to use the "htmlized"
| format: you can view and compare different versions, view errata
| for a formal RFC, and go back to Datatracker at any time.
|
| Also, the Datatracker URL is version-insensitive, so unlike the
| pure HTML format, it will not be stuck on draft-14 forever.
| zzq1015 wrote:
| From the Datatracker, I can see that it was called SEARCH until
| draft-2 (Nov 2021), and then changed to QUERY.
|
| Also, the previous SEARCH method was proposed in Apr 2015 (!!),
| but nobody took it seriously, and it never gained traction back
| then. A lot of software was developed/updated during the last
| decade, and a lot of opportunities were missed. Even if the
| QUERY method is turned into a formal RFC right now, expect 10+
| years for everyone to adopt it, without running into HTTP-405
| or 501's.
| nine_k wrote:
| It just takes some significant piece of _server_ software to
| start accepting it, RFC or not. "Write code, not laws", or
| however was that formulated.
|
| See the history of the PATCH method, and of the whole WebDAV
| thing.
| Hackbraten wrote:
| > please use the IETF Datatracker URL.
|
| On my phone, your Datatracker link results in an unreadable
| mess of a page due to the hard-coded line breaks in the
| plaintext rendition of the RFC text (making it unreadable in
| portrait mode) and the huge sticky page nav (causing the
| content viewport to shrink vertically to almost zero in
| landscape mode). The HTML page behind OP's link reads just
| fine.
|
| > The best way to view an RFC, IMHO, is to use the "htmlized"
| format
|
| I don't see any choices of format such as HTML behind your
| link. There's a sticky nav, then a couple of pages of metadata,
| followed by a plaintext rendering of the RFC. What am I
| missing?
| znpy wrote:
| It reads decently in landscape mode, and i'm on a small
| screen (iPhone se 3rd gen).
| Hackbraten wrote:
| It shows me only seven lines of text at a time [0], too few
| for me to read comfortably, let alone make sense of e.g.
| diagrams. Firefox on Librem 5.
|
| [0]: https://0x0.st/KJZ_.png
| dan-robertson wrote:
| When I open the link there is a table of information before
| the main RFC text. One row is titled 'formats' in bold and
| has a 'htmlized' link in it. Presumably that is what you were
| missing due to some understandable banner blindness.
| IanCal wrote:
| In the top section where there's authors etc, there's a
| format list. I didn't see it the first time.
| gethly wrote:
| 0.1% of people will implement this into their code.
|
| Waste of time.
| aiven wrote:
| In the first ten years? Maybe. After that, it might become
| mainstream.
| fpoling wrote:
| Interesting that instead of just allowing GET with body the
| proposal went with a new HTTP method. I wonder if this would
| delay the support by proxies and other middle boxes. It seems
| supporting body would be easier than a new method.
| fogzen wrote:
| What's wrong with POST'ing a report?
|
| POST to /reports with the query parameters in the body. Respond
| with bookmarkable, cacheable /reports/id and GET /reports/id
|
| And that's only necessary for huge, complex queries. If filtering
| some resources doesn't fit into the URL you might want to rethink
| what you're doing.
| onfir3 wrote:
| The convention for internal "Query" routes in my company is just
| a Post with a path starting with "/queries" This is taken care of
| in eg. our retry middleware.
|
| Not as good as a standardized idempotent Method, but good enough
| for the time being till they finally approve this as RFC
| tlhunter wrote:
| I suppose this is the kind of thing that would be handled by a
| separate RFC but I hope that browsers will be allowed to send
| QUERY requests via HTML <form> elements since traditionally they
| can only send GET and POST.
| paulddraper wrote:
| Just add a body to GET.
|
| Obviously doesn't work with all systems, but QUERY works with
| even fewer.
___________________________________________________________________
(page generated 2025-11-30 23:01 UTC)