Randhana.com
Published on
1 min read

HTTP Just Got a New Verb: Meet QUERY

Authors
  • avatar
    Name
    Pulathisi Kariyawasam
    LinkedIn
    LinkedIn

If you've built REST APIs for any amount of time, you've faced this exact dilemma:

You need a search endpoint. The filters are complex nested conditions, date ranges, sorting, pagination. Do you:

  1. Put all the data into the GET query string and hope it doesn't hit a URL length limit somewhere between the client and your server?
  2. Use POST and quietly accept that you're lying to every proxy, CDN, and cache on the internet about what your request actually does?

Most of us picked option 2 and moved on with our lives. GraphQL made it official nearly every GraphQL API sends read-only queries over POST.

Well, in June 2026 the IETF finally shipped the real answer: RFC 10008 — The HTTP QUERY Method. It's the first new standard HTTP method since PATCH in 2010. Sixteen years.

The problem in one table

GETPOSTQUERY
Request body❌ (unreliable)
Safe (read-only)
Idempotent (retry-safe)
Cacheable

QUERY is basically "GET with a body" or "POST that promises to behave."

Why not just send a body with GET?

Technically nothing stops you from attaching a body to a GET request. Practically, everything stops you. Some proxies strip GET bodies. Some servers silently ignore them. Some frameworks reject them outright. Decades of infrastructure was built assuming GET has no body, and redefining GET would break the internet. A new method was the safe path.

There's also a privacy angle. Query params end up in browser history, server access logs, and referrer headers. If your filter contains something sensitive (an email, an NIC number, an account ID), a request body is a much better place for it than the URL.

What a QUERY request looks like

QUERY /orders HTTP/1.1
Host: api.example.org
Content-Type: application/json
Accept: application/json

{
  "select": ["surname", "givenname", "email"],
  "limit": 10,
  "match": { "email": "*@example.*" }
}

Same shape as a POST but the method itself tells every intermediary in the chain: this is a read. You can cache it. You can retry it.

Why idempotency actually matters here

If a POST request times out, your client can't safely retry maybe the server processed it, maybe it didn't. Retry a payment POST and you might charge someone twice. That's why retry logic around POST always needs idempotency keys and extra ceremony.

QUERY requests carry a protocol-level guarantee: running it ten times is the same as running it once. Network blip? Retry blindly. Load balancer can re-dispatch a failed request to another backend without asking anyone. This is a small thing that removes a whole category of defensive code.

The caching catch

QUERY responses are cacheable like GET but there's a twist. With GET, the URL is the cache key. With QUERY, two requests to the same URL can carry completely different bodies, so caches must include the request body in the cache key. The RFC is explicit about this.

Until CDNs and proxies fully support this, be careful: set explicit Cache-Control headers and test how your infrastructure actually behaves.

The saved-query trick (my favourite part)

The spec supports responding to a QUERY with 303 See Other plus a Location header. The server can effectively say: "I've saved your query GET it here from now on."

QUERY /reports HTTP/1.1
Content-Type: application/json

{ "type": "monthly", "branch": "colombo", "year": 2026 }
HTTP/1.1 303 See Other
Location: /saved-queries/42

Now GET /saved-queries/42 re-runs the query against fresh data. Suddenly a complex query is a shareable, bookmarkable, cacheable URL. Report builders and dashboards are going to love this.

Trying it today

Most frameworks don't have first-class support yet, but since an HTTP method is ultimately just a string, you can wire it up now.

FastAPI:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class OrderQuery(BaseModel):
    status: str | None = None
    limit: int = 10

@app.api_route("/orders", methods=["QUERY"])
async def query_orders(q: OrderQuery):
    # read-only lookup no side effects, that's the contract
    return {"results": search_orders(q)}

Node.js (Express):

Express routes are method-name based, so use a small guard:

app.use('/orders', (req, res, next) => {
  if (req.method !== 'QUERY') return next()
  const { status, limit = 10 } = req.body
  res.json({ results: searchOrders({ status, limit }) })
})

Calling it with curl:

curl -X QUERY https://api.example.org/orders \
  -H "Content-Type: application/json" \
  -d '{"status": "active", "limit": 10}'

One rule to respect: if your "search" endpoint has side effects say, it logs every search into a recent_searches table that's a mutation, and it still belongs on POST. QUERY's guarantees only work if you keep it honestly read-only.

The security team's homework

New verb, new blind spots. If you run any infrastructure, check:

  • WAF rules — many are configured with an allowlist of methods. QUERY either gets blocked (broken app) or bypasses inspection entirely (worse).
  • Rate limiting — gateways often rate-limit per method. If GET gets 500 req/min and POST gets 100, what does QUERY get? If the answer is "unlimited because nobody configured it," that's a problem.
  • Monitoring dashboards — SOC tooling that categorises traffic by method may drop QUERY into an "other" bucket and create visibility gaps.

Should you use it in production?

Not yet but soon. The realistic adoption path: servers and dev tools first, then frameworks (Spring already has an open PR), then CDNs, then finally browsers and fetch(). Cloudflare and Akamai engineers co-authored the RFC, so expect CDN support to move fast.

My take: don't migrate existing GET endpoints if a query fits comfortably in a URL and users benefit from shareable links, GET is still the right tool. But for new complex-read endpoints (search, reporting, analytics, anything currently abusing POST), design with QUERY in mind. Test the full request path client, gateway, CDN, origin because one outdated middlebox rejecting an unknown method is all it takes.

Sixteen years for a new HTTP verb. Worth the wait, honestly.

Thanks for reading 👋


Reference: RFC 10008 — The HTTP QUERY Method, IETF, June 2026.