HTTP QUERY Method: A New Standard for Complex Reads
The HTTP QUERY method is an official IETF standard (RFC 10008, June 2026) introduced to fill the long-standing gap between GET…
HTTP QUERY Method: A New Standard for Complex Reads

Blog Thumbnail
The HTTP QUERY method is an official IETF standard (RFC 10008, June 2026) introduced to fill the long-standing gap between GET (safe/idempotent, no body) and POST (body, but non-idempotent). It allows complex, read-only requests by carrying a request body (e.g. JSON or SQL) while remaining safe, idempotent and cacheable. The IETF approved QUERY as a Proposed Standard in Nov 2025, and it was published June 2026. The new Accept-Query response header advertises supported query formats. In practice today, support is limited – clients typically feature-detect QUERY (e.g. via an OPTIONS check) and fall back to POST if needed. We compare QUERY to existing methods, show usage examples, discuss security/CORS implications, and give implementation advice with sample code.
History and Standardization
The idea of a “query” method dates back over a decade. In 2015, James Snell proposed reusing WebDAV’s SEARCH method for general queries (WebDAV RFC 5323). However, reusing SEARCH conflicted with existing WebDAV clients. By 2021, the IETF HTTPbis working group adopted the draft under a new name: QUERY. After extensive review (including W3C/WHATWG feedback and an HTTP directorate review), the IETF approved the latest draft on Nov 20, 2025, and the specification was published as RFC 10008 in June 2026.

HTTP Query Method Timeline
The RFC 10008 itself defines QUERY on the Internet Standards track (Proposed Standard). The RFC’s abstract summarizes its intent: “A QUERY requests that the target process the enclosed content in a safe and idempotent manner and respond with the result”. In short, QUERY is explicitly a read-only method (with side-effect safety guarantees) that carries a body.
Semantics and Usage
The QUERY method is conceptually like GET (a read) but allows a body like POST. Key points from RFC 10008:
- Safe and Idempotent: By definition,
QUERYis safe (does not alter the target resource) and idempotent (repeating the same request has no additional effect). This enables retries and caching. Table 1 below (from RFC 10008) highlights this comparison forGET,QUERYandPOST:

Http Method Use
- *POST and PATCH responses can be cached only if they include explicit freshness information.
- Unlike
POST, which is not safe or idempotent by default,QUERYguarantees the safe/idempotent semantics ofGETwhile supporting a request body. ThusQUERYbrings back caching and retry behavior lost when usingPOSTfor queries: proxies and CDNs can safely cache identicalQUERYresponses (taking the body into account). - URL vs. Body: With a
QUERYrequest, the query parameters or filter logic are sent in the request body, not the URL. This avoids long or encoded query strings and leaking sensitive data into URIs. For example, instead ofGET /search?role=admin&active=true, one could do:
QUERY /search HTTP/1.1
Host: example.com
Content-Type: application/json
{ "role": "admin", "active": true }
- The RFC notes that encoding complex queries in the URL is often problematic (length limits, logging of URIs, awkward data structures), and using
GETwith a body is unreliable (many servers ignore or forbid it).QUERYfixes this by being designed to carry a body. - Content Negotiation and Formats: The actual format of the query is determined by content negotiation: the
Content-Typeof theQUERYrequest signals how to interpret the body (e.g. JSON, SQL, GraphQL, etc.). Servers may only support certain query types. To help with this, the standard introduces an**Accept-Query** response header. A server may includeAccept-Query: <media-types>in its responses to indicate which query formats it supports. (E.g.,Accept-Query: application/json, application/sql.) Clients canHEADorOPTIONSthe resource to readAccept-Queryand choose an appropriate format. If a client sends an unsupported media type, the server should reply415 Unsupported Media Typeand include anAcceptorAccept-Queryheader with valid types. - Redirection and Resource URIs:
QUERYcan either return results directly (2xx) or indirectly. For large queries, a server may respond303 See Otherwith aLocationheader pointing to a stored query resource. Similarly, a response may includeContent-LocationorLocationheaders for result caching or repeatable GETs. In all cases, the request semantics stay safe/idempotent; the difference is only where and how the results are returned (directly or via a follow-upGET).
Example Requests/Responses
Below are illustrative examples (based on RFC 10008) showing how QUERY is used:
- Simple Query with JSON (direct 200 response):
QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/json
Accept: application/json
{"q": "Smith", "limit": 5}
- Response:
HTTP/1.1 200 OK
Content-Type: application/json
[
{"surname": "Smith", "givenname": "John", "email": "jsmith@example.org"},
{"surname": "Smith", "givenname": "Jane", "email": "jsmith@example.com"}
]
- Discovering
QUERYSupport (via OPTIONS):
OPTIONS /contacts HTTP/1.1
Host: example.org
- Response:
HTTP/1.1 200 OK
Allow: GET, QUERY, OPTIONS, HEAD
- The
Allowheader lists the supported methods, includingQUERY. IfQUERYwere not supported, the server could return405 Method Not Allowedinstead. - Advertising Query Formats (via Accept-Query):
HEAD /contacts HTTP/1.1
Host: example.org
- Response:
HTTP/1.1 200 OK
Accept-Query: application/json, application/sql
- This indicates the server accepts either JSON-formatted queries or SQL queries.
- Indirect Query (303 Redirect):
QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/sql
Accept: text/csv
SELECT surname, email WHERE active=true
- Response (no immediate results, see other URI):
HTTP/1.1 303 See Other
Location: /contacts/query-12345
- The client can then
GET /contacts/query-12345to retrieve the cached results.
These examples show how QUERY carries a body and uses standard headers. Unlike POST, there is no automatic side-effect; these are treated as read operations. Because QUERY is cacheable, identical queries can be cached by intermediaries, subject to normal cache rules (e.g. Vary on body).
Method Comparison
The table below summarizes key attributes of various HTTP methods (safe/idempotent/cacheable) and their typical roles. (This is adapted from MDN and RFC 10008 data.)

Method Comparison
(*POST/PATCH responses are cacheable only if explicit freshness and Content-Location headers are provided.) Importantly, only GET, HEAD, OPTIONS, and now QUERY are safe/idempotent. This means QUERY can leverage caching and automatic retry safely, unlike POST.
Security and CORS Considerations
Because QUERY is a new method, there are a few implications to note:
- Sensitive Data in URI: One motivation for
QUERYis to avoid putting sensitive query parameters in the URL. If a server generates a new URI for query results (viaLocationorContent-Location), it should not encode any sensitive request data into that URI. In other words, temporary result URLs should not expose private filters or credentials. - Cache Normalization: Caches must be careful. If a cache normalizes query bodies (for deduplication), it must do so exactly as the server would process them. Any incorrect normalization could yield wrong cached results. In practice, most caches will key on the entire request (method + URI + body).
- Cross-Origin (CORS) Preflight: In browsers,
QUERYis not a CORS-safelisted method (the safelisted methods areGET,HEAD,POST). This means any cross-originQUERYrequest will trigger a CORS preflight (OPTIONS) check. Developers should be aware: usingQUERYfrom web frontends requires proper CORS setup and may incur the overhead of preflight.
Implementation and Adoption
Because QUERY is brand-new, support in clients, frameworks and servers is still emerging:
- Clients and Browsers: Modern HTTP libraries (like
fetch,axios, Python’srequests, etc.) typically allow sending a custom method string. For example, Python’srequestscan dorequests.request("QUERY", url, json={...}). Node.jsfetchalso accepts any method token. However, older tools or frameworks might restrict methods to the common ones. For example, many browsers or API gateways simply ignore or strip bodies onGETrequests, so trying to workaround by sending a body withGETis unreliable. As per the RFC, feature-detectingQUERYis recommended: one can issue anOPTIONSor try a harmlessQUERYand see if one gets a200or a405 Method Not Allowed. If405or not supported, fall back toPOST. - Servers and Proxies: Many HTTP servers (nginx, Apache, IIS, etc.) and proxies (Cloudflare, AWS ALB/CloudFront, etc.) do not yet recognize
QUERYby default. Configurations may be needed to allow it (for example, addingQUERYto allowed methods). If a server doesn’t support it, it will typically respond405or may list only standard methods inAllow. The IETF draft expected such roll-out delays: one comment notes CloudFront already blocksGETwith body, so supportingQUERYwill require updates to intermediaries. In short, today you should assume limited support. Frameworks and servers will need to catch up; in the meantime, developers should write fallback logic. For example, if aQUERYrequest fails or is refused, retry asPOSTto the same endpoint (the semantics will match, since aPOSTwith the same body was how many APIs did complex reads before). - Discovery: To handle varied support, clients can use HTTP options:
OPTIONS /search HTTP/1.1
Host: example.com
- A compliant server will list
QUERYinAllowif supported. Alternatively, one can simply sendQUERYand check if the response is405(with anAllowheader) or success.
Best Practices and Migration
- Use
QUERYfor Complex Read APIs: The primary use case is APIs that perform filtered, sorted, paginated, or graph-like queries where the parameters exceed a URL’s convenience. If your current design usesPOST /searchpurely as a read (no side-effects), consider switching toQUERYfor semantic clarity and to regain caching/retry benefits. Examples include faceted search, reporting queries, or any endpoint that takes a complex JSON filter. - Fallback to POST: For backward compatibility, detect if
QUERYis supported and otherwise send the same payload viaPOST(keeping the same URL). This way, you get the safety ofPOSTfallback where needed. A sequence flow might look like:
sequenceDiagram
participant C as Client
participant S as Server
C->>S: QUERY /search with {body}
alt Server supports QUERY
S-->>C: HTTP/200 OK (result data)
else
S-->>C: HTTP/405 Method Not Allowed
C->>S: POST /search with same {body}
S-->>C: HTTP/200 OK (result data)
end
- Keep Bookmarkable Queries on GET: If your queries produce a shareable or bookmarkable link (i.e. all query parameters fit in a URL), continue to use
GET. Remember,QUERY-based requests with bodies cannot be bookmarked or retried by manually copying URLs. - Cache Keys Include Body: If you implement caching (client-side or on proxies), be sure to include the request body in the cache key. A
QUERYrequest with the same URL but different body is a distinct query. RFC 10008 explicitly notes that caching systems must incorporate the full content when caching aQUERYresponse. - Content-Location and Location: If your server generates URIs for queries or results, use the
Content-Locationheader for a URI that can return the same result, andLocationfor a URI that, when GETed, re-executes or retrieves the query. This lets clients use plainGETthereafter if needed.
Code Examples
Here are some sample code snippets showing how to use QUERY in practice:
- cURL (shell):
curl -X QUERY "https://api.example.com/products" \
-H "Content-Type: application/json" \
-d '{"category":"laptop","filters":{"price":{"min":500,"max":1500}}}'
- This sends a
QUERYrequest with a JSON body. - JavaScript (Fetch API, e.g. in Node or browser):
const res = await fetch("https://api.example.com/products", {
method: "QUERY",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
category: "laptop",
filters: { price: { min: 500, max: 1500 } }
})
});
const data = await res.json();
console.log(data);
- Node.js (Express server):
const express = require('express');
const app = express();
app.use(express.json());
// Express does not have built-in `app.query()`, but you can catch it:
app.all('/search', (req, res, next) => {
if (req.method === 'QUERY') {
// Handle query logic, reading req.body
const query = req.body;
// ... perform database search or filter ...
res.json(results);
} else {
next();
}
});const express = require('express'); const app = express(); app.use(express.json()); // Express does not have built-in `app.query()`, but you can catch it: app.all('/search', (req, res, next) => { if (req.method === 'QUERY') { // Handle query logic, reading req.body const query = req.body; // ... perform database search or filter ... res.json(results); } else { next(); } });
- Python (requests client):
import requests
url = "https://api.example.com/data"
body = {"filter": {"type": "active"}}
response = requests.request("QUERY", url, json=body)
print(response.status_code, response.json())
- Python (Flask server):
from flask import Flask, request, jsonify
app = Flask(__name__)
# Flask allows custom methods in routes
@app.route('/data', methods=['GET','QUERY'])
def data():
if request.method == 'QUERY':
query = request.get_json()
# ... perform query ...
return jsonify(results)
else:
# handle normal GET if needed
return jsonify({"message": "Please use QUERY for complex queries."})
Each example above treats QUERY much like a POST with a JSON body, but the semantics are read-only.
Summary
The new HTTP QUERY method is now an official standard for sending complex queries. It is safe, idempotent, and cacheable by definition. It allows APIs to use request bodies for rich filtering without misusing POST. Adoption will take time – until then, clients should detect support (e.g. via OPTIONS) and gracefully fall back to POST. When supported, QUERY gives API designers a semantically correct way to do large read-only queries, recovering caching and retry benefits for those operations. The full specification and examples are in [RFC 10008][28] and the IETF announcements.
메타데이터
- post_id
- 9e7587cd6bec
- slug
- http-query-method-a-new-standard-for-complex-reads-9e7587cd6bec
- url
- https://medium.com/algomart/http-query-method-a-new-standard-for-complex-reads-9e7587cd6bec
- canonical_url
- https://medium.com/algomart/http-query-method-a-new-standard-for-complex-reads-9e7587cd6bec
- author_url
- https://medium.com/@yashjainio
- status
- ok
- fetched_at
- 2026-07-13 06:23:13