For a very long time, whenever I needed to send a query to a server, I had only two real options: GET or POST. Both worked. Based on personal preference, some prefer to use the HTTP GET method and others prefer HTTP POST. Recently, while going through the newly published RFC 10008, I came across a new HTTP method called QUERY that finally fills this gap. In this post, I am going to walk through what it is, why we need it, and how it actually works.
The problem with GET and POST
The most common way to send a query is to encode everything into the URL query parameters and send a GET request.
GET /feed?q=foo&limit=10&sort=-published HTTP/1.1
Host: example.org
This is clean and works well for most use cases, until your system grows.
- URLs have practical size limits. HTTP itself doesn't define a maximum URI length, but every system our request goes through has its own limits. Browsers, servers, proxies, load balancers, and CDNs all impose their own limits. Based on the RFC, it's said to be 8 KB. If any of these underlying systems has a URI limit, our request can be rejected with
414 URI Too Long. - Encoding. When working with nested filters, arrays, JSON, or query parameters with spaces, quotes, or Unicode, it is more prone to data-handling issues and even a nightmare to debug and isolate a real production issue.
- Sensitive data exposure. URIs are far more likely to be logged in browser history or saved in bookmarks than the request body, so putting sensitive data there is risky.
- Caching issues. For a GET request, the cache uses the full URL as the label for each stored response. The cache only reuses a stored response if the URL matches exactly; it doesn't understand if the user sends the same query parameters in a different order. Because of this, there will be fewer cache hits and wasted cache storage.
When our query gets too big or too complex for a URL, the obvious fix is to switch from HTTP GET to POST. POST lets us put the query in the request body instead of the URL. It solves the first three issues at once.
- No length limit, because the request body can hold a larger payload.
- No messy encoding issues, because we are not squeezing everything into the URL.
- No leaking of sensitive data, because the query isn't sitting in the URL where it gets logged and saved.
But querying data via HTTP POST comes with a catch. GET has two valuable qualities that POST does not:
- Safe means the GET request only reads data and never changes anything on the server.
- Idempotent means running the same request several times has the same effect as running it once.
POST is normally used to create or change things. Since the system can't be sure our POST request is just a harmless read, there is no automatic caching (unless we implement it). Also, repeating it might do something twice (for example, create an order twice), so there are no automatic retries.
What is this HTTP QUERY Method
QUERY /feed HTTP/1.1Host: example.orgContent-Type: application/x-www-form-urlencoded
q=foo&limit=10&sort=-publishedWhen we send a QUERY request, two things describe what we are asking for: the content in the request body (the actual query) and the media type (the Content-Type header). Together they define our query.
The server takes that query and runs it against the target resource. This grants two things:
- Safe: the server knows we are only reading data, not asking it to change any data. Our query looks around and returns results, but it won't add, edit, or delete anything.
- Idempotent: running the same query again gives the same outcome as running it once. So if the connection drops midway, the request can simply be sent again automatically. There's no risk of something happening twice (this is a read-only query).
Example
Request :
QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Accept: application/json
select=surname,givenname,email&limit=10&match=%22email=*@example.*%22
Response :
HTTP/1.1 200 OK
Content-Type: application/json
[
{ "surname": "Smith", "givenname": "John", "email": "smith@example.org" },
{ "surname": "Jones", "givenname": "Sally", "email": "sally.jones@example.com" }
]
How do I know a server supports QUERY?
The simplest way to find out if a server supports HTTP QUERY is to send a request with the OPTIONS method. The other option is to just try a QUERY request; if the server doesn't support HTTP QUERY, it will reply with 405 Method Not Allowed.
Accept-Query header
To discover what type of query the server supports, based on the specification we can send an HTTP HEAD request to the resource as below and get Accept-Query in the response headers. This Accept-Query header is the server advertising its supported query formats to the client.
EX:
HEAD /contacts HTTP/1.1
Host: example.org
RES:
HTTP/1.1 200 OKContent-Type: application/xhtmlAccept-Query: application/x-www-form-urlencoded, application/sqlThe most interesting part of this RFC is that, since QUERY sends data in the body, we lose the nice property of GET where the URL itself identifies the query. RFC 10008 addresses this by letting the server hand back URIs in the response using two header fields:
- Content-Location points to a resource holding the result of the query we just ran. We can send a GET to that URI to fetch the same result again.
- Location points to a resource that represents the query itself. A GET to that URI re-runs the same query and gives us the current result, without resending the query body again.
Caching with HTTP QUERY
For HTTP QUERY, the cache has to build its label from the URL and the request body. That means the cache has to actually read the whole request body before it can even figure out the label (hash). Here is what we can do to avoid this request-body processing for caching:
- Send your QUERY once, with the body.
- The server runs it and gives us back a plain URL for that exact query (in the
Locationheader). - From now on, we just do a normal GET to that URL whenever we want to get those results again and again.
Conclusion
The QUERY method is a small but meaningful addition to HTTP. If you are building or designing APIs that deal with rich, structured queries, this is definitely something worth keeping an eye on. But don't rely on this yet, as most servers and HTTP clients don't support the HTTP QUERY method yet. Probably mid-2027 or 2028?
![]() |

No comments:
Post a Comment