⚡ A New HTTP Verb for Developers
The QUERY method (RFC 10008, June 2026) solves a long‑standing pain point: sending complex request bodies safely and cacheably without abusing GET or POST.
Because QUERY is safe and idempotent, if a network drop happens, the client can automatically retry the request without risk of duplicating side effects — a major architectural win.
The Problem with GET and POST
GET Example (Fails with Complex Filters)
GET /api/products?category=electronics&tags=wireless,sale,new-arrival&price_min=100&price_max=1000&sort=rating_desc&page=2&limit=20&brand=Sony|Samsung&in_stock=true&discount_gte=10 HTTP/1.1
Host: shop.com
- Too long → URLs hit browser/server length limits.
- Leaky → Query strings show up in logs, browser history, and monitoring tools.
-
Awkward encoding → Nested conditions (
AND/OR) are hard to represent.
POST Example (Breaks Caching)
POST /api/products/search HTTP/1.1
Host: shop.com
Content-Type: application/json
{
"category": "electronics",
"tags": ["wireless", "sale", "new-arrival"],
"price_range": { "min": 100, "max": 1000 }
}
- Not cacheable → POST responses aren’t cached by browsers or CDNs.
- Wrong semantics → POST is meant for creating resources, not fetching.
🚀 The Solution: QUERY
QUERY combines the best of both worlds: request body support like POST, but safe and cacheable like GET.
📦 Example: Advanced Product Search
{
"category": "electronics",
"tags": ["wireless", "sale", "new-arrival"],
"price_range": { "min": 100, "max": 1000 },
"sort": { "field": "rating", "order": "desc" },
"pagination": { "page": 2, "limit": 20 },
"conditions": {
"or": [
{ "brand": "Sony" },
{ "brand": "Samsung" }
],
"and": [
{ "in_stock": true },
{ "discount": { "gte": 10 } }
]
}
}
QUERY Request
QUERY /api/products HTTP/1.1
Host: shop.com
Content-Type: application/json
Accept: application/json
{ ...payload above... }
📊 Core Comparison Matrix
| Metric | GET | POST | QUERY |
|---|---|---|---|
| Intended Use | Simple fetch | Create data | Complex fetch |
| Request Body | ❌ No | ✅ Yes | ✅ Yes |
| Safe & Idempotent | ✅ Yes | ❌ No | ✅ Yes |
| Cacheable | ✅ Yes | ❌ No | ✅ Yes |
| Retry on Drop | ❌ Risky | ❌ Risky | ✅ Safe |
| URI for Query | ✅ Always | ❌ No | ⚠️ Optional via Location
|
| URI for Result | ⚠️ Optional | ⚠️ Optional | ⚠️ Optional via Content-Location
|
| Discovery | ❌ No | ❌ No | ✅ Accept-Query
|
| Conditional Requests | ✅ Yes | ❌ No | ✅ Yes |
| Redirection | ✅ Yes | ✅ Yes | ✅ Yes (QUERY→QUERY or GET) |
🔧 Real-World Code Examples
Frontend (QUERY with fetch):
async function searchProducts(filters) {
const response = await fetch('https://shop.com/api/products', {
method: 'QUERY',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(filters)
});
return response.json();
}
Backend (Express.js):
const express = require('express');
const app = express();
app.use(express.json());
app.all('/api/products', (req, res, next) => {
if (req.method !== 'QUERY') return next();
const filters = req.body;
const products = db.findProducts(filters);
res.setHeader('Cache-Control', 'public, max-age=3600');
res.json(products);
});
🌐 CDN Support for QUERY with Body
RFC 10008 requires caches to incorporate both the request target and the body into cache keys:
Cache Key = Path + Body Hash
Path: /api/products
Body: {"category":"electronics","tags":["sale"]}
Body Hash: abcd1234
Final Key: /api/products:abcd1234
- Cloudflare → Cache rules + body hash
- Akamai → EdgeWorkers extend cache keys
-
Fastly → VCL:
set req.hash += req.body; - AWS CloudFront → Lambda@Edge workaround (rewrite QUERY → GET + body hash)
- Google Cloud CDN → Proxy QUERY through Cloud Functions until native support arrives
🔑 RFC 10008 Extra Features
-
Discovery → Use
OPTIONSor theAccept-Queryheader to check if a resource supports QUERY - Location Header (URI for Query) → Server may assign a URI representing the query definition
- Content-Location Header (URI for Result) → Server may assign a URI representing the result set
-
Conditional Requests → QUERY supports
ETagandIf-Modified-Sincefor cache validation - Redirection → QUERY can be redirected but must remain QUERY or map to GET
- Security → QUERY avoids leaking sensitive data in URIs, but servers must handle generated URIs carefully
❓ FAQ Highlights
- 🛠️ Frameworks → Express, Django, Spring, and FastAPI don’t yet have
app.query(), but you can intercept QUERY as a raw method string - 🌐 Browsers → All major browsers allow sending QUERY via
fetch; tooling may still show it as a custom verb - 📊 Monitoring → Grafana/Prometheus don’t yet classify QUERY; treat it as a custom verb in logs until native support arrives
✨ Closing Thoughts
The QUERY method (RFC 10008, June 2026) is a true architectural upgrade:
- Safe, idempotent, cacheable
- Supports complex request bodies with arrays, sorting, pagination, and nested conditions
- Enables automatic retries after network drops
- Works with CDNs when cache keys include body hashes
- Adds discovery, conditional requests, redirection, and URI assignment for queries/results
👉 For full details, see the official spec: RFC 10008 – The HTTP QUERY Method
Top comments (0)