HTTP QUERY Method: The Safe GET With a Body (RFC 10008)

Photo by Taylor Vick on Unsplash
QUERY is an HTTP request method, standardized in RFC 10008 in June 2026, that asks a server to process content carried in the request body and return the result. It is essentially a safe GET with a body: the parameters travel in the body instead of the URI, but the request keeps GET's read-only guarantees. It was defined by the IETF HTTP Working Group in the draft named draft-ietf-httpbis-safe-method-w-body.
Yes. RFC 10008 states that a QUERY response is cacheable and a cache may reuse it to satisfy later QUERY requests. The key difference from GET is that the cache key must incorporate the request body and related metadata, not just the URL, because the query itself lives in the body. A server can also return a Content-Location header pointing to a GET-able results resource for conventional caching.
GET can technically carry a body, but RFC 9110 says that content in a GET request has no generally defined semantics and may even be rejected as a possible request-smuggling attack. QUERY was created precisely to remove that ambiguity: it explicitly defines that the request body is the query. So QUERY gives you a portable, well-specified, interoperable way to send a body on a safe request, which GET never had.
Partially. Server frameworks are starting to support it: .NET 10 and ASP.NET Core 10 expose HttpMethod.Query on the client and HttpMethods.Query with an IsQuery helper on the server. However, browsers cannot yet send QUERY via fetch or XMLHttpRequest, and MDN has no dedicated page for it. For now QUERY is best suited to service-to-service APIs, with a parallel POST endpoint for public and browser clients.
POST works for complex search bodies, but it is neither safe, idempotent, nor cacheable, so proxies and caches cannot safely retry or reuse the response. QUERY carries the same body but is defined as safe and idempotent, so failed requests can be retried automatically and responses can be cached. Use QUERY for read-only searches and keep POST for operations that actually create or change state.

Photo by Taylor Vick on Unsplash
Key Takeaway
The HTTP QUERY method, standardized in RFC 10008 in June 2026, is a request that carries a body like POST but is safe, idempotent, and cacheable like GET. It exists so search and filter APIs can send complex queries in the body without abusing GET-with-a-body or losing caching by falling back to POST.
Every backend engineer eventually hits the same wall: a search endpoint whose parameters no longer fit in a URL. A faceted product filter, a GraphQL-style field selection, a geospatial polygon — the query is structured data, not a handful of string parameters. HTTP has historically given you two poor options for that, and in June 2026 the IETF finally shipped a third.
That third option is QUERY, published as RFC 10008, The HTTP QUERY Method. It grew out of the working-group draft named draft-ietf-httpbis-safe-method-w-body, and that draft name is the whole idea in one phrase: a safe method that is allowed to carry a body. Before we get to QUERY, it is worth being precise about why the two existing options hurt.
The instinct is to put the body on a GET, since a search reads data and GET is the read method. The specification disagrees. RFC 9110, the core HTTP semantics document, states plainly that 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. In practice: some proxies silently drop the body, and some treat it as an attack. A request that behaves differently depending on which intermediary it passes through is not something you can ship.
GET /contacts?select=surname,givenname,email&limit=10&match=%22email%3D*%40example.*%22 HTTP/1.1
Host: example.org
# RFC 9110 §9.3.1: content in a GET request "has no generally
# defined semantics" and may be rejected as request smuggling.So most of us reach for POST. It carries any body you like and every client and proxy understands it. The problem is what POST means. POST is neither safe, idempotent, nor cacheable — it is defined as a method that may change server state. That single definition costs you three concrete things. A dropped connection cannot be retried automatically, because nothing guarantees the first attempt did not already mutate something. A CDN or shared cache cannot reuse the response. And a reader of your logs cannot tell a state-changing write apart from a read that merely happens to carry a big body. You end up documenting this POST is really a read in prose that no cache or proxy will ever read.
QUERY resolves the tension. RFC 10008 defines it as a method that asks the target resource to process the enclosed request content in a safe and idempotent manner and return the result. The content — JSON, form-encoded, whatever media type you declare — is the query. Because the method is defined as safe, the server promises the request changes no state; because it is idempotent, a client or proxy may retry it after a network blip without fear; and because the response is cacheable, a shared cache may reuse it for later identical QUERY requests. It is, quite literally, the read semantics of GET with the request body of POST.
QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/json
Accept: application/json
{ "select": ["surname","givenname","email"], "limit": 10, "match": "email=*@example.*" }
HTTP/1.1 200 OK
Content-Type: application/json
Content-Location: /contacts/responses/42
[ { "surname": "Smith", "givenname": "John", "email": "[email protected]" } ]A 2xx QUERY response can carry a Content-Location header pointing at a results resource. RFC 10008 describes this as the server's claim that a client may send a plain GET to that URI to retrieve the same results — giving you a second, GET-cacheable handle on the query output for clients and CDNs that only know how to cache GET.
These three words are not decoration; each one unlocks a specific behavior in the machinery between your client and your server.
There is one genuinely new thing to get right. For GET, the cache key is the URI. For QUERY, the query is in the body, so the URI alone is not enough. RFC 10008 requires that the cache key for a QUERY request incorporate the request content and related metadata, not just the target URI. In practice a cache must hash the body — respecting content type and relevant headers — to distinguish two different searches sent to the same path. Caches that support QUERY do this for you; the point is that a naive URI-only cache will happily return the wrong results if you bolt QUERY onto it without support.
Do not enable QUERY caching on infrastructure that keys purely on the URL. A load balancer or edge cache that ignores the body will serve one search's results for a completely different search sent to the same path. Confirm your cache understands QUERY's body-inclusive cache key before turning caching on — otherwise leave it off and treat QUERY as an uncached safe read.
| Property | GET (with body) | POST | QUERY |
|---|---|---|---|
| Request body | Undefined by the spec | Fully supported | Defined as the query |
| Safe (read-only) | Yes | No | Yes |
| Idempotent / auto-retry | Yes | No | Yes |
| Response cacheable | Yes | No | Yes |
| Works across proxies today | No — body often dropped | Yes | Emerging (RFC 10008) |
QUERY is a Proposed Standard, not a future promise, but tooling is still catching up — so the honest answer is on the server, increasingly yes; in the browser, not yet.
I would not rip out a working POST /search tomorrow. But if you are designing a new internal search or filter API between services you control, QUERY is the correct method — it finally lets a read that needs a body stay a read, all the way down through every cache and proxy on the path. Reach for it there first, keep POST as the browser-facing fallback, and let the ecosystem catch up around you.