Skip to main content

HTTP QUERY Method Explained: The REST Fix for GET vs POST (RFC 10008)

The HTTP QUERY method (RFC 10008) is a safe, idempotent, cacheable request with a body — the REST method that ends the GET-vs-POST workaround. Full guide.

9 min read
Cover for the HTTP QUERY method guide: RFC 10008's safe, idempotent, cacheable request method with a body, explained for REST API designers

The HTTP QUERY method (RFC 10008, June 2026) is a new REST request method that is safe and idempotent like GET but carries the query in a request body like POST — so large, structured queries finally get HTTP-layer caching and automatic retries. It’s the first general-purpose method HTTP has gained since PATCH in 2010, and it closes a design gap REST API developers have been working around for 25 years. If you’ve ever tunneled a read-only search through POST and silently given up caching and retry safety, this method exists because of you.

THE HTTP QUERY METHOD AT A GLANCE

RFC 10008

Proposed Standard

published June 2026

Safe

+ idempotent

retryable by definition

URL + body

cache key

shared caches can store results

16 yrs

since the last new method

PATCH, RFC 5789 (2010)

TL;DR

  • QUERY is a new HTTP request method that sends a query in the request body while guaranteeing the operation is safe and idempotent — no state change, freely retryable, and cacheable by proxies and CDNs.
  • It exists because GET can’t reliably carry a body (the spec gives GET bodies “no defined semantics”, and URLs cap out around 2,000–8,000 characters) while POST forfeits caching and automatic retries even for purely read-only queries.
  • The cache key for a QUERY request is the URL plus the request body, so two identical searches can be served from the edge without touching your origin — something POST-based search endpoints will never get.
  • It’s already real: Node.js parses QUERY natively (21.7.2+/22+), Fastify supports it via addHttpMethod(), nginx landed basic support, ASP.NET Core recognizes it in .NET 11 previews, and OpenAPI 3.2 models it — but browsers’ fetch() can’t send it yet.
  • My take: design new server-to-server search/filter/report endpoints as QUERY-shaped now (single query document in the body, mandatory Content-Type), even if you expose them via POST today. The migration later becomes a method-name change.

What Is the HTTP QUERY Method?

The HTTP QUERY method is a safe, idempotent request method, defined in RFC 10008, that asks a resource to run a query described by the request body and return the result. The body — with a mandatory Content-Type — carries the query parameters, so the URL no longer has to. Unlike POST, the server promises the operation changes nothing; unlike GET, the query can be as large and structured as you want: JSON documents, GraphQL queries, SQL-ish filters, JSONPath expressions.

The RFC’s own framing is precise: a QUERY request asks “the target resource to perform a query operation within the scope of that target resource.” Two guarantees make everything else possible. First, safety: “the client does not request or expect any change to the state of the target resource.” Second, idempotency: QUERY requests “can be retried or repeated when needed, for instance, after a connection failure.”

That second sentence is the quiet superpower. A dropped connection mid-POST leaves your client guessing — did the server process it? A dropped connection mid-QUERY is a non-event: any client, library, or proxy may resend it without asking.

Diagram showing the 25-year gap in HTTP's method table: GET is safe and cacheable but has no body, POST has a body but is unsafe and uncacheable, and the new QUERY method provides both — safe, idempotent, cacheable, with a request body

Why HTTP Needed a New Method

Here’s the design flaw we all normalized: HTTP made you choose between honest semantics and a request body.

GET is the semantically correct method for reads. Every cache, proxy, prefetcher, and crawler on Earth understands it. But RFC 9110 gives content in a GET request “no generally defined semantics” — intermediaries may drop it, some servers reject it, and browsers won’t send it. So real query data had to squeeze into the URL, which breaks somewhere between 2,000 and 8,000 characters depending on the browser, proxy, and server in the chain.

POST takes any body you like. But POST is defined as potentially unsafe and non-idempotent, so every intermediary treats your read-only search like a payment submission: no shared caching, no automatic retry, no prefetching. Every GraphQL query — explicitly read-only by design — loses HTTP-level caching and retry safety the moment it ships as POST.

The industry’s workarounds tell the story better than any spec rationale:

THE WORKAROUND ERA VS QUERY

What read-heavy APIs did for two decades, and what RFC 10008 replaces it with.

BEFORE — THE HACKS

Tunneling reads through the wrong method

  • Elasticsearch ships GET-with-body for _search — technically undefined behavior that some proxies silently drop
  • GraphQL standardizes on POST /graphql for every query — zero HTTP caching, custom retry logic in every client
  • REST APIs grow POST /orders/search endpoints that look like writes to every tool in the chain
  • Teams base64-encode JSON filters into query strings until the URL length limit bites

AFTER — RFC 10008

One method that says what it means

  • QUERY /orders carries the full filter document in the body with a mandatory Content-Type
  • Safety and idempotency are guaranteed by the method itself — proxies can cache, clients can retry
  • The cache key incorporates the body, so identical queries hit the edge cache
  • Accept-Query lets servers advertise exactly which query formats they accept

The workarounds all worked. They also all lied to the infrastructure — and the infrastructure priced that lie in lost caching and manual retry code.

This isn’t a new idea, which makes the 18-year journey instructive. WebDAV had a body-carrying SEARCH method back in RFC 5323 (2008), but it never escaped WebDAV’s orbit. The IETF HTTP working group adopted draft-ietf-httpbis-safe-method-w-body in 2021, initially to generalize SEARCH, renamed it QUERY by draft-02 in 2022 to shed the WebDAV baggage, and shipped RFC 10008 after fourteen draft revisions. The author list explains the industry buy-in: Julian Reschke (greenbytes, co-editor of the core HTTP specs), James Snell (Cloudflare), and Mike Bishop (Akamai). When the two largest CDNs co-author a caching-focused method, they intend to implement it.

Timeline of the HTTP QUERY method's standardization: WebDAV SEARCH in RFC 5323 (2008), the workaround era of Elasticsearch GET-with-body and GraphQL-over-POST (2015–2020), the httpbis draft adoption (2021), the rename from SEARCH to QUERY (2022), and RFC 10008 as Proposed Standard in June 2026

How QUERY Works on the Wire

A QUERY request looks like a POST that tells the truth. Here’s the RFC’s canonical example — a form-encoded query against a contacts collection:

A MINIMAL QUERY EXCHANGE

The body carries the query; Content-Type is mandatory; the response is an ordinary, cacheable 200.

REQUEST QUERY

QUERY /contacts HTTP/1.1

Host: api.example.com

Content-Type: application/x-www-form-urlencoded

Accept: application/json

select=surname,givenname,email&limit=10

RESPONSE 200 OK

HTTP/1.1 200 OK

Content-Type: application/json

Cache-Control: max-age=60

[ ...ten contacts... ]

Swap the Content-Type for application/json, application/graphql, or your own media type — the method doesn't care, the resource defines what queries mean.

Beyond the basic exchange, RFC 10008 nails down four behaviors that make QUERY more than “POST, but pinky-promise it’s safe”:

1. Content-Type is not optional. Servers “MUST fail the request if the Content-Type request field is missing or is inconsistent with the request content.” No content sniffing, no guessing — a sharp break from POST’s anything-goes reality.

2. Discovery via Accept-Query. A server advertises QUERY support and its accepted formats with a response header using Structured Field syntax:

OPTIONS /contacts HTTP/1.1
Host: api.example.com

HTTP/1.1 204 No Content
Allow: GET, HEAD, OPTIONS, QUERY
Accept-Query: application/x-www-form-urlencoded, application/jsonpath

One subtlety worth knowing: the Accept-Query value “applies to every URI on the server that shares the same path” — the URL’s query component is ignored for this purpose.

3. Results can get their own URIs. A 2xx response may include a Location header naming a URI you can later GET to re-run the equivalent query, or a Content-Location naming a resource that holds this specific result snapshot. That turns an expensive ad-hoc query into a shareable, bookmarkable, cacheable resource — a genuinely RESTful touch POST never standardized for reads.

4. Redirects behave like you’d hope. A 301 or 308 means repeat the QUERY at the new target; 303 means fetch the result with a plain GET. Crucially, the legacy exception that lets clients degrade a redirected POST into GET “does not apply to QUERY requests” — your query body survives the redirect.

Caching: The Actual Killer Feature

The RFC is blunt about the mechanics: “The cache key for a QUERY request MUST incorporate the request content and related metadata.” URL plus body, hashed, stored. Identical query, identical key, edge-served response.

Diagram of HTTP QUERY caching flow: a client sends QUERY with a body, the CDN computes a cache key from the URL plus the request body, forwards a miss to the origin, caches the 200 response, and serves the next identical query from the edge without contacting the origin

Caches are even allowed to normalize semantically insignificant differences — stripping content encoding, or applying format-aware knowledge (JSON key order, whitespace) — so trivially different bodies can still share a cache entry. If that makes you nervous, no-transform opts out.

Think about what this does for a search-heavy API. Today, your “cache” for POST /search is an application-level Redis layer you built, keyed by a hash you invented, invalidated by rules you maintain. QUERY moves that entire concern into infrastructure that already exists at every hop between the user and your origin. This is the same architectural instinct as moving analytics to the edge with Cloudflare Workers — push work to the layer that’s already positioned to do it.

💡 Key insight: QUERY doesn’t make anything possible that was impossible before. It makes the default correct — caching, retries, and semantics you previously had to hand-build now fall out of the method name.

QUERY vs GET vs POST

The one-table version, straight from the RFC’s own comparison:

PropertyGETQUERYPOST
Safe (no state change)YesYes — by definitionNo guarantee
Idempotent (retryable)YesYes — by definitionNo guarantee
Request bodyNo defined semanticsYes — carries the queryYes
Shared-cache friendlyYes (URL key)Yes (URL + body key)Effectively no
Query size limit~2K–8K chars in URLBody-sizedBody-sized
Sensitive params in logsURL is logged everywhereBody rarely loggedBody rarely logged
CORS without preflightYesNo — always preflightsSometimes

That security row deserves a sentence: because the query moves out of the URL, it stops leaking into access logs, browser history, referrer chains, and analytics pipelines. RFC 10008’s Security Considerations calls this out as a real benefit for sensitive queries — with the matching warning that servers minting result URIs must not embed sensitive query parts back into them.

Where QUERY Works Today (July 2026)

The honest adoption picture, one month after publication:

Adoption map for the HTTP QUERY method as of July 2026: works now in Node.js 21.7.2+/22+, Fastify via addHttpMethod, nginx basic support, and OpenAPI 3.2; in progress in ASP.NET Core .NET 11 previews, Spring Framework PR 34993, Ruby on Rails proposal, and CDNs; not yet in browsers, curl's native verbs, Express, Django, FastAPI, and CORS safelisting

On the working side: Node.js parses QUERY natively since 21.7.2 and 22+, and Fastify exposes it with one line. nginx landed basic upstream support, Spring Framework has an active PR (#34993), Rails has a live core proposal, and ASP.NET Core recognizes it in .NET 11 previews.

OpenAPI 3.2 also models QUERY operations — which means generated clients will offer it before most hand-written servers accept it.

Here’s a working Fastify endpoint today:

import Fastify from 'fastify';

const app = Fastify();
app.addHttpMethod('QUERY', { hasBody: true });

app.route({
  method: 'QUERY',
  url: '/products',
  handler: async (req, reply) => {
    const results = await search(req.body); // body IS the query
    reply.header('cache-control', 'public, max-age=60');
    return results;
  }
});

And from any client that lets you set a custom method:

curl -X QUERY https://api.example.com/products 
  -H 'content-type: application/json' 
  -d '{ "category": "keyboards", "maxPrice": 200, "sort": "rating" }'

The missing piece is the browser. fetch() can’t send QUERY until the WHATWG Fetch spec adds it, and even then QUERY is not a CORS-safelisted method, so cross-origin requests will always preflight. In 2026, QUERY is a server-to-server and API-gateway story — which is exactly where search, reporting, and internal query traffic lives anyway. If you build backend-for-frontend layers in Node.js, that BFF-to-service hop is the perfect first deployment.

Common Mistakes to Avoid

Four more, seen in the wild already:

  1. Omitting Content-Type. Legal-ish on POST, a mandatory failure on QUERY. Fail these requests loudly, as the RFC requires — don’t sniff.
  2. Forgetting the CORS preflight. QUERY from browser-adjacent contexts will send OPTIONS first. Your gateway needs Access-Control-Allow-Methods: QUERY or every request dies preflight.
  3. Leaking query content into result URIs. If QUERY returns a Location for later GETs, that URL will be logged everywhere. Use opaque result IDs, not serialized query parameters.
  4. Assuming your WAF and proxies pass it through. Older intermediaries reject unknown methods. Test the full path — one method-allowlist in a corporate proxy can 405 your rollout.

Should You Adopt QUERY Now?

THE ADOPTION CALL

For teams designing or evolving REST APIs in 2026.

The pros

  • Correct semantics for read-only queries with real bodies — no more lying to infrastructure
  • HTTP-layer caching for search endpoints, with the body in the cache key
  • Free retry safety on flaky networks — no custom retry-with-dedupe logic
  • Sensitive query params move out of URLs, logs, and referrer chains
  • Backed by Cloudflare and Akamai authorship plus OpenAPI 3.2 — the tooling wave is coming

The cons

  • No browser fetch() support yet — server-to-server only for now
  • Framework support is uneven: Fastify yes; Express, Django, FastAPI not yet
  • Always triggers CORS preflight — never a "simple request"
  • Old proxies and WAFs may 405 an unknown method
  • Cache normalization is subtle — a misconfigured cache can serve wrong results

Adopt the shape now, the verb where your stack allows. Design query endpoints as single-body query documents behind POST today, and flipping to QUERY later is a rename, not a rewrite.

A PRAGMATIC MIGRATION PATH

How I'd move a search-heavy API to QUERY without betting the roadmap on it.

  1. STEP 1

    Make endpoints QUERY-shaped behind POST

    One query document in the body, mandatory Content-Type, handler verifiably side-effect free. This costs nothing and pays off regardless.

  2. STEP 2

    Dual-route QUERY and POST to the same handler

    Where your stack supports it (Node/Fastify, nginx, .NET 11 previews), accept both verbs. Advertise support via Allow and Accept-Query on OPTIONS.

  3. STEP 3

    Turn on HTTP caching for the QUERY route

    Add Cache-Control, watch your origin query load drop for repeated searches, and validate cache-key behavior with your CDN as edge support lands.

  4. STEP 4

    Deprecate the POST tunnel when clients catch up

    OpenAPI 3.2 already models QUERY, so generated clients arrive first. Keep POST as a compatibility alias as long as you need.

    Why this step existsSame handler, honest semantics, and caching you didn’t have to build.

Before you ship a QUERY endpoint

Track progress as you work through the list

0%

0/6 done

FAQ

Questions readers usually have

Common questions about the HTTP QUERY method and RFC 10008.

The Bottom Line

REST API design has spent 25 years contorting reads into methods that either couldn’t carry the query or couldn’t admit it was a read. The HTTP QUERY method ends that trade-off with the least glamorous, most durable kind of fix: a verb that tells the infrastructure the truth, and infrastructure that rewards honesty with caching and retries you no longer have to build.

You don’t need to rewrite anything this quarter. But every new search, filter, or reporting endpoint you design from today should be QUERY-shaped: one query document in the body, a mandatory content type, and a handler with zero side effects. Do that, and adopting the verb itself — when your framework, gateway, and CDN all catch up — becomes a one-line change instead of a migration project.

If you found this useful, read Node.js Backend for Frontend Developers next — the BFF layer is exactly where QUERY will land first — or see how FastAPI’s app.frontend() rethinks another old default.

Sources


Written for umesh-malik.com — no-fluff technical writing on AI, Web Dev, and Engineering.

Share this article:
X LinkedIn