{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreign43nqenyq6fx3apdwigkwq5nuo26w7zshupxodnivkvxbwrv6se",
    "uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mpuvo72kogj2"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreibtgckrzgxeabkrh24zqb2m7f7xw2wu7czlt2zii3cpeuj75hxw2a"
    },
    "mimeType": "image/webp",
    "size": 119434
  },
  "path": "/hardikgoel/the-http-query-method-rfc-10008-is-here-and-caching-it-correctly-is-harder-than-it-looks-2he6",
  "publishedAt": "2026-07-05T04:55:28.000Z",
  "site": "https://dev.to",
  "tags": [
    "http",
    "node",
    "typescript",
    "webdev",
    "http-queryable",
    "https://github.com/hardik-goel/http-queryable"
  ],
  "textContent": "##  TL;DR\n\n  * HTTP got a new method: **QUERY** (RFC 10008, June 2026). It's a **safe, idempotent, cacheable request that carries a body** — \"GET with a body.\"\n  * It fixes a decade-old pain: complex reads (search/filter/graph queries) that don't fit in a URL, without abusing `POST`.\n  * The subtle part is **caching** : the RFC requires the **request body** to be part of the cache key. Get it wrong and one client gets another client's response.\n  * http-queryable is a small library that does this correctly for Express, Fastify, raw `http`, and the browser.\n\n\n\n##  What is the QUERY method?\n\nFor decades HTTP forced a bad choice for \"reads with a big input\":\n\n  * `GET` — safe, idempotent, cacheable, but **no body**. Cram everything into the URL and hit length limits.\n  * `POST` — has a body, but it's **unsafe and non-idempotent**. Caches and proxies won't treat it as a read, and you can't safely retry.\n\n\n\n`QUERY` is the missing middle: **a body like POST, but the semantics of GET** — safe, idempotent, and cacheable.\n\n\n    QUERY /search HTTP/1.1\n    Content-Type: application/json\n\n    { \"q\": \"cats\", \"filters\": { \"color\": \"black\" } }\n\n\n##  The catch nobody talks about: caching\n\nRFC 10008 §2.7 is explicit: **the cache key must incorporate the request content.**\n\nShared HTTP caches have always keyed on **method + URL**. With QUERY, many _different_ bodies hit the _same_ URL:\n\n\n    QUERY /search  { \"q\": \"cats\" }   -> cats\n    QUERY /search  { \"q\": \"dogs\" }   -> dogs\n\n\nA method+URL cache would serve the **cats** response to the **dctness and security bug — the RFC's Security Considerationscalls it out.\n\n##  Doing it right: conservative body normalization\n\nYou want two things in tension:\n\n  1. `{\"a\":1,\"b\":2}` and `{ \"b\":2, \"a\":1 }` mean the same thing → **same key** (a hit).\n  2. `{\"q\":\"cats\"}` and `{\"q\":\"dogs\"}` differ → *_different keys_\n\n\n\nThe key insight is an **asymmetry** : a false **miss** is harmle** is a bug (wrong data served). So every normalization must be*_provably meaning-preserving_ _, and when in doubt you normalize *less_.\n\nSafe for JSON: whitespace, object key order, string escape forms. NOT safe: merging numeric literals (`JSON.parse(\"9007199254740993\")` returns `...992` — a\nsilent collision), guessing on duplicate keys, or normalizing ctand.\n\n##  Show me the code\n\n\n    import express from \"express\";\n    import { queryable, QueryCache } from \"http-queryable/express\";\n\n    const app = express();\n    app.use(queryable({ cache: new QueryCache() }));\n    app.query(\"/search\", (req, res) => res.json(search(req.body)));\n    app.listen(3000);\n\n    curl -X QUERY /search -d '{\"q\":\"cats\"}'      # MISS -> cats\n    curl -X QUERY /search -d '{ \"q\" : \"cats\" }'  # HIT  (same meaning)\n    curl -X QUERY /search -d '{\"q\":\"dogs\"}'      # MISS -> dogs\n\n\nThat third line is the whole point: a different body gets the cr a stale hit.\n\n##  It handles the rest too\n\nAccept-Query negotiation, Content-Location \"switch to GET\" flow CORS-safelisted), an isomorphic client with safe auto-retry,and Fastify + raw http adapters over the same core.\n\n##  Try it\n\nNode >= 22 (where `QUERY` lands in `http.METHODS`).\n\n\n    npm install http-queryable\n\n\nRepo + docs: https://github.com/hardik-goel/http-queryable — stars and edge-case bug reports welcome.",
  "title": "The HTTP QUERY method (RFC 10008) is here — and caching it correctly is harder than it looks"
}