What is the HTTP QUERY Method ? Full Guide with Examples

 

QUERY: The HTTP Method We've Needed for 16 Years


In June 2026, the IETF published RFC 10008: The HTTP QUERY Method, authored by Julian Reschke (greenbytes), James M. Snell (Cloudflare), and Mike Bishop (Akamai), under the HTTP Working Group (HTTPBIS). It's the first new standard HTTP method registered since PATCH in 2010 — a 16-year gap. This post walks through what QUERY actually does, how it's meant to be used, and where its rough edges are.

Official reference: RFC 10008, published by the IETF HTTPBIS working group, June 2026, status "Proposed Standard." The method and a new response header (Accept-Query) have both been added to IANA's official HTTP registries.

The Problem QUERY Solves

HTTP has always had a gap between two extremes:

  • GET is semantically correct for reads, but everything has to be squeezed into the URL's query string.
  • POST can carry a rich request body, but it isn't safe or idempotent by definition — a proxy or client can't assume it's OK to retry or cache a POST.

The RFC calls out several concrete pain points with cramming complex filters into a URL:

  • Servers don't have a guaranteed size limit to work with, since a request can pass through many unrelated systems before reaching its destination.
  • Encoding structured data (nested filters, arrays, special characters) into a URI-safe string is inefficient and easy to get wrong.
  • URLs are far more likely to end up logged, cached in browser history, or saved as bookmarks than request bodies are — which matters if the query itself contains sensitive values.
  • Treating every distinct combination of filter parameters as its own "resource" doesn't really reflect what's happening.

The common workaround has been to send filters as a POST body instead. It works, but it quietly breaks HTTP's contract: intermediaries have no way of knowing that this particular POST is actually a safe, read-only operation, so they can't cache it or safely retry it after a dropped connection.

The Method Comparison

RFC 10008 summarizes the difference with a simple table of properties:

Property GET QUERY POST
Safe Yes Yes Not guaranteed
Idempotent Yes Yes Not guaranteed
Has its own URI by definition Yes Optional No
Request body Not defined Expected Expected
Cacheable Yes Yes Only for later GET/HEAD

QUERY is designed to sit exactly in that gap: a request body like POST, but safety and idempotency guarantees like GET.

A Basic Example

QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Accept: application/json

select=surname,givenname,email&limit=10&match="email=*@example.*"

Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
  { "surname": "Smith", "givenname": "John", "email": "[email protected]" },
  { "surname": "Jones", "givenname": "Sally", "email": "[email protected]" }
]

The Content-Type header is mandatory here — a QUERY request without one, or with a body that doesn't match the declared type, must be rejected. The spec lays out specific status codes for different failure modes:

  • 400 Bad Request — missing or mismatched Content-Type
  • 415 Unsupported Media Type — the server doesn't understand the query format at all
  • 422 Unprocessable Content — the format is understood, but the query itself is invalid (e.g., valid SQL syntax pointing at a table that doesn't exist)
  • 406 Not Acceptable — the server can't produce a response in the format the client asked for via Accept

Letting Clients Discover What's Supported

Because QUERY's actual behavior depends entirely on the request body's media type, servers need a way to advertise what they accept. That's what the new Accept-Query response header is for:

HEAD /contacts HTTP/1.1
Host: example.org
HTTP/1.1 200 OK
Accept-Query: application/x-www-form-urlencoded, application/sql

A client can also just try a QUERY request without knowing in advance — if the format isn't supported, the server responds 415 and lists what it does accept.

Caching, Conditional Requests, and "Equivalent Resources"

This is where QUERY gets genuinely more complex than GET. Since two QUERY requests to the same URL can carry completely different bodies, a cache can't just key on the URL — it has to incorporate the full request body and relevant metadata into the cache key. The spec explicitly allows caches to normalize semantically insignificant differences (like stripping content-encoding) to improve hit rates, but warns that incorrect normalization can serve the wrong cached result.

To make life easier, a server can optionally expose a stable URI for a given query — called the equivalent resource — using the Location header, or a URI for a specific result snapshot using Content-Location. Once a client has that URI, it can switch to plain GET (with normal conditional requests like If-Modified-Since or If-None-Match) instead of resending the full QUERY body every time. This is the mechanism the spec leans on to keep QUERY interoperable with the rest of HTTP's caching model.

Redirects work too, with one notable exception: unlike POST, a 301 or 302 response to a QUERY request does not get silently downgraded to a GET on redirect — the client is expected to retry with QUERY again at the new location, preserving the original semantics.

Tradeoffs and Drawbacks

QUERY isn't a free upgrade — it comes with real complexity costs:

  • Caching is harder to implement correctly. A cache needs to read and hash the entire request body (and account for encoding/format differences) just to compute a cache key. For GET, the URL alone is enough.
  • No built-in range/pagination semantics. HTTP Range requests technically apply to QUERY, but the spec itself notes they offer little practical value here — you're expected to use your query format's own paging mechanism (e.g., SQL's FETCH FIRST ... ROWS ONLY) instead.
  • CORS preflight is mandatory. QUERY is not on the browser fetch spec's list of "safelisted" methods, so any cross-origin QUERY request from a browser will trigger a CORS preflight OPTIONS request — extra latency you don't pay with a simple GET.
  • Ecosystem support is still catching up. Browsers, HTTP client libraries, API gateways, load balancers, and API frameworks all need to add explicit QUERY support. Until that lands broadly, using QUERY in production may mean patching tooling or writing your own client/server support.
  • Security logging tradeoffs cut both ways. Moving sensitive filter data out of the URL and into the body reduces the chance it leaks into access logs or browser history — but if a server exposes a Location or Content-Location URI for the query, the spec explicitly warns that URI shouldn't leak sensitive query content either.
  • It's easy to misuse. The RFC's own examples come with a disclaimer that if a query is genuinely short and simple, you're usually still better off with plain GET. QUERY is meant for the cases where a URL-encoded query string is impractical, not as a blanket GET replacement.

Security Considerations

The RFC flags a few points worth calling out directly:

  • Because QUERY content isn't part of the URI, it's less likely to be logged by intermediaries — useful when filters contain sensitive values.
  • If a server creates a temporary "equivalent resource" URI representing a query's results, that URI shouldn't itself encode any sensitive part of the original query.
  • Caches that normalize request bodies incorrectly could return a cached response for a request it doesn't actually match — a subtle class of bug that GET-based caching doesn't have to worry about.

Why "QUERY" and Not an Existing Method?

Interestingly, HTTP already had three safe, idempotent methods that carry a body: PROPFIND, REPORT, and SEARCH — all originally defined for WebDAV. The working group considered reusing one of these but ultimately went with a new name, mainly because those older methods tie their semantics to a generic media type rather than letting the request body's media type define the operation, and because "QUERY" more directly reflects its relationship to a URL's query component.

Where Things Stand

RFC 10008 is published as a Proposed Standard, meaning it's gone through IETF consensus and IESG approval, but broad real-world adoption is still in its early stages. If you're building or maintaining APIs — especially ones with search, filtering, or RAG-style retrieval endpoints where filters can get complex — it's worth watching how quickly your frameworks, gateways, and client SDKs start supporting it, since QUERY finally gives a semantically honest option for "this is a read, not a write, and it's safe to retry or cache."

Reference: RFC 10008, "The HTTP QUERY Method," IETF HTTPBIS Working Group, June 2026 — rfc-editor.org/info/rfc10008

Post a Comment

Post a Comment (0)

Previous Post Next Post