In June 2026 the IETF published RFC 10008, and HTTP got its first new method in 16 years: QUERY. The last time this happened was PATCH, back in 2010.
QUERY exists to kill one of the oldest workarounds in API design: POST /search. If you've ever POSTed a request that didn't actually change anything — just because your filter wouldn't fit in a URL — this method is for you.
What is the HTTP QUERY method?
QUERY is a safe, idempotent HTTP method that carries a request body. Think of it as GET's guarantees with POST's payload:
QUERY /users HTTP/1.1
Content-Type: application/json
{ "filter": "age > 21", "fields": ["name", "email"], "limit": 10 }
The semantics in one line each:
- Safe — the client is asking for data, not requesting a state change. Tooling, proxies, and crawler-like clients can treat it as read-only.
- Idempotent — sending the same QUERY twice produces the same result, so clients and intermediaries may retry a failed request automatically. Nobody gets double-charged.
- Cacheable — responses can be cached like GET responses, with one twist we'll get to: the request body is part of the cache key.
-
Body-first — the query itself lives in the body, described by
Content-Type. RFC 10008 requires servers to reject requests whose Content-Type is missing or doesn't match the body.
There's also a new response header, Accept-Query, that lets a resource advertise which query formats it understands (JSON, JSONPath, whatever — expressed in HTTP Structured Fields syntax).
Why not just use GET?
GET is the right semantics — but the query has to live in the URL, and URLs are a terrible place for a complex query:
- Length limits. Servers, proxies, CDNs, and browsers all cap URL length at different, undocumented points. A long ID list or nested filter will eventually hit one of them, and it'll fail only in production, only sometimes.
-
Encoding pain. Nested conditions, arrays, and operators like
>all have to be percent-encoded into query-string soup. Every API invents its own convention (filter[age][gt]=21, anyone?). -
URLs leak. Full URLs end up in server access logs, proxy logs, browser history, and
Refererheaders. Put a search term or an ID list in a URL and it's now in a dozen log files you don't control.
A GET with a body isn't the answer either — the spec allows a body on GET but explicitly gives it no meaning, and real-world intermediaries drop or reject it. (Elasticsearch users have been living in this gray zone for a decade.)
Why not just use POST?
Because POST is a semantic lie for reads — and the lie has a cost. The moment you use POST, everything in the HTTP ecosystem assumes you're changing something:
- No caching. Intermediaries won't cache POST responses. Your identical search request hits the origin every single time.
- No safe retries. A client that times out on a POST can't safely resend it — it might create a duplicate order. So SDKs, proxies, and service meshes all refuse to auto-retry, even when your POST was secretly a read.
- Tooling treats it as a write. Monitoring, API gateways, security scanners, idempotency middleware — all of them classify your search as a mutation.
POST /search became the industry standard anyway, because it was the only option that worked. QUERY is the honest verb that replaces it.
QUERY vs GET vs POST
| GET | POST | QUERY | |
|---|---|---|---|
| Safe (read-only semantics) | ✅ | ❌ | ✅ |
| Idempotent (auto-retry OK) | ✅ | ❌ | ✅ |
| Cacheable response | ✅ | ❌* | ✅ (body in cache key) |
| Meaningful request body | ❌ | ✅ | ✅ |
| Query visible in URL/logs | ✅ (that's the problem) | ❌ | ❌ |
| Works in every framework today | ✅ | ✅ | ❌ (adoption is early) |
* POST responses are technically cacheable in narrow cases nobody relies on.
The pros
- Honest semantics, real benefits. Retryability and cacheability aren't academic — they're the difference between a search that survives a flaky network and one that errors out, and between a hot query hitting your database once or a thousand times.
- Complex queries without URL hacks. JSON bodies with real structure, no percent-encoding, no invented query-string conventions, no length limits.
- Queries stay out of logs. Bodies don't land in access logs, browser history, or Referer headers by default. For queries containing emails, IDs, or search terms, that's a privacy upgrade.
-
Self-describing APIs.
Accept-Querygives clients a standard way to discover what query format an endpoint speaks — somethingPOST /searchnever had.
The cons (and honest caveats)
- Server support is early. This is the big one. Node.js parses QUERY natively, and OpenAPI 3.2 can document it, but framework routing (Rails, Spring, and friends) is still in progress. If your framework only routes the classic verbs, QUERY bounces with a 405.
-
Caching has sharp edges. The cache key must include the request body. A cache that normalizes or hashes bodies sloppily — treating
{"a":1,"b":2}and{"b":2,"a":1}as identical, or worse, ignoring the body — opens the door to cache poisoning. Until CDN support matures, treat QUERY caching as opt-in, not automatic. -
CORS preflight required. QUERY isn't a CORS-safelisted method, so browser JavaScript pays a preflight round-trip. Same as
POSTwithapplication/json, so in practice you're not losing anything — but it's not free. -
Ecosystem lag. Most HTTP clients, mock servers, and test tools predate the RFC. Even the public echo services (
httpbingo.org,postman-echo.com) reject QUERY with a 405 today.
How to send a QUERY request today
You don't need to wait for your framework. Any HTTP client that allows custom methods can send QUERY right now. With curl:
curl -X QUERY https://echo.postmateclient.com/ \
-H "content-type: application/json" \
-d '{"filter":"age > 21","limit":10}'
That endpoint — echo.postmateclient.com — is (as far as I can tell) the only public echo server that accepts QUERY today. It reflects your method, headers, and body back as JSON, so you can verify the method survives the trip:
{
"method": "QUERY",
"path": "/",
"body": "{\"filter\":\"age > 21\",\"limit\":10}",
"json": { "filter": "age > 21", "limit": 10 }
}
In JavaScript, fetch sends it without complaint:
const res = await fetch("https://echo.postmateclient.com/", {
method: "QUERY",
headers: { "content-type": "application/json" },
body: JSON.stringify({ filter: "age > 21", limit: 10 }),
});
console.log(await res.json()); // { method: "QUERY", ... }
And GUI clients are starting to pick it up — Postmate Client (a VS Code API client) has QUERY in its method dropdown since v1.6.0. Postman doesn't list it yet, though you can type it as a custom method.
On the server side, a minimal Node.js handler needs zero special configuration — Node's HTTP parser already accepts QUERY, so req.method === "QUERY" just works.
Should you adopt QUERY now?
For internal APIs: yes, cautiously. You control both ends. If your stack passes QUERY through (test it — one curl tells you), you get honest semantics today, and safe retries from your service mesh for free.
For public APIs: offer it alongside POST /search, not instead. Your consumers' frameworks, SDKs, and corporate proxies are on their own timelines. The graceful pattern is the one HTTP always rewards: support both, advertise QUERY via Accept-Query, deprecate the workaround later.
For caching: wait. Let CDNs ship well-tested body-aware cache keys before you let intermediaries cache QUERY responses.
FAQ
Is QUERY a replacement for GET?
No. If your query fits comfortably in a URL, GET is still right — simpler, universally cached, zero preflight. QUERY replaces POST /search, not GET.
Is the QUERY method cacheable?
Yes — that's much of the point. Unlike POST, QUERY responses are explicitly cacheable, with the request body as part of the cache key.
Does my server need to support QUERY?
Yes. It's a real method on the wire — if your framework only routes classic verbs, you'll get a 405. Node.js parses it natively today; most frameworks are catching up.
Can I test QUERY without writing a server?
https://echo.postmateclient.com/ accepts QUERY (and any other method) and echoes the request back as JSON. The long-standing echo services predate the RFC and reject it.
Further reading: RFC 10008 at the IETF datatracker · RFC Editor info page
Top comments (1)
The introduction of the QUERY method as defined in RFC 10008 addresses a long-standing issue in API design, particularly with workarounds like
POST /search. I appreciate how the QUERY method combines the safety and idempotence of GET with the ability to carry a request body like POST, which is especially useful for complex queries that exceed URL length limits or require nested conditions. TheAccept-Queryresponse header is also a thoughtful addition, allowing resources to advertise supported query formats. How do you envision the adoption of the QUERY method impacting existing API gateways and intermediary services, which are currently tuned for the semantics of GET and POST requests?