HTTP Just Got a New Method And API Developers Should Pay Attention
HTTP finally has a method for complex read-only requests with a body. Meet QUERY.
For years, API developers have been using POST for something it was never really meant to describe: search.
The reason is understandable. Modern search APIs often need nested filters, sorting rules, aggregations, selected fields, pagination, and other structured parameters. Trying to squeeze all of that into a URL quickly becomes difficult to read and maintain.
So we did what worked. We used POST.
Consider a typical search endpoint:
POST /api/products/search HTTP/1.1
Content-Type: application/json
{
"filters": {
"status": "active",
"price": {
"lt": 30
}
},
"sort": ["-created"]
}
There is nothing unusual about this API design. You have probably built something similar yourself.
But look at what the request actually does. It does not create a product, update a record, delete anything, or intentionally change application state. It simply reads data.
Yet, at the HTTP protocol level, the request is still a POST.
That semantic mismatch has quietly followed modern APIs for years. Our controllers know the operation is read-only. Our documentation describes it as a search. Developers understand exactly what the endpoint does.
HTTP, however, only sees POST.
In June 2026, the IETF published RFC 10008 and introduced a new HTTP method designed specifically to address this gap.
Meet QUERY.
The Gap Between GET and POST
HTTP already has a well-understood method for retrieving information: GET.
GET /api/products/42
The semantics are clear. The client is requesting information rather than asking the server to change application state.
GET is considered safe and idempotent. Those properties are useful not only to your application but also to HTTP clients, proxies, gateways, caches, and other infrastructure that processes the request.
The problem is that modern APIs do much more than retrieve a resource by ID.
Applications search large datasets, combine nested filters, calculate aggregations, rank results, group records, and generate reports. The query itself can become a structured document.
For simple filters, GET still works perfectly:
GET /api/products?category=laptop&inStock=true
But as requirements grow, URLs can quickly become difficult to manage:
/api/products?
filter[and][0][price][lt]=1500&
filter[and][1][or][0][category]=laptop&
filter[and][1][or][1][category]=tablet&
groupBy[0]=brand&
sort[0]=-rating
This may be technically possible, but it is hardly an elegant API contract.
There is also a practical infrastructure problem. URLs travel through browsers, proxies, load balancers, API gateways, and web servers. Different components may impose different URI length limits, meaning a sufficiently complex query can fail before it ever reaches your application.
Structured query documents naturally belong in a request body.
Unfortunately, that creates another problem.
Why Not Just Send a Body With GET?
At some point, almost every API developer asks the same question: if the operation is read-only, why not simply send a request body with GET?
For example:
GET /api/products/search HTTP/1.1
Content-Type: application/json
{
"category": "laptop",
"price": {
"max": 1500
}
}
From an application perspective, this looks completely reasonable. The request reads data and the filters are represented as structured JSON.
The problem is interoperability.
Historically, HTTP has not defined generally applicable semantics for content in a GET request. As a result, support across servers, frameworks, client libraries, proxies, and other intermediaries has been inconsistent.
A request may work perfectly in your local environment but behave differently when deployed behind another gateway or HTTP infrastructure.
That uncertainty makes GET with request content a poor foundation for interoperable APIs.
So developers reached for the HTTP method that reliably accepts a request body: POST.
How POST Became the Universal Search Workaround
Complex search API? Use POST.
Analytics query? Use POST.
Large reporting definition? Use POST.
GraphQL operation? Usually POST.
Functionally, the approach works extremely well. The client can send a structured document in the request body and the server can process it without dealing with an enormous URL.
The problem is that HTTP loses important semantic information.
Consider these two requests:
POST /api/payments
POST /api/products/search
The first request may charge a customer. The second may simply return a list of products.
Your application understands the difference, but an HTTP intermediary cannot inspect your business logic and conclude that one POST is safe while another may change state.
From the protocol’s perspective, both are POST requests and must be treated accordingly.
This is the gap the new QUERY method is designed to fill.
Meet the HTTP QUERY Method
RFC 10008 introduces a new HTTP method:
QUERY
A request can now be expressed like this:
QUERY /api/products HTTP/1.1
Content-Type: application/json
{
"filters": {
"category": "laptop",
"price": {
"max": 1500
}
},
"sort": ["-rating"]
}
The query is carried in the request content, but unlike POST, the method explicitly communicates safe and idempotent semantics.
The server processes the enclosed query and returns the result. The client is requesting read-oriented processing rather than a state-changing business operation.
A useful mental model is:
GET-like semantics with request content.
Technically, QUERY is not simply GET with a body. It is a separate HTTP method with its own defined semantics. However, this mental model makes the motivation behind the method easy to understand.
QUERY Is Safe
In HTTP terminology, a safe method means the client is not requesting a change to application state.
That does not mean the server is forbidden from writing anything internally. A QUERY request may still generate logs, record metrics, create traces, populate caches, or perform internal accounting.
GET requests already do many of these things.
Safety describes the operation requested by the client.
With QUERY, the client is asking the server to process query content and return information. It is not asking to create a resource, update a record, or trigger a state-changing business operation.
For the first time, that intent can be expressed directly through the HTTP method.
QUERY Is Also Idempotent
The QUERY method is idempotent, which becomes important when requests are retried.
Imagine a client sends this request:
POST /api/orders
The server successfully creates the order, but the network connection drops before the response reaches the client.
The client does not know whether the operation succeeded.
Retrying the request may be dangerous because the first request could already have created the order.
Now consider:
QUERY /api/products
The operation is explicitly idempotent. Repeating the request is not supposed to introduce additional state-changing effects.
This gives clients and HTTP infrastructure stronger semantics when dealing with interrupted requests and retry behavior.
The protocol no longer has to treat a complex read operation as an unknown POST.
QUERY Does Not Introduce a New Query Language
One important detail about RFC 10008 is what it does not define.
QUERY does not introduce a universal filtering syntax, a mandatory JSON schema, or a new HTTP query language.
The format of the query is still controlled by the application and described through Content-Type.
An API could accept JSON:
QUERY /api/products
Content-Type: application/json
A GraphQL service could use:
QUERY /graphql
Content-Type: application/graphql
Another system could use XML, CBOR, or a custom domain-specific query language.
HTTP defines the semantics of the operation. Your application defines the format and meaning of the query document.
This distinction is important because QUERY is not a competitor to GraphQL, SQL, or any search DSL. It is an HTTP method for expressing safe, idempotent query processing that requires request content.
Caching Is Where QUERY Gets More Interesting
Caching body-based read requests has always been awkward.
Consider two POST requests sent to the same endpoint:
POST /api/search
{
"status": "active"
}
and:
POST /api/search
{
"status": "disabled"
}
Both requests use the same URI, but they represent completely different queries and may return completely different results.
Traditional URI-based caching cannot simply treat them as the same resource.
RFC 10008 defines semantics that allow a server to identify a URI representing the result of a QUERY request using Content-Location.
For example:
QUERY /api/products HTTP/1.1
Content-Type: application/json
{
"category": "laptop",
"inStock": true
}
The server could respond with:
HTTP/1.1 200 OK
Content-Location: /api/products/query-results/7f3a91
Cache-Control: max-age=300
Content-Type: application/json
The query result now has an identifiable location that can participate in HTTP caching semantics.
This does not mean every CDN, reverse proxy, or cache supports QUERY today. Infrastructure still needs to implement the method and its caching behavior.
The important change is that the protocol now provides standardized semantics for this type of body-based, read-only request. API developers no longer need to invent those semantics themselves.
QUERY Has Nothing Specifically to Do With SQL
The method name may initially create some confusion.
A request such as:
QUERY /api/database
does not mean the server should execute arbitrary SQL from the request body.
QUERY is an HTTP method, not a database protocol.
Your API still defines and validates its own contract:
{
"filters": {
"status": ["active", "pending"]
},
"createdAfter": "2026-01-01"
}
The application decides which fields can be queried, which operators are supported, how authorization is applied, how input is validated, and how the query is ultimately executed.
QUERY only communicates the semantics of the HTTP operation: safe, idempotent, read-oriented processing with request content.
Where QUERY Actually Makes Sense
QUERY is not intended to replace GET.
If you are retrieving a specific resource, GET remains the obvious choice:
GET /api/users/42
If your filters fit naturally into a URL, GET is still perfectly appropriate:
GET /api/products?category=laptop&page=2
QUERY becomes interesting when the query itself is a structured document.
A complex product search may contain nested filters, ranking options, projections, and multiple sorting rules. An analytics API may need dimensions, metrics, aggregation rules, and time ranges. Reporting systems may accept large report definitions, while graph APIs may receive structured traversal instructions.
All of these scenarios share the same pattern:
The operation reads data, but the query is too complex to fit comfortably in a URI.
That is the problem QUERY was designed to solve.
Should You Replace Your POST Search Endpoints Today?
Probably not immediately.
Publishing a new HTTP standard does not instantly update the entire HTTP ecosystem.
Your web server needs to accept the method. Your framework needs to route it. API gateways and reverse proxies need to forward it correctly. HTTP clients need to send it. CDNs and caching infrastructure need to understand its semantics.
Monitoring, observability, and security tools may also need updates.
Many systems currently use explicit HTTP method allowlists such as:
GET
POST
PUT
PATCH
DELETE
OPTIONS
A gateway, firewall, or security policy configured with such a list may reject QUERY before the request reaches your application.
Adoption will take time, which is normal for a new HTTP method.
But that does not make the standard unimportant.
The major change is that API designers now have standardized HTTP semantics for a problem that previously required a workaround.
For years, we have described endpoints by saying, “It uses POST, but it only reads data.”
Now there is a method that can communicate that intent directly.
Final Thoughts
HTTP APIs have lived with an awkward gap for years.
GET correctly represents read operations, but it is not a comfortable fit for large, structured query documents. POST handles request content perfectly, but it does not communicate safe and idempotent query semantics.
So developers built read-only POST endpoints.
They worked. Many of them will continue to work for years.
The problem was never that these APIs were broken. The problem was that the HTTP method did not accurately describe what the operation was doing.
RFC 10008 finally gives that operation a name.
GET remains the right choice for straightforward resource retrieval. POST remains appropriate when an operation may create or change state. And QUERY gives complex, body-based, read-only operations a method designed specifically for them.
Sometimes a protocol does not need another abstraction.
It just needs the missing word.
HTTP finally has one.
QUERY.
I hope you found this guide helpful and informative.
Thanks for reading!
If you enjoyed this article, feel free to share it and follow me for more practical, developer-friendly content like this.


