HTTP QUERY: A Safe, Cacheable Method With a Body
The IETF standardized HTTP QUERY in RFC 10008, the first new HTTP method since 2010. What it does, when to pick it over GET or POST, and how to try it today.

For fifteen years, the answer to "how do I send a search request that's too big for a URL?" was the same awkward shrug: POST it, and try not to think about what you just told the protocol. That workaround finally has a real name. In June 2026 the IETF published RFC 10008 and gave HTTP its first brand-new method since PATCH landed back in 2010. It's called QUERY, and it does one specific thing well. A read request that carries a body.
Why GET and POST both fall short
Every API that does real searching hits this wall. You have a read that's too complicated for the URL: a filter with a dozen fields, a GraphQL document, an embedding vector for semantic search. Your two classic options both hurt.
GET is the "correct" verb for a read. It's safe (the server isn't expected to change anything), idempotent (retry it all day, same result), and cacheable. The catch is that everything travels in the URL. Servers and proxies cap URL length somewhere around 4 to 8 KB, so a big query just falls over. And whatever you put in that URL lands in access logs, browser history, and Referer headers. Your customer's search filters, or an API key someone stuffed in a query param, now live in a dozen log files you didn't mean to write to.
POST has none of those size or privacy problems, because the data rides in the body. But POST means "I'm changing something." It isn't safe and isn't idempotent, so a cache won't store the response and a proxy won't automatically retry a failed one. Point a POST at a read-only search endpoint and you've quietly lied to every intermediary between you and the server. It works. It's just semantically wrong, and you give up caching and safe retries to get it.
So teams POST their searches, shrug, and move on. QUERY is the verb that stops the shrug.
| Method | Body? | Safe | Idempotent | Cacheable |
|---|---|---|---|---|
| GET | No (URL only) | Yes | Yes | Yes |
| POST | Yes | No | No | No |
| QUERY | Yes | Yes | Yes | Yes |
That table is the whole pitch in four columns. QUERY takes the body from POST and the good manners from GET.
What a QUERY request looks like
Here's the shape of one. The query lives in the body, exactly where you'd want it:
QUERY /products/search HTTP/1.1
Host: shop.example.com
Content-Type: application/json
Accept: application/json
{ "category": "shoes", "size": 42, "inStock": true, "sort": "price" }Content-Type is required here. The spec says the server must reject the request if it's missing or doesn't match the actual content, which closes off a whole class of ambiguity. The server processes the query and answers like any other read:
HTTP/1.1 200 OK
Content-Type: application/json
{ "results": [ ... ], "total": 128 }Nothing changed on the server. Send the identical request again and you get the identical answer. That's the property everything else hangs off.
Who actually wrote this
RFC 10008 comes from the IETF HTTP Working Group, authored by Julian Reschke, James Snell, and Mike Bishop (of greenbytes, Cloudflare, and Akamai). It's a Proposed Standard, the stage where a spec is considered stable and implementers are meant to start shipping it.
Caching a request body is the genuinely new part
This is where QUERY stops being "GET with a body" and gets interesting. A normal cache keys everything on the URL. Two GETs to the same URL are the same request, so one stored response serves both. But two QUERY requests to the same URL can carry totally different bodies and deserve different answers.
So RFC 10008 changes the rule. The cache key must include the request content, not just the URL. A cache storing a QUERY response has to fold the body into its key. That sounds like a footnote. It isn't. It means your CDN, your reverse proxy, and every caching layer in the path has to learn a trick it has never done before, and most of them haven't yet.
The spec does leave room for smarts. A cache may strip "semantically insignificant differences" before keying, so {"a":1,"b":2} and { "b": 2, "a": 1 } can hit the same entry if the cache understands the format. Whether any given CDN does that today is a very different question.
The network path is the long pole
You can send a QUERY request from a client this afternoon. Whether it survives the round trip is another matter. Load balancers, WAFs, API gateways, and CDNs that have never heard of QUERY may strip the body, reject the method, or refuse to cache the response. Origin frameworks are running ahead of the middle boxes. Treat end-to-end QUERY caching as something you test on your real infrastructure, not something you assume.
How a server says it speaks QUERY
Discovery is built in. A resource can advertise support with an Accept-Query response header that lists the query formats it understands:
Accept-Query: application/json, application/sqlIf a server doesn't support QUERY on a resource, it answers 405 Method Not Allowed with an Allow header listing what it does accept, the same way it would for any unsupported method. There's also a neat escape hatch. If a query turns out simple enough to express as a plain URL, the server can reply 303 See Other and redirect the client to a normal GET. Older clients degrade gracefully instead of hitting a wall.
Can you use it today?
On the server side, yes, and it's spreading fast. ASP.NET Core added first-class QUERY support (tracked in dotnet/aspnetcore#61089), so on .NET you can register a QUERY endpoint with the routing primitives:
app.MapMethods("/products/search", new[] { "QUERY" }, (SearchFilter filter, ICatalog catalog) =>
{
return catalog.Search(filter);
});Sending one is just as boring. Any client that lets you set the method string can do it now:
curl -X QUERY https://shop.example.com/products/search \
-H "Content-Type: application/json" \
-d '{ "category": "shoes", "inStock": true }'const res = await fetch("/products/search", {
method: "QUERY",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ category: "shoes", inStock: true }),
});
const data = await res.json();The fetch API is happy to send a custom method with a body. The client was never the hard part. Every hop after it is.
When to reach for QUERY
Don't go rewrite your whole API. QUERY earns its place in one clear situation: a read that's currently a POST only because it wouldn't fit in a URL. That covers a lot of modern surface area.
- Search and filter endpoints with rich, structured criteria.
- Analytics and reporting queries with big parameter blobs.
- GraphQL-style endpoints, where you already POST a query document just to read data.
- Semantic search, where the "query" is a whole embedding vector.
If a request already fits comfortably in a GET, leave it alone. QUERY isn't a replacement for GET. It's a replacement for the guilty POST.
Quick check
Why not just keep POSTing your search endpoints instead of switching to QUERY?
Where this goes next
RFC 10008 is a Proposed Standard as of June 2026, which is the starting gun, not the finish line. Expect origin frameworks and client libraries to pick it up through 2026 and into 2027, with CDNs and proxies trailing behind because body-aware caching is real engineering work. The verb itself is done and stable. The ecosystem around it is the part still being built.
If you build APIs, the practical move now is small. Know that QUERY exists, reach for it on new read-heavy endpoints where you'd otherwise POST, and check whether your infrastructure passes it through before you lean on the caching. HTTP went fifteen years without a new method. The one it just got is worth understanding.
For the client-side plumbing under all this, the async/await and fetch guide covers how requests actually move, and the 2026 JavaScript backend rundown covers where you'd implement a QUERY endpoint in the first place.

Written by
Rhythm Bhiwani
Engineer and relentless builder, happiest reverse-engineering hard problems until they click.
Enjoyed this?
Tap the heart to leave some love.
Be the first to react
Comments
Join the conversation.
Loading comments…


