QUERY is a proposed HTTP method that fills a real gap: it is safe and
idempotent like GET, but it may carry a request body like POST.
Think of it as “a GET you can send a payload with.”
Why it exists
Complex queries have long forced an awkward choice:
GETwith a query string puts every filter in the URL. URLs have length limits, get logged in plaintext, and are clumsy for structured or nested criteria.POSTwith a body carries the payload fine, but lies about intent.POSTis neither safe nor idempotent, so caches, crawlers, and intermediaries must assume the request changes state. It doesn’t — you’re just reading.
QUERY resolves the tension: the semantics say “this is a read”, and the body carries the criteria.
Properties
| Property | QUERY | GET | POST |
|---|---|---|---|
| Safe | ✓ | ✓ | ✗ |
| Idempotent | ✓ | ✓ | ✗ |
| Request body | ✓ | ✗ | ✓ |
| Cacheable | ✓ | ✓ | conditional |
What a request looks like
QUERY /products HTTP/1.1
Host: shop.example
Content-Type: application/json
Accept: application/json
{ "category": "boots", "inStock": true }
Caching with Content-Location
Because QUERY is safe and idempotent, a response can be cached — but the
cache key can’t be the URL alone, since the body varies. The server names the
canonical location of the result with a Content-Location header:
HTTP/1.1 200 OK
Content-Location: /products?category=boots&inStock=true
Cache-Control: max-age=60
A cache (or the client) can then reuse that representation for an equivalent request. This is the mechanism that lets a body-bearing read stay cacheable.
Try it
Head to the Playground and send a real QUERY request at this
site’s echo endpoint to see exactly how the method, headers, and body arrive at
the server.
QUERY is defined in an IETF Internet-Draft and is still evolving. Treat the details above as a working summary and check the linked draft for the authoritative, current text.