DEV Community

🧩 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
  • 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 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

Comments

No comments yet. Start the discussion.