# 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.

Source: https://howhttpworks.com/methods/query
Last reviewed: 2026-10-04

> **TL;DR:** QUERY is a safe, idempotent HTTP method whose query goes in the request body. It is now a standard, [RFC 10008](https://www.rfc-editor.org/rfc/rfc10008.html) (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](https://howhttpworks.com/status-codes/414)) and leaks the query into logs and history. Putting it in a POST body works, but [POST](https://howhttpworks.com/methods/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:

```http
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
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](https://howhttpworks.com/status-codes/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.

```http
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](https://www.rfc-editor.org/rfc/rfc10008.html) 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](https://www.rfc-editor.org/rfc/rfc9110#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](https://howhttpworks.com/status-codes/405) or [501](https://howhttpworks.com/status-codes/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.

```bash
curl -i -X QUERY https://api.example.com/contacts \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data 'select=surname,givenname,email&limit=10'
```

## Related

QUERY keeps the guarantees of [GET](https://howhttpworks.com/methods/get) and the body of [POST](https://howhttpworks.com/methods/post). For the decision between those two today, see [GET vs POST](https://howhttpworks.com/compare/get-vs-post).
