QUERY
Sending complex search parameters that exceed URI length limits calls for the HTTP QUERY method, which carries query content in the request body while preserving the safe, idempotent semantics of GET.
Usage
The QUERY method asks the target resource to perform a query operation within the scope of the resource. The request content and its media type define the query, and the target URI sets the scope.
Complex queries often exceed practical URI length limits. Search parameters, GraphQL operations, SQL expressions, and structured filter objects are difficult to encode as query strings. GET has no defined body semantics, forcing these inputs into the URI. POST accepts a body but is neither safe nor idempotent, preventing caches and intermediaries from optimizing repeated requests.
QUERY fills this gap. The method sends query content in the request body while preserving the safe and idempotent semantics of GET. Responses are cacheable, and intermediaries are free to retry failed requests without risk of unintended side effects.
Properties
| Property | Value |
|---|---|
| Safe | Yes |
| Idempotent | Yes |
| Cacheable | Yes |
The request requires a Content-Type header describing the query format. Servers reject requests with:
- Missing or inconsistent Content-Type: 400 Bad Request
- Unsupported query media type: 415 Unsupported Media Type
- Valid syntax but unprocessable query: 422 Unprocessable Content
- Unsupported response format: 406 Not Acceptable
Equivalent resources
The specification models every QUERY request as an equivalent resource, a conceptual resource responding to GET and representing the combination of the query content and the target resource. Servers assign a URI to the equivalent resource when useful and skip the URI otherwise. The concept underpins three response patterns:
- Include a Content-Location header identifying a resource containing the query results, retrievable via GET.
- Include a Location header identifying the equivalent resource URI, allowing clients to repeat the query via GET without resending the body.
- Redirect with 303 and a Location header pointing to a GET-accessible URI for the results.
Redirects
Unlike POST, redirect responses preserve the QUERY method. 301, 302, 307, and 308 redirects all repeat the QUERY request to the new URI without converting to GET. Only 303 switches the method to GET, directing the client to retrieve results from a different URI.
Caching
QUERY responses are cacheable.
The cache key incorporates the request content
and related metadata in addition to the target
URI. Caches normalize insignificant differences
in the request body (such as removing content
encoding or normalizing based on media type
semantics) for cache key generation only. A client
opts out of normalization with the no-transform
directive, an advisory signal.
Caching QUERY costs more than caching GET, since the cache reads the entire request body to compute the key. A response carrying a Location header hands clients a GET-addressable result, letting follow-up requests skip the body entirely.
Range requests
Range semantics match GET, and byte ranges
offer little value for query results. Query formats
page results themselves, SQL with
FETCH FIRST ... ROWS ONLY, so format-level paging
substitutes for Range headers.
CORS
QUERY is not a CORS-safelisted method. Cross-origin QUERY requests require a preflight OPTIONS request before the browser sends the actual request.
Accept-Query
The Accept-Query response header field declares the media types a server accepts for QUERY requests. The field uses Structured Fields List syntax.
Accept-Query: application/graphql, application/sql
Each media type appears as a Structured Fields Token or a quoted String, and the choice between the two forms carries no meaning. The String form covers types outside Token syntax, such as names with a leading digit. Media type parameters map to Structured Fields Parameters on either form, as in the specification's own example.
Accept-Query: "application/jsonpath", application/sql;charset="UTF-8"
Wildcards are limited to */* and type/* forms,
and the order of listed types carries no meaning.
The field value applies to every URI on the server
sharing the same path, with the query component
ignored, and when responses disagree, the most
recently received fresh value wins.
Servers include this header in responses to inform clients about supported query formats for a given resource.
Discovering support
An OPTIONS request answers whether a
resource supports QUERY: the
Allow response header lists the supported
methods, as in Allow: GET, QUERY, OPTIONS, HEAD.
Sending a QUERY without prior knowledge works
equally well, since a server lacking support
answers 405 with the same Allow
header.
Formats surface the same two ways. A HEAD request returns Accept-Query naming the supported media types, and a QUERY sent in an unsupported format draws 415 with an Accept response header listing the formats the resource takes.
Security
Request bodies travel with more privacy than URIs. Intermediaries log and process the URI far more often than request content, so a query carrying sensitive terms belongs in a QUERY body rather than a GET query string. The specification makes the logging argument the method's core security property.
Two cautions follow from the response side. A server minting a temporary result URI for a sensitive query keeps sensitive portions of the query out of the URI itself. And a cache normalizing query content differently from the origin risks serving the wrong stored response when normalization produces a false match.
Example
A GraphQL query sent to an API endpoint. The request body contains the full query, avoiding URI length constraints.
QUERY /api/graphql HTTP/1.1
Host: api.example.re
Content-Type: application/graphql
{
users(role: "admin") {
id
name
email
}
}
HTTP/1.1 200 OK
Content-Type: application/json
Content-Location: /api/graphql/results/a7f3
{"data":{"users":[{"id":"1","name":"Ada","email":"ada@example.re"}]}}
A structured search with URL-encoded form data. The query exceeds typical URI length limits due to multiple filter parameters.
QUERY /search HTTP/1.1
Host: www.example.re
Content-Type: application/x-www-form-urlencoded
q=distributed+systems&category=books&year=2025&sort=relevance&lang=en&format=hardcover
HTTP/1.1 303 See Other
Location: /search/results/b8e2
The 303 redirect points to a cached result set accessible via GET, allowing bookmarking and sharing of the query results.
A conditional query using If-None-Match to avoid transferring unchanged results. The validator applies to the selected representation, the same one a GET to the equivalent resource returns, so conditional semantics carry over from GET unchanged.
QUERY /feed HTTP/1.1
Host: www.example.re
Content-Type: application/x-www-form-urlencoded
If-None-Match: "v42"
topic=http&since=2025-01-01
HTTP/1.1 304 Not Modified
ETag: "v42"
See also
- RFC 10008: The HTTP QUERY Method
- Accept-Query
- GET
- POST
- Content-Type
- Caching
- Conditional requests
- CORS
- Redirects
- HTTP methods