How HTTP Works

Method · safe · idempotent

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

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

HTTP QUERY is a safe, idempotent method with the query in the body. RFC 10008 status, an example exchange, caching rules, and why GET with a body fails.

Reviewed 3 min readintermediate4 sourcesMarkdown
Safe
Yes
Idempotent
Yes
Cacheable
Yes (key includes the body)
Request body
Yes, required
Response body
Yes
Spec
RFC 10008
On this page

TL;DR: QUERY is a safe, idempotent HTTP method whose query goes in the request body. It is now a standard, RFC 10008 (June 2026, formerly draft-ietf-httpbis-safe-method-w-body), and it exists because GET cannot carry a large or structured query reliably and POST tells every proxy the request might change something.

The gap it fills

You have a search endpoint whose filter is a JSON document, a GraphQL-style query, or a form with hundreds of IDs. Putting it in the URL runs into length limits (see 414) and leaks the query into logs and history. Putting it in a POST body works, but POST is neither safe nor idempotent, so a client cannot automatically retry it after a dropped connection, and shared caches will not reuse the response without extra work. A body on GET is not an escape hatch (see below).

QUERY is defined as safe and idempotent: the RFC says the client does not request or expect any change to the target resource’s state, and that a QUERY can be retried, for instance after a connection failure.

Example exchange

The request is the example from RFC 10008, Appendix A.1; the response body is an illustrative sketch:

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

select=surname,givenname,email&limit=10
HTTP/1.1 200 OK
Content-Type: application/json

[
  { "surname": "Smith", "givenname": "John", "email": "smith@example.org" },
  { "surname": "Jones", "givenname": "Sally", "email": "sally.jones@example.com" }
]

Points from the specification:

  • Content is required, and the server must fail the request if Content-Type is missing or inconsistent with the content. An unsupported media type gets 415.
  • The body is not an arbitrary payload: its meaning is defined by its media type and the target resource, such as a form encoding, a JSON query document or SQL.
  • A response may include Content-Location pointing at a resource where the result can be fetched with a plain GET, and Location pointing at a resource that repeats the same query without resending the body. A 303 See Other says the query can be answered by a normal retrieval of the Location URI.
  • Servers can advertise supported query formats with the Accept-Query response field, a structured-fields list of media types.
Accept-Query: "application/jsonpath", application/sql;charset="UTF-8"

Caching

QUERY responses are cacheable. The difference from GET is the key: RFC 10008 section 2.7 requires that the cache key for a QUERY request incorporate the request content and related metadata. A cache may normalize insignificant differences before keying, such as removing content encoding or applying format conventions like +json, but that only changes the key; the request forwarded upstream is untouched. Standard freshness rules (Cache-Control, Vary) still apply to the response.

Practically, a CDN or reverse proxy that does not know QUERY will not cache it, and may refuse or mishandle it. Do not assume your edge supports the method because the RFC exists.

Why GET with a body is unreliable

RFC 9110 section 9.3.1 says content in a GET request has no generally defined semantics, cannot change 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 vector. In practice:

  • Browsers will not do it. fetch fails with TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body. in Chrome.
  • Proxies and CDNs differ: some strip the body, some forward it, some return an error. A cache that keys on the URL treats two different bodies as the same request.
  • Some HTTP libraries, and tools such as API gateways and WAFs, drop or reject it.

QUERY gives the body defined semantics, so none of this is guesswork.

Using it today

  • Check the Allow header or Accept-Query before relying on it; servers that do not know the method answer 405 or 501.
  • From a browser, fetch(url, { method: 'QUERY', body }) sends the method name as written. It is not a CORS-safelisted method, so a cross-origin call triggers a preflight and the server must list QUERY in Access-Control-Allow-Methods.
  • Keep a POST fallback for clients and intermediaries that cannot pass QUERY through, and say so in your API docs.
curl -i -X QUERY https://api.example.com/contacts \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data 'select=surname,givenname,email&limit=10'

QUERY keeps the guarantees of GET and the body of POST. For the decision between those two today, see GET vs POST.

Frequently asked questions

What is the HTTP QUERY method?

QUERY is a method that asks the target resource to process the request body as a query, safely and idempotently, and respond with the result. It gives you POST-style bodies with GET-style guarantees, so clients and proxies may retry it and caches may store its responses.

Is QUERY an official standard?

Yes. It was developed as draft-ietf-httpbis-safe-method-w-body and published as RFC 10008 (Proposed Standard) in June 2026. Older articles that call it a draft or an experiment are out of date, though support in servers, proxies, CDNs and client libraries is still uneven.

Why not just send a body with GET?

RFC 9110 says content in a GET request has no defined semantics and some implementations may reject the request or close the connection because of request-smuggling risk. Browsers refuse to send it at all: fetch throws "Request with GET/HEAD method cannot have body". Caches also key on the URL alone, so two different GET bodies can collide.

How is QUERY cached?

The cache key must include the request body and related metadata, so identical queries can hit the cache and different ones cannot collide. RFC 10008 also lets a cache normalize insignificant differences such as content encoding before keying, which only affects the key, not the request sent upstream.

How do I know a server supports QUERY?

A server can advertise it with the Accept-Query response header, which lists the media types it accepts for QUERY, for example Accept-Query: "application/jsonpath", application/sql;charset="UTF-8". Otherwise expect 405 or 501 from servers that do not know the method, and check the Allow header.

Sources

  1. RFC 10008: The HTTP QUERY Methodrfc-editor.org
  2. IETF Datatracker: draft-ietf-httpbis-safe-method-w-bodydatatracker.ietf.org
  3. RFC 9110 section 9.3.1: GETrfc-editor.org
  4. MDN Web Docs: HTTP request methodsdeveloper.mozilla.org

Keep going

Browse /search