Cached at:
06/18/26, 12:02 PM
# RFC 10008: The HTTP QUERY Method
Source: [https://blainsmith.com/articles/rfc-10008-http-query-method/](https://blainsmith.com/articles/rfc-10008-http-query-method/)
June 17 2026
[RFC 10008](https://www.rfc-editor.org/info/rfc10008)was published on June 15, 2026 and defines a new HTTP method:`QUERY`\. It fills a gap that has existed for as long as I have been building APIs\. You have data to send to the server in order to describe what you want back, but`GET`does not have a body and`POST`is neither safe nor idempotent\.`QUERY`gives you a method that accepts a request body while remaining safe, idempotent, and cacheable\.
If you have ever built an SDK that talks to a JSON\-RPC API you have felt this pain\. JSON\-RPC by design sends a JSON payload describing the method and parameters\. That payload has to go in the body, which means`POST`, which means caches and intermediaries treat every request as a state\-changing operation\. Retry logic gets complicated\. CDN caching is off the table\. You end up building your own application\-level caching because HTTP's built\-in mechanisms cannot help you\.
`QUERY`changes that\. The semantics are simple: send a body, get a response, and the whole exchange is treated like a`GET`from the perspective of caching and safety\.
## In Go
Go's[`net/http`](https://pkg.go.dev/net/http)already lets you use arbitrary method strings with[`http\.NewRequest`](https://pkg.go.dev/net/http#NewRequest), so SDK code using`QUERY`looks about like you would expect:
```
body, _ := json.Marshal(map[string]any{
"jsonrpc": "2.0",
"method": "getScore",
"params": []any{"0xABC123", "latest"},
"id": 1,
})
req, _ := http.NewRequestWithContext(ctx, "QUERY", "https://rpc.example.com", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
```
No new dependencies needed\. The standard library handles it because HTTP methods are just strings\.
## In Rust
With[`reqwest`](https://docs.rs/reqwest/latest/reqwest/)you can use[`reqwest::Method`](https://docs.rs/http/latest/http/method/struct.Method.html)to define a custom method:
```
use reqwest::{Client, Method};
let client = Client::new();
let query_method = Method::from_bytes(b"QUERY").unwrap();
let resp = client
.request(query_method, "https://rpc.example.com")
.header("Content-Type", "application/json")
.body(r#"{"jsonrpc":"2.0","method":"getScore","params":["0xABC123","latest"],"id":1}"#)
.send()
.await?;
```
## Caching
The part I have been waiting for is in Section 2\.7\. The response to a`QUERY`is cacheable and the cache key must incorporate the request body and its metadata\. This means a reverse proxy or CDN can look at the`Content\-Type`and the body bytes together and serve a cached response for identical queries\. Caches can also normalize the body \(reorder JSON keys, strip insignificant whitespace\) to improve hit rates\.
For RPC\-style APIs where every request is semantically a read operation but structurally a`POST`, this is a meaningful improvement\. You get HTTP\-native caching without building a bespoke layer on top\.
The RFC is short and readable\. Worth 20 minutes if you build or consume HTTP APIs\.