# HTTP Just Got a New Method — Meet QUERY

*If you've ever designed a search endpoint, filter API, or complex read operation — you've hit the wall every backend engineer eventually hits. GET can't safely carry a body. POST isn't safe, idempotent, or cacheable. So you compromise. You either shove everything into query strings until URLs break, or you misuse POST for reads and lose caching entirely.*

*In June 2026, the IETF finally shipped the real answer:* ***RFC 10008 — The HTTP QUERY Method.*** *It's a safe, idempotent, cacheable HTTP method designed from day one to carry a request body. If you build backend systems, this is worth understanding now — because the tooling around it is going to move fast over the next 12–24 months.*

* * *

## The Short Version

*   **QUERY** is a new HTTP method, standardized as **RFC 10008 (June 2026)** on the IETF Standards Track.
    
*   Fills the long-standing gap between GET (safe but bodyless) and POST (unsafe, non-cacheable).
    
*   Solves the "GET with a body" ambiguity that has plagued search and filter APIs for years.
    
*   Node.js has parsed QUERY natively since early 2024. OpenAPI 3.2 supports documenting it. Spring support is an open pull request as of publication.
    
*   Not a replacement for GET or POST — a purpose-built method for complex read operations.
    

* * *

## The Problem QUERY Solves

Every backend engineer has faced this pattern.

You're designing a search endpoint. Users want to filter across 20 fields, some with nested arrays, some with ranges, some with boolean logic.

Your options:

**1\. GET with query string.** Clean semantics — safe, idempotent, cacheable. But URLs balloon past browser and proxy limits at around 2KB. Complex nested filters become unreadable escaped JSON in query params. Some proxies strip long URLs silently.

**2\. GET with a body.** The HTTP spec technically permits a body on GET, but says "servers should not expect or process it." Some clients strip it. Some proxies drop it. Some servers reject it outright. Undefined behavior territory.

**3\. POST for reads.** Send the query as JSON in a POST body. Works everywhere. But it breaks caching entirely, is not idempotent by spec, and confuses anyone reading your API docs. You've turned a read into a "write" from HTTP's perspective.

Everyone has picked option 3 at some point. Everyone has felt slightly wrong about it.

QUERY is the option we always wanted: **a method that says "this is a safe read, has a structured body, and can be cached like GET."**

* * *

## What Exactly Is QUERY?

QUERY is defined in **RFC 10008**, published on the IETF Standards Track in June 2026. It's the culmination of the Safe Method with Body work that ran for years in the IETF HTTPBIS working group. Its properties, straight from the spec:

*   **Safe** — read-only. Executing it does not modify server state.
    
*   **Idempotent** — repeating the request yields the same result.
    
*   **Cacheable** — responses can be cached like GET responses.
    
*   **Has a request body** — unlike GET, it's designed for bodies from day one.
    
*   **Distinct semantic** — separate from POST, so intermediaries can treat it correctly.
    

An example request looks like this:

```json
QUERY /api/search HTTP/1.1
Content-Type: application/json

{
  "filters": {
    "status": ["active", "pending"],
    "createdAt": { "from": "2025-01-01", "to": "2026-01-01" },
    "tags": ["urgent", "customer-priority"]
  },
  "pagination": { "page": 1, "size": 50 },
  "sort": [{ "field": "createdAt", "direction": "desc" }]
}
```

It reads like a GET semantically — safe, idempotent, cacheable — but with a proper body designed into the method from the start.

* * *

## QUERY vs GET vs POST — When to Use Each

| Property | GET | POST | QUERY |
| --- | --- | --- | --- |
| Safe (read-only) | Yes | No | Yes |
| Idempotent | Yes | No | Yes |
| Cacheable | Yes | Rarely | Yes |
| Body allowed | Undefined | Yes | Yes |
| Semantic | Read | Write | Complex read |
| URL length safe | No (~2KB limit) | N/A | Yes |

**Use GET when:** simple reads with parameters that fit in a URL. `/users/123`, `/orders?status=active`.

**Use POST when:** state-changing operations. Creating, updating, deleting, triggering side effects.

**Use QUERY when:** complex reads that can't be expressed cleanly in query strings — search endpoints, filter APIs, analytical queries, batch reads, or anywhere the payload structure exceeds what URL parameters can carry.

* * *

## Real-World Use Cases

**1\. Search APIs**

You have a `/api/products/search` endpoint that accepts complex filter criteria. Today: POST. Tomorrow: QUERY.

**2\. Analytical Queries**

Dashboards, reports, and cross-cutting aggregations that don't fit in URLs. All read-only. QUERY is a natural fit.

**3\. GraphQL-over-HTTP**

GraphQL has always awkwardly used POST for reads because queries can be arbitrary size. QUERY is a much better semantic fit and gives GraphQL back its cacheability story.

**4\. AI / ML Inference APIs**

Passing embeddings, feature vectors, or prompt bodies to a model endpoint. Structurally reads, but bodies are large and don't belong in URLs.

**5\. Batch Reads**

"Give me the current state of these 500 items" — a batch read that's semantically GET but structurally needs a body.

* * *

## Adoption Landscape (as of publication)

Adoption is moving quickly now that RFC 10008 is out:

*   **Node.js** has parsed QUERY natively since early 2024 (well before the RFC finalized) — safe to use in Express, Fastify, and Koa handlers today.
    
*   **OpenAPI 3.2** supports documenting QUERY endpoints in your specs.
    
*   **Spring / Spring Boot** — support is currently an open pull request against Spring Framework. Until that lands, you'll need the workaround shown below.
    
*   **Cloudflare, AWS ALB, and modern Envoy / nginx** pass QUERY through to origins. Older middleboxes may need testing.
    

Expect the framework matrix to fill in rapidly through late 2026.

## Code Examples — Spring Boot

Until Spring's first-class QUERY support merges, you can wire a QUERY endpoint using the string method name via `RequestMethod.valueOf`:

```java
@RestController
@RequestMapping("/api/products")
public class ProductSearchController {

    @RequestMapping(method = RequestMethod.valueOf("QUERY"))
    public SearchResponse search(@RequestBody SearchQuery query) {
        return searchService.execute(query);
    }
}
```

Client side with RestClient:

```java
SearchResponse response = restClient
    .method(HttpMethod.valueOf("QUERY"))
    .uri("/api/products")
    .contentType(MediaType.APPLICATION_JSON)
    .body(searchQuery)
    .retrieve()
    .body(SearchResponse.class);
```

Once Spring's QUERY PR merges, expect a proper `@QueryMapping` or `RequestMethod.QUERY` enum constant. Until then, `RequestMethod.valueOf("QUERY")` is the tactical path.

In Node.js, no workaround is needed — QUERY has been natively parseable since 2024:

```javascript
app.use((req, res, next) => {
  if (req.method === 'QUERY') {
    // req.body is already parsed by your standard JSON middleware
    return handleSearch(req, res);
  }
  next();
});
```

Always check your framework's current release notes before adopting in production — support is landing fast.

* * *

## Common Questions I've Seen

**Will my proxy or CDN choke on QUERY?**

Older middleboxes may drop or reject unknown methods. Modern proxies (recent nginx, Envoy, Cloudflare, AWS ALB) are progressively adding support or passing QUERY through untouched. Test the full request path end-to-end before rolling out in production.

**Can I cache QUERY responses in a CDN?**

The spec allows it. Practical CDN support is still catching up — expect broader adoption through 2026 and 2027. Cache-Control semantics work the same as GET.

**Does QUERY replace POST for search?**

Yes, for pure read operations. If your "search" endpoint has side effects (like logging every search into a "recent searches" table), that's a mutation and it still belongs on POST.

**What if I already use POST for reads?**

Nothing breaks. QUERY is additive. You can migrate incrementally, endpoint by endpoint, as your framework support matures.

**Do I need to change anything in my API design tomorrow?**

Not immediately. But for new complex-read endpoints, QUERY is the future-proof choice. For existing POST-based search endpoints, plan to migrate when your tooling supports it fully — the migration is mechanical once the plumbing is ready.

* * *

## What This Means for API Design

QUERY isn't revolutionary — it's the missing piece HTTP should have had for a decade. Its real impact is in **cleaner API semantics.**

Before QUERY, when I saw an endpoint documented as "POST /api/search," I couldn't tell whether it was:

*   A safe read using POST because bodies are needed, or
    
*   A mutation that creates a saved search record
    

That ambiguity forced defensive coding. No client-side caching. No confident retries. No smart caching in intermediaries. QUERY removes that ambiguity. When an endpoint is QUERY, everyone — clients, proxies, caches, and developers reading the docs — knows what it is.

For engineers designing APIs, this is worth internalizing. **Method choice is documentation.** Using QUERY where it fits communicates intent that no amount of Swagger doc can. And explicit intent is one of the quiet markers of well-designed systems.

* * *

## Adoption Checklist

Before adopting QUERY in production:

*   \[ \] Verify your HTTP server framework supports it (check current Spring, Ktor, Express, FastAPI versions and their release notes)
    
*   \[ \] Verify your reverse proxies pass it through untouched (nginx, Envoy, HAProxy)
    
*   \[ \] Verify your CDN supports it if you rely on edge caching
    
*   \[ \] Verify your monitoring and observability tools capture it (some filters drop unknown methods)
    
*   \[ \] Test with your primary client SDKs (Java, JavaScript, Python, Go — support varies)
    

If any of these are gaps, either wait or plan a mitigation. Rolling out QUERY halfway can create silent 405 errors that are painful to debug in production.

* * *

## Common Mistakes to Avoid

**1\. Using QUERY for endpoints that mutate state.** Even if the response looks like a read, if the request writes anything — a search log, a "last accessed" timestamp, an analytics event — it should be POST. QUERY is strict about safety.

**2\. Skipping proxy verification.** A single misbehaving middlebox in your stack can turn every QUERY request into a 405 or dropped connection. Test end-to-end with your actual production topology.

**3\. Assuming caching just works.** QUERY responses can be cached, but only if you set proper `Cache-Control` headers and your intermediaries respect them for non-GET methods. Verify with real traffic.

**4\. Migrating everything at once.** Introduce QUERY gradually — one endpoint at a time, ideally new endpoints first, and only migrate legacy POST-for-search endpoints when the rest of your stack is ready.

* * *

## Closing Thoughts

Every few years HTTP quietly evolves in a way that makes something cleaner. PATCH gave us partial updates. HTTP/2 gave us multiplexing. HTTP/3 gave us better transport. RFC 10008's QUERY gives us a proper semantic for complex reads.

None of these forced anyone to change overnight. All of them shifted what "modern" looks like over the next 3–5 years.

If you're a backend engineer, my recommendation:

1.  **Read RFC 10008** — the spec is short and worth an evening
    
2.  **Watch your framework's support** — Node.js is ready today, Spring is close, others are catching up
    
3.  **Prefer QUERY for new complex-read endpoints** once your stack is ready
    
4.  **Don't rush to migrate legacy POST-for-search endpoints** — the effort rarely justifies itself unless you're rewriting anyway
    

QUERY isn't a revolution. It's the quiet cleanup HTTP needed. The engineers who understand it early will design better APIs for the next decade.

* * *

*If this helped, a clap goes a long way. And if you've already deployed QUERY in production — I'd love to hear about your rollout experience in the comments.*

* * *

*All views in this post are my own. Code examples are illustrative and not drawn from any specific codebase.*
