RFC 10008 Just Gave HTTP a Fourth Read-Only Method, Here's Why It Matters

RFC 10008 Just Gave HTTP a Fourth Read-Only Method, Here’s Why It Matters

The new HTTP QUERY method (RFC 10008) finally bridges the gap between GET and POST for complex queries. But does the web need another verb, or is this a solution in search of a problem?

The IETF published RFC 10008 this week, and if you’ve ever stared at a 400 Bad Request because your search filter was too long for a URL, this one is for you. The new HTTP QUERY method splits the difference between GET and POST in a way that feels obvious in hindsight, but whether it’s a long-overdue fix or another layer of protocol cruft is worth unpacking.

QUERY sends its payload in the request body, exactly like POST, but explicitly marks itself as safe and idempotent. Responses are cacheable. Retries are automatic. It’s the method that should have existed for GraphQL, complex search APIs, and every developer who ever hacked a POST endpoint for a read-only operation. But adding a new HTTP method is not a trivial decision, and the community reaction has been… spirited.

The Problem That Wouldn’t Die

The core tension has been there since HTTP/1.1. GET is the right method for safe, idempotent, cacheable read operations. But GET doesn’t carry a body. All query data has to fit in the URL, and URLs have limits, browsers cap somewhere between 2,000 and 8,000 characters depending on implementation, and intermediaries are even less predictable. The RFC itself notes that while senders and recipients are recommended to support at least 8000 octets, this recommendation often falls apart in practice.

When your query gets complex, multi-field filters, deeply nested criteria, long search strings, GET breaks down. Developers have been filling the gap with POST for years. But POST carries no safe-or-idempotent guarantee. From a cache’s perspective, POST is a black box. The response can’t be cached, the request can’t be automatically retried, and the semantics imply state mutation even when none is happening.

GraphQL is the poster child here. Every GraphQL query, explicitly read-only by design, loses HTTP-level caching and auto-retry safety because it has to route through POST to accommodate complex query payloads. Developers patch this with persisted queries, CDN-specific POST caching rules, and other workarounds. It’s inelegant, and it accumulates invisible operational debt.

What QUERY Actually Does

The QUERY method takes the body flexibility of POST and attaches the semantics of GET. Here’s the comparison table straight from the RFC (Table 1), which lays out the differences cleanly:

Property GET QUERY POST
Safe yes yes potentially no
Idempotent yes yes potentially no
URI for query itself yes (by definition) optional (Location response field) no
URI for query result optional (Content-Location response field) optional (Content-Location response field) optional (Content-Location response field)
Cacheable yes yes yes, but only for future GET or HEAD requests
Content (body) “no defined semantics” expected (semantics per target resource) expected (semantics per target resource)

The critical insight is that QUERY is both safe and idempotent. Safe means it has no significant side-effects, repeating the request won’t change server state. Idempotent means repeating it produces the same result. These two properties together unlock caching and automatic retries at the protocol level, without any application-layer hacks.

A basic QUERY request looks like this:

QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Accept: application/json

select=surname,givenname,email&limit=10&match=%22email=*@example.*%22

The server responds with 200 OK and the query results. But the real power comes from the redirection and location features. A server can respond with 303 See Other, providing a Location header pointing to a cached result resource:

HTTP/1.1 303 See Other
Content-Type: text/plain
Location: /contacts/stored-queries/42

See stored query at "/contacts/stored-queries/42".

This pattern is particularly useful for CDNs: the result gets stored at a stable URL that can be cached and served like any GET response. Clients can then fetch that resource repeatedly without resending the query payload.

The Caching Complexity That Has Everyone Nervous

The most contentious part of the specification is how caching works. The cache key for a QUERY request MUST incorporate the request content and related metadata. This is inherently more complex than caching GET responses, where the cache key is just the URL.

The RFC allows for normalization, caches MAY remove semantically insignificant differences from request content to improve cache hit rates. This could include:

  • Removing content encodings
  • Normalizing based on media subtype suffixes (e.g., “+json”)
  • Normalizing based on knowledge of the content’s semantics

But normalization is a minefield. The Hacker News thread on the RFC captured the anxiety well. One commenter pointed out that “an unbounded and user-controlled cache key… implies cache busting would be trivial.” If you can generate unique request bodies, you can flood the cache with unique entries. The spec acknowledges this risk: “Caches that normalize QUERY content incorrectly or in ways that are significantly different from how the resource processes the content can return an incorrect response if normalization results in a false positive.”

The pragmatic expectation is that most CDN-level implementations will use a collision-resistant hash of the body as part of the cache key, which sidesteps normalization problems but also means the cache can’t do smart parameter reordering. Whether this matters depends on whether your query format treats a=1&b=2 the same as b=2&a=1, which application/x-www-form-urlencoded does, but arbitrary JSON payloads may not.

What This Means for REST APIs and Microservices

For REST APIs, the most immediate impact is on complex filter and search endpoints. If you’ve built an endpoint that accepts a JSON filter body over POST because URL encoding was too unwieldy, search facets, aggregation pipelines, multi-condition filters, QUERY is the semantically correct replacement. It signals to every layer of your infrastructure that this is a read operation, enabling caching configurations that POST simply can’t support.

The Accept-Query header is a smart addition. Servers can advertise which query formats they support:

Accept-Query: "application/jsonpath", application/sql;charset="UTF-8"

This enables content negotiation for queries themselves, clients can discover whether the server supports SQL, JSONPath, XSLT, or custom formats, and choose accordingly. The RFC includes extensive examples showing queries using SQL, XSLT, and JSONPath against the same endpoint, with the server responding in CSV, JSON, or XML based on the client’s Accept header.

For microservices communication, the benefits are more nuanced. If you control the entire stack, you can already implement safe, idempotent, cacheable queries using POST along with custom headers. But the value of QUERY is that it’s standardized, every client, server, proxy, and CDN in the chain can recognize it without application-specific configuration. As one commenter on the IETF mailing list put it, “you can’t communicate idempotency to caching layers throughout the network” with POST alone.

The Adoption Mountain

RFC 10008 is a finalized standard, not a shipping feature. Actual adoption requires updates across the entire HTTP stack: client libraries (curl, fetch, axios), server frameworks (Express, FastAPI, Django, Spring), and CDN caching engines.

The fact that Cloudflare’s James Snell and Akamai’s Mike Bishop co-authored the spec is a meaningful signal. Both companies are positioned to ship CDN-level QUERY support earlier than most framework integrations. But browser fetch() support requires WHATWG action, and that will take time. The WHATWG issue for HTML form support of QUERY is open but hasn’t seen movement yet.

The intermediate proxy problem is real. WebDAV’s SEARCH method (RFC 5323) has existed for nearly two decades and never gained traction precisely because intermediaries strip bodies from unrecognized methods or reject them outright. The spec acknowledges this indirectly: “A QUERY request from user agents implementing Cross-Origin Resource Sharing (CORS) will require a ‘preflight’ request, as QUERY does not belong to the set of CORS-safelisted methods.” This means every cross-origin QUERY request will trigger an OPTIONS preflight, adding latency.

Is the Name Confusing?

The Hacker News thread quickly identified a naming problem: “the term ‘query’ is already used to refer to HTTP requests in general.” The RFC’s title, “The HTTP QUERY Method”, invites confusion with query strings, query parameters, and database queries. One commenter suggested “IPOST” (for idempotent POST) as an alternative.

The RFC’s Appendix B addresses the naming decision. The authors considered reusing WebDAV’s SEARCH method, which has similar semantics, but rejected it because “they all originate from the WebDAV activity, about which many have mixed feelings.” They also note that WebDAV’s methods use a generic request content media type, while QUERY is designed to support multiple query formats through content negotiation. The name “QUERY” was chosen because it “captures the relation with the URI’s query component well.”

Whether this naming causes real-world confusion will depend on adoption. If QUERY becomes widely used, the ambiguity will fade. If it remains a niche method, developers will continue to use “query” to mean both the operation and the method, and the cognitive overhead persists.

The Verdict

RFC 10008 solves a real problem: the inability to express safe, idempotent, cacheable read operations with complex payloads within the existing HTTP method set. The workarounds, POST with body, long query parameters, custom headers, are functional but fragile. Having an explicit method for this pattern is architecturally cleaner.

The risks are real. Caching complexity, intermediary compatibility, CORS preflight overhead, and the long tail of framework adoption all work against immediate utility. The Lobsters comment that called it “about 20 years longer than it should have” is paired with “now let’s see how many decades until this is actually usable.”

What developers should do now: identify existing POST-for-query endpoints in your API that could be refactored once support lands. If you’re building GraphQL services, watch for framework-level support for serving queries over QUERY. The spec is clean and well-reasoned, it deserves to succeed, but success depends on CDNs and browser vendors shipping support ahead of the framework ecosystem.

And yes, this is a reminder that radical bets against traditional client-server architecture can sometimes be more practical than waiting for the HTTP spec to catch up. But when the spec does catch up, it’s worth paying attention.

Share:

Related Articles