HTTP QUERY method: the missing verb for complex search APIs
Video version at https://youtu.be/REjWp_2Dt30
Hypertext Transfer Protocol (HTTP) provides us with a set of basic methods to describe what our request is doing. Generally, we’re working with GET or POST requests, but these have limitations on them that you won’t be aware of until you’ve run headlong into one of them.
The best example is if you’re building a search API. It might start simple with three search fields and an order by field so you can easily fit the requests in a standard GET request. But then the requests get more complex, ballooning your request string to hundreds or thousands of characters. One day you get reports of random failures because a new field you added blew past a URL length limit somewhere between the browser and your server. To fix it want to add a request body, and now you’re stuck choosing between a GET that technically shouldn’t have a body and a POST that “lies about what your endpoint actually does.”
The good news is there’s finally a proper answer to this problem. The HTTP QUERY method, defined in RFC 10008, gives you a request that’s safe and cacheable like GET, and can contain a structured body like POST.
In this article, we’ll discuss why GET and POST both fall short for complex search requests, what the QUERY method actually is, and what this means going forward.
If you’re new here, we cover topics related to the PHP ecosystem. Hit subscribe so you don’t miss the next one.
Why GET and POST Fall Short
Today, when you have a complex search, you have essentially three bad options.
The first is a GET request with a large query string. This is the natural choice because searching is a read operation, and GET is safe, idempotent, and cacheable. The trouble is that everything lives in the URL, and while you can generate any length of URL you want, browsers, proxies, and servers all impose limits on URL length that you can’t control. Once your filters get complex enough, you’ll hit them. Encoding nested structures like a price range or an array of categories into a query string is also awkward and easy to mess up.
The second option is GET with a request body. While HTTP doesn’t strictly forbid this, the specification says a body has no defined meaning on a GET, so nobody has to respect it. Some servers strip it, some proxies ignore it, and HTTP clients handle it inconsistently. You cannot safely rely on it, so it isn’t a real option.
The third option is a POST request. It has a body, so your complex filters fit fine, and generally the upper limit on a POST request is massive. The problem is that in general POST is non-idempotent, which means the same request sent twice might do two different things. To the rest of the internet, POST signals “causes a side effect,” and because of that fact, most infrastructure won’t cache a POST response, and it won’t safely retry a POST for you after a network hiccup, because retrying might accidentally do the action twice. You’re using a verb that means “change something” to describe an operation that changes nothing.
What Is HTTP QUERY?
The QUERY method is a new HTTP verb designed to solve this exact situation. Where you need a read-only request with a body.
Here’s how it compares to what we have today:
| Method | Body | Idempotent | Safe | Cacheable |
|---|---|---|---|---|
| GET | No (not reliably) | Yes | Yes | Yes |
| POST | Yes | No | No | Limited |
| QUERY | Yes | Yes | Yes | Yes |
QUERY gives you the best of both GET and POST. It’s safe and idempotent like GET, so infrastructure can retry it and cache its response, and it carries a structured body like POST, so you can send whatever complex filter payload you need.
A raw QUERY request looks like this:
QUERY /products HTTP/1.1
Host: api.unleashedpodcasts.com
Content-Type: application/json
{
"filters": {
"category": ["electronics", "accessories"],
"price": {"min": 50, "max": 500}
}
}
It reads like a POST, but its meaning is closer to a GET.
Gotchas
Before you rush to convert every endpoint, keep a few things in mind.
Support for the QUERY verb is essentially non-existent right now. Most browsers, CDNs, and servers don’t recognize QUERY yet, so you’ll need to build a POST fallback for clients and infrastructure that can’t handle it yet.
Some PHP servers and routers reject unknown HTTP methods outright. Test your full stack, including your web server and any proxies in front of it, before you deploy.
For simple queries with just a few parameters, GET with a query string is still the right choice. It’s shareable, bookmarkable, and cacheable everywhere today. QUERY is going to be for the complex cases where GET struggles with the length and complexity.
What You Need To Know
- QUERY is a new HTTP method from RFC 10008
- Supports read-only requests that need a body.
- It’s safe, idempotent, and cacheable like
GET - Adoption is early, so keep a
POSTfallback and stick withGETfor simple queries.



Leave a comment
Use the form below to leave a comment: