Here's a simple way to think about the new HTTP QUERY method the IETF just standardized in RFC 10008.
Imagine you're at a restaurant.
- GET: "Can I see the menu?"
- POST: "I'd like to order this meal."
- QUERY: "Can you show me all spicy meals under ₦5,000 that don't contain peanuts?"
You're not creating or changing anything — you're simply making a complex request to find exactly what you're looking for. That's exactly what QUERY does. It lets clients send complex search criteria in the request body while remaining a safe operation that only retrieves data.
It's a small addition, but it's a meaningful one: QUERY is the first genuinely new HTTP method since PATCH landed as RFC 5789 back in 2010 — a 16-year gap.
The problem it actually solves
GET has always been the "safe, cacheable, retrieve-only" method, but it has one long-standing limitation: everything has to fit in the URI. That's fine for ?category=shoes&size=10, and it falls apart fast once your query gets complex:
- URI length limits are inconsistent across servers, proxies, and browsers, and nobody agrees on the real number.
- Encoding a nested filter (spicy AND under-5000 AND NOT-peanuts) into a query string is awkward and error-prone.
- URIs get logged everywhere — access logs, browser history, analytics — which is a real privacy concern when the "query" contains something like a search for sensitive personal data.
- Every distinct combination of filters technically becomes its own "resource" from the URI's point of view, which never really matched what was happening semantically.
The usual workaround has been to abuse POST for read-only searches, which throws away the one guarantee that made GET useful in the first place: that it's safe to cache, safe to prefetch, and safe to retry automatically if it fails.
Safe and idempotent, with a body
QUERY is explicitly defined as safe and idempotent — same as GET. The server must not change the target resource's state when handling one. That's the whole point: it gives you POST's ability to carry a rich, structured body, with GET's guarantee that intermediaries (proxies, CDNs, the browser itself) can cache the response and safely retry the request if it times out.
GET |
QUERY |
POST |
|
|---|---|---|---|
| Safe | Yes | Yes | Not guaranteed |
| Idempotent | Yes | Yes | Not guaranteed |
| Query lives in | URI | Request body | Request body |
| Cacheable | Yes | Yes (with caveats) | Rarely |
On the wire, it looks like this:
QUERY /products HTTP/1.1
Host: api.example.com
Content-Type: application/json
Accept: application/json
{
"category": "spicy",
"maxPrice": 5000,
"excludeIngredients": ["peanuts"]
}HTTP/1.1 200 OK
Content-Type: application/json
{
"results": [
{ "id": "42", "name": "Suya Wrap", "price": 3500 }
]
}A Content-Type header is required on the request — the RFC says servers must reject requests where it's missing or inconsistent with the body, since without it there's no reliable way to know how to interpret the query.
The caching catch
Caching a QUERY response isn't quite as simple as caching a GET. With GET, the cache key is just the URI. With QUERY, a cache has to fold the full request body and relevant headers into the cache key too, since two requests to the same URI can carry completely different query bodies. It's a solvable problem, but it's more work for intermediaries than GET ever required.
Cross-origin requests are affected as well: QUERY isn't one of the CORS-safelisted methods, so browsers will send a preflight OPTIONS request before the real one — same as they already do for most non-trivial POST and PUT requests.
Where things stand right now
Standardization is only the first step — actual support is what matters. As of this RFC's publication: Node.js has parsed QUERY as a valid HTTP method since early 2024, OpenAPI 3.2 already documents it as a first-class method, and framework support is arriving unevenly (Spring hasn't shipped it yet as of this writing). Browser-level fetch support is still being evaluated, so for now, using QUERY from client-side JavaScript means falling back to something like fetch(url, { method: "QUERY", body, headers }) and checking runtime support before relying on it.
It'll take a while for QUERY to show up in every framework and every browser dev tools dropdown. But the underlying idea — a method that's honest about being safe and idempotent while still letting you send a real body — is one API design has needed for a long time.