Meet QUERY: the HTTP method REST always needed
HTTP QUERY (RFC 10008, June 2026) is the safe, idempotent, cacheable method with a body that POST /search never was. What it is, how to use it, what supports it
The oldest workaround in REST is using POST to read data. Every API with a search endpoint has done it: the filters do not fit in a URL, so the request becomes POST /search with a JSON body, and we quietly give up everything GET gave us. In June 2026 HTTP fixed it. RFC 10008 defines the QUERY method: a request with a body, with the semantics of GET. It is the first new HTTP method standardized since PATCH in 2010.

The problem QUERY solves
GET is safe, idempotent and cacheable, which is exactly what a read should be. But GET carries its parameters in the URL, and URLs are a bad place for complex queries: nested filters, lists of ids, geo bounds, pagination cursors. Servers and proxies cap URL length, encoding gets ugly, and logs fill with sensitive data. So we reach for POST, which accepts a body but is none of safe, idempotent or cacheable. Caches will not store the response, retries are not allowed to be automatic, and tooling cannot tell a read from a write.
QUERY takes the body from POST and the guarantees from GET. The server must process the content without side effects, the request can be retried or replayed safely, and the response can be cached.
What a QUERY request looks like
QUERY /products HTTP/1.1
Host: api.example.com
Content-Type: application/json
Accept: application/json
{"category": "laptops", "price": {"max": 1200}, "inStock": true, "sort": "-rating"}The body is the query. The media type is up to the API: JSON, a search DSL, even SQL-like text. A server can advertise what it accepts with the Accept-Query response header, and a client that receives 405 knows the resource does not support querying.
Caching is the interesting part. Because the body is part of the request, it becomes part of the cache key: two QUERY requests with identical bodies can share a cached response, which no cache would ever do for POST. The usual headers, Cache-Control and ETag, apply as they do for GET.
Serving it in Node.js
Node's HTTP parser recognizes QUERY, and http.METHODS lists it from Node 22. A plain server needs no special handling:
import { createServer } from "node:http";
createServer((req, res) => {
if (req.method !== "QUERY" || req.url !== "/products") {
res.writeHead(405, { Allow: "QUERY, GET" }).end();
return;
}
let body = "";
req.on("data", (chunk) => (body += chunk));
req.on("end", () => {
const query = JSON.parse(body);
const results = search(query); // read-only
res.writeHead(200, {
"Content-Type": "application/json",
"Cache-Control": "max-age=60",
});
res.end(JSON.stringify(results));
});
}).listen(3000);Frameworks that route by method name need to expose the new verb; check yours before wiring it. With curl the request is simply curl -X QUERY -H "Content-Type: application/json" -d '{...}' https://api.example.com/products.
Calling it from the browser
fetch() sends whatever method string you give it, uppercase, so a same-origin QUERY works today:
const res = await fetch("/products", {
method: "QUERY",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ category: "laptops", inStock: true }),
});
const products = await res.json();Cross-origin is stricter. QUERY is not a CORS-safelisted method, so the browser sends an OPTIONS preflight first, and the API must answer with Access-Control-Allow-Methods: QUERY. Plan for that on any public API.
Documenting it
OpenAPI 3.2, released in September 2025, added a query operation alongside get and post, so the method can be described, validated and rendered by tooling that has caught up:
paths:
/products:
query:
summary: Search products
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/ProductQuery"
responses:
"200":
description: Matching productsWhere it breaks today
- Intermediaries. Some CDNs, API gateways and web application firewalls still reject methods they do not know. Test the whole path, not just your server.
- Frameworks. Routers with a fixed list of verbs may not expose QUERY yet, even when the runtime parses it.
- Semantics are on you. The spec promises caches and clients that QUERY is safe. If your handler writes to the database, you have broken that promise and retries will multiply the damage.
When to use it
Use QUERY for reads whose parameters do not fit comfortably in a URL: search, filtering, reporting, batch lookups by id. Keep GET for simple reads, and keep POST for anything that creates or changes state. If you are starting a new API in 2026, model your search endpoint as QUERY from day one and let the gateway catch up; if you maintain an old one, expose QUERY next to the existing POST /search and migrate clients when the path is clear.
Reference: RFC 10008, The HTTP QUERY Method.
Frequently asked questions
Is HTTP QUERY the same as GET with a body?
No. GET with a body has undefined semantics and most servers and proxies drop or reject it. QUERY defines the body as the query itself, with safe and idempotent semantics, so caches and intermediaries can handle it correctly.
Can I use QUERY from a browser?
fetch() sends any method name, so same-origin QUERY requests work today. Cross-origin requests trigger a CORS preflight because QUERY is not a safelisted method, and the server must list it in Access-Control-Allow-Methods.
Does my framework support QUERY?
Node.js recognizes it in its HTTP parser (http.METHODS includes QUERY from Node 22) and OpenAPI 3.2 documents it with a query operation key. Check your proxy, CDN and WAF too: some still reject unknown methods.
Should I replace all my POST /search endpoints?
Only the read-only ones. QUERY must not change state. Keep POST for anything that creates or modifies resources.