DEV Community

Rohan Shukla
Rohan Shukla

Posted on

🧩 How to Pass a Request Body in a GET Request? Meet the New HTTP QUERY Method (RFC 10008)

⚡ 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
Enter fullscreen mode Exit fullscreen mode
  • 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 }
}
Enter fullscreen mode Exit fullscreen mode
  • 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 } }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

QUERY Request

QUERY /api/products HTTP/1.1
Host: shop.com
Content-Type: application/json
Accept: application/json

{ ...payload above... }
Enter fullscreen mode Exit fullscreen mode

📊 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();
}
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

🌐 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
Enter fullscreen mode Exit fullscreen mode
  • 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 OPTIONS or the Accept-Query header 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 ETag and If-Modified-Since for 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)