O que é o método HTTP QUERY

O método QUERY é uma requisição HTTP que envia a consulta no corpo da request mantendo as garantias de segurança do GET.
Em uma frase
Seção intitulada “Em uma frase”QUERY = GET com corpo. Safe, idempotent, cacheable, mas com request body. O problema do POST /search resolvido no nível do protocolo.
O que a RFC diz
Seção intitulada “O que a RFC diz”RFC 10008, publicada em 15 de junho de 2026. Primeiro método HTTP novo desde PATCH (RFC 5789, 2010). Dezesseis anos sem um método novo.
“A QUERY requests that the request target process the enclosed content in a safe and idempotent manner and then respond with the result of that processing.”
Autores: Julian Reschke (greenbytes), James Snell (Cloudflare), Mike Bishop (Akamai).
A spec começou como SEARCH em 2015. Renomearam em novembro de 2021 para escapar da bagagem do WebDAV. Onze anos do primeiro draft até a publicação.
Propriedades do método
Seção intitulada “Propriedades do método”| Propriedade | Valor | O que significa na prática |
|---|---|---|
| Safe | Sim | Não altera estado no servidor. Proxies e crawlers podem executar sem medo. |
| Idempotent | Sim | Repetir a mesma request produz o mesmo resultado. Retry automático é seguro. |
| Cacheable | Sim | Respostas podem ser cacheadas. Cache key inclui o body + Content-Type. |
| Request body | Esperado | O corpo É a query. Content-Type obrigatório. |
O body define a pergunta. O Content-Type define o formato da pergunta. O servidor DEVE rejeitar requests sem Content-Type ou com tipo inconsistente com o conteúdo.
Discovery: Accept-Query
Seção intitulada “Discovery: Accept-Query”Servidores anunciam suporte com o header Accept-Query:
Accept-Query: application/json, application/graphqlGET vs POST vs QUERY
Seção intitulada “GET vs POST vs QUERY”| GET | POST | QUERY | |
|---|---|---|---|
| Safe | ✅ | ❌ | ✅ |
| Idempotent | ✅ | ❌ | ✅ |
| Cacheable | ✅ | Só para GET/HEAD futuros | ✅ |
| Request body | Sem semântica definida | Esperado | Esperado |
| Retry automático | ✅ | ❌ (pode causar side effects) | ✅ |
| Limite prático | ~8.000 octetos na URL | Sem limite | Sem limite |
| Logs/bookmarks | Query vaza em access logs | Body não vaza | Body não vaza |
O problema com GET
Seção intitulada “O problema com GET”RFC 9110 recomenda suporte a URIs de pelo menos 8.000 octetos. Isso é um piso, não uma garantia. Cada proxy, load balancer e servidor na cadeia tem seu próprio limite. Você descobre o menor em runtime — geralmente com um 414 atrás de um proxy corporativo que seu test suite nunca vai reproduzir.
URLs também vazam. Access logs, bookmarks, histórico do browser. Se a query tem dados sensíveis, agora estão em todo log do caminho.
O problema com POST
Seção intitulada “O problema com POST”POST funciona pra queries. Até você precisar de retry, cache ou semântica honesta.
POST não é safe. POST não é idempotent. Quando a conexão cai no meio da request, nenhum cliente ou proxy sabe se o estado mudou no servidor. Nada faz retry automático. Você acaba construindo idempotency keys na mão — maquinaria que leituras nunca deveriam ter precisado.
Cache? RFC 9110 permite cachear respostas POST só com freshness explícita + Content-Location matching, e mesmo assim só serve GET/HEAD futuros. Duas chamadas POST /search idênticas sempre batem na origin.
Quando usar
Seção intitulada “Quando usar”- Filtros complexos que não cabem na URL (JSON com nested objects, arrays, ranges)
- Queries com dados sensíveis que não devem vazar em logs
- Endpoints de busca/pesquisa que hoje abusam de POST
- JSON-RPC e APIs onde toda chamada é semanticamente uma leitura
- Qualquer read-only request que precisa de body
Quando NÃO usar
Seção intitulada “Quando NÃO usar”- Queries simples que cabem confortavelmente na URL — GET continua sendo melhor (mais simples, universalmente suportado)
- Operações que alteram estado — use POST/PUT/PATCH/DELETE
- APIs públicas onde clientes antigos não suportam QUERY — mantenha o POST como fallback
- Cross-origin em browsers se o preflight OPTIONS é inaceitável para sua latência
Cache: como funciona
Seção intitulada “Cache: como funciona”A resposta QUERY é cacheable, mas a cache key DEVE incorporar o conteúdo da request, não só a URI. Seção 2.7 da RFC é explícita.
Isso é mais complexo que cachear GET. O cache precisa ler o body inteiro antes de decidir se já viu essa request. Caches podem normalizar (reordenar chaves JSON, remover whitespace) para melhorar hit rate.
O risco: normalização agressiva demais gera falsos positivos — o cache devolve resultado da query errada.
Conditional requests funcionam via ETag e If-None-Match, operando contra o “equivalent resource” — um recurso GET hipotético derivado incorporando o body da request no target.
Um exemplo real
Seção intitulada “Um exemplo real”curl -X QUERY 'http://localhost:3000/contacts' \ -H 'Content-Type: application/json' \ -d '{"filter": {"city": "Berlin"}, "limit": 50}'O que antes era:
GET /contacts?filter[city]=Berlin&limit=50Ou, quando ficava grande demais:
POST /contacts/searchContent-Type: application/json
{"filter": {"city": "Berlin", "age_gte": 25, "tags": ["vip", "active"]}, "limit": 50}Agora tem o método certo: uma leitura que se comporta como leitura.
Suporte atual (julho 2026)
Seção intitulada “Suporte atual (julho 2026)”| Stack | Status |
|---|---|
| Node.js | Nativo desde Node 21.7.2 / 22+ (llhttp 9.2.0) |
| Fastify | fastify.addHttpMethod('QUERY', { hasBody: true }) |
| Go net/http | Funciona com method string arbitrária |
| .NET | .NET 11 Preview 4 reconhece QUERY |
| Spring | PR #34993 aberta, bloqueada |
| OpenAPI | 3.2.0 (set/2025) — campo query nativo |
| curl | -X QUERY com --data e Content-Type explícito |
| Browsers | fetch() aceita, mas CORS preflight obrigatório |
CDNs: os autores da RFC trabalham na Cloudflare e Akamai. Bom sinal. Suporte oficial de cache nas edges? Não confirmado ainda.