For decades, web developers have faced an awkward choice when building search and query endpoints: use GET and cram everything into the URL, or use POST and lose caching, retries, and clear read-only semantics. In June 2026, the IETF finally closed this gap by publishing RFC 10008: The HTTP QUERY Method — a brand-new HTTP verb designed specifically for complex, read-only queries.
In this article, we'll cover what the QUERY method is, the problem it solves, how to use it in practice, and how it compares to GET and POST.

What Is the HTTP QUERY Method?
QUERY is a new HTTP request method that asks the server to process the request body as a query and return the result — without changing any state on the server. Officially:
Safe — it performs a read-only operation, like GET
Idempotent — sending the same request twice produces the same effect, so clients, proxies, and CDNs can safely retry it
Cacheable — responses can be cached, with the request body included in the cache key
Body-capable — the query payload travels in the request body, like POST
In one line: QUERY = the body of POST + the semantics of GET. No existing HTTP method combined all four of those properties before.
The specification is intentionally format-agnostic. It doesn't define a query language — the body can be JSON, SQL, GraphQL, form-encoded data, or anything else the server declares support for. QUERY defines the transport semantics, and the resource decides how to interpret the content.
The Problem QUERY Solves
Why GET falls short
GET is semantically perfect for queries — safe, idempotent, cacheable — but it has no request body. All query data must be encoded into the URL, which creates real problems:
Length limits. Browsers and intermediaries cap URLs somewhere between ~2,000 and ~8,000 characters, and you never know which system in the chain will truncate or reject a long one.
Encoding overhead. Complex nested filters or structured queries become an unreadable mess of percent-encoded characters.
Privacy leakage. URLs end up in server logs, browser history, bookmarks, analytics tools, and Referer headers. Query data in the URL is far more exposed than data in a body.
Cache pollution. Every combination of query inputs becomes a "distinct resource" in the URL space.
Why POST falls short
POST solves the body problem, but it's a semantic black box:
Not safe or idempotent (by contract). Even if your endpoint only reads data, HTTP infrastructure must assume a POST might mutate state.
No caching. CDNs and reverse proxies won't cache POST responses by default.
No automatic retries. If a POST times out mid-flight, a client can't safely retry — it might duplicate a side effect.
Misleading intent.
POST /searchtells every layer of your stack "something is being changed here," which is simply false.
This is exactly why GraphQL — where every query is read-only by design — has struggled with HTTP-level caching for years: everything goes over POST, and developers pile on workarounds like persisted queries and custom CDN rules.
QUERY: the best of both
QUERY carries the payload in the body and explicitly tells every client, proxy, cache, and server in the chain: "this is a read operation — cache it, retry it, repeat it freely."
How to Use the QUERY Method
Basic request format
A QUERY request looks like a POST, but with the QUERY verb and a mandatory Content-Type header describing the body format:
QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/json
Accept: application/json
{
"filter": {
"city": "Ahmedabad",
"tags": ["client", "active"],
"created_after": "2025-01-01"
},
"sort": "name",
"limit": 50
}The server processes the body as a query and responds like any read request:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=300
[ { "name": "...", ... } ]Using QUERY in JavaScript (fetch)
HTTP methods are just strings, so fetch() can send QUERY today:
javascript
const response = await fetch('https://api.example.com/products/search', {
method: 'QUERY',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
filter: { category: 'laptops', price: { max: 60000 } },
sort: 'price_asc',
page: 1,
}),
});
const results = await response.json();CORS note: QUERY is not a CORS-safelisted method, so cross-origin QUERY requests from browsers will trigger a preflight OPTIONS request. Make sure your server includes QUERY in Access-Control-Allow-Methods.
Using QUERY in PHP (cURL)
php
$payload = json_encode([
'filter' => ['status' => 'active', 'city' => 'Ahmedabad'],
'limit' => 50,
]);
$ch = curl_init('https://api.example.com/contacts');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'QUERY',
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
],
]);
$response = curl_exec($ch);
curl_close($ch);
$results = json_decode($response, true);Handling QUERY in Laravel
Laravel's router lets you match arbitrary HTTP verbs with Route::match():
php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::match(['QUERY'], '/products/search', function (Request $request) {
$query = json_decode($request->getContent(), true);
$products = Product::query()
->when($query['filter']['category'] ?? null,
fn ($q, $cat) => $q->where('category', $cat))
->when($query['filter']['price']['max'] ?? null,
fn ($q, $max) => $q->where('price', '<=', $max))
->orderBy('price')
->paginate($query['limit'] ?? 20);
return response()->json($products)
->header('Cache-Control', 'public, max-age=300');
});Since the operation is read-only, remember to keep your handler genuinely side-effect free — that's the contract QUERY makes with the rest of the web.
Discovering server support: the Accept-Query header
RFC 10008 also introduces a new response header, Accept-Query, which lets a resource advertise that it supports QUERY and which media types it accepts:
http
HTTP/1.1 200 OK
Content-Type: text/html
Accept-Query: application/json, application/x-www-form-urlencodedAlternatively, a client can simply attempt a QUERY request. A server that doesn't support it responds with 405 Method Not Allowed (plus an Allow header listing supported methods), and the client can fall back to GET or POST.
Error handling status codes
The RFC recommends specific status codes for query failures:
400 Bad Request — the request has no media type information
405 Method Not Allowed — the resource doesn't support QUERY
406 Not Acceptable — the client's requested response format isn't supported
415 Unsupported Media Type — the query format (e.g., SQL body sent to a JSON-only endpoint) isn't supported
422 Unprocessable Content — the format is fine but the query itself can't be processed (e.g., valid SQL referencing a non-existent table)
QUERY vs GET vs POST: Full Comparison
PropertyGETPOSTQUERYRequest bodyNo (undefined behavior)YesYesSafe (read-only)YesNoYesIdempotentYesNoYesCacheable responsesYes (by URL)Rarely, with hacksYes (URL + body in cache key)Safe automatic retriesYesNoYesQuery data in URL/logsYes (exposed)NoNoSize limit on query data~2K–8K chars (URL)Practically nonePractically noneSemantic clarity for readsClearMisleadingClearCORS-safelistedYesYes (simple cases)No (preflight required)Ecosystem support (2026)UniversalUniversalEmerging
Key Benefits of QUERY
HTTP-native caching for complex queries. The cache key incorporates the request body and its metadata, so CDNs and reverse proxies can serve identical queries from cache — something POST could never offer. Caches may even normalize bodies (e.g., reordering JSON keys) to improve hit rates.
Safe retries and resumption. Because QUERY is idempotent, a client or proxy can automatically repeat or restart a request after a network failure without worrying about partial state changes.
Cleaner security posture. Query criteria stay out of URLs, so they don't leak into access logs, browser history, bookmarks, or analytics.
Honest API semantics. Your infrastructure — monitoring, gateways, WAFs, load balancers — can finally distinguish "big read" from "write" without out-of-band conventions.
A clean path for GraphQL and RPC-style APIs. Read-only GraphQL queries and JSON-RPC calls currently forced over POST can migrate to QUERY and regain HTTP-layer caching without changing the query language at all.
Adoption: What to Expect
RFC 10008 is a finalized Standards Track document (co-authored by engineers from Cloudflare and Akamai), but standardization and ecosystem adoption run on different clocks. Legacy proxies, enterprise middleware, and older frameworks may reject unfamiliar methods until vendors update — the same slow-burn path PATCH followed after its standardization.
The practical strategy for 2026:
New internal APIs: adopt QUERY now where you control both client and server.
Public APIs: support QUERY alongside a POST fallback, and advertise it via
Accept-Query.Watch the ecosystem: keep an eye on curl, browser fetch implementations, CDN documentation, and your framework's release notes for first-class QUERY support.
Conclusion
The HTTP QUERY method fixes one of the web's oldest design gaps: there was simply no way to send a large, structured, read-only query with proper HTTP semantics. GET couldn't carry the data; POST couldn't carry the meaning. QUERY carries both.
If you've ever built a POST /search endpoint and felt slightly guilty about it — RFC 10008 is your redemption. Start experimenting with it in your own APIs today, keep a POST fallback for compatibility, and enjoy caching, retries, and semantics that finally match what your code actually does.
