O que é o HTTP QUERY Method

TL;DR - O RFC 10008 criou um novo método HTTP chamado QUERY: ele funciona como o GET (semântica de leitura, idempotente, cacheável) mas permite enviar um corpo (body) com a requisição, resolvendo um problema antigo das APIs de busca.

Há anos os desenvolvedores backend enfrentam um dilema clássico: como fazer uma busca complexa via HTTP? O GET é o método certo semanticamente, mas não tem corpo de requisição. O POST aceita corpo, mas tem semântica de "criar algo", não é idempotente é não é cacheável por padrão.

A solução improvisada mais comum é colocar parâmetros complexos na query string do GET, o que fica feio, tem limite de tamanho em torno de 2000 a 8000 caracteres dependendo do servidor, é não suporta estruturas aninhadas com facilidade. Outra gambiarra é usar POST para buscas é torcer para que os caches entendam.

O RFC 10008, publicado em 2026 pelo IETF, oficializa o método QUERY como a solução definitiva para este problema. É um método HTTP de primeira classe, com semântica bem definida, suporte a corpo de requisição é comportamento cacheável por design.

Como funciona o método QUERY

O QUERY se comporta de forma semelhante ao GET em termos de semântica: ele é seguro (não modifica dados no servidor), idempotente (repetir a mesma requisição dá o mesmo resultado) é cacheável (caches podem armazenar a resposta).

A diferença central é que o QUERY aceita um corpo de requisição (request body). O conteúdo do corpo, combinado com a URL, forma a chave de cache. Isso significa que duas requisições QUERY para a mesma URL mas com corpos diferentes são tratadas como requisições distintas para fins de cache.

💡
Como o cache funciona no QUERY

A chave de cache do QUERY é a combinação de URL + corpo da requisição + Content-Type. O servidor deve incluir cabeçalho Vary adequado para que proxies intermediários tratem corretamente.

Veja um exemplo de requisição usando o novo método:

QUERY /api/produtos HTTP/1.1
Host: api.exemplo.com.br
Content-Type: application/json
Accept: application/json

{
  "filtros": {
    "categoria": "eletronicos",
    "preco_max": 2000,
    "disponível": true
  },
  "ordenacao": "preco_asc",
  "página": 1,
  "por_pagina": 20
}

A resposta segue o padrão HTTP normal com código 200 OK é os resultados no corpo. O servidor pode incluir Cache-Control é ETag normalmente, assim como em respostas a GET.

Principais recursos é diferenciais

O RFC 10008 define claramente o que o QUERY pode é não pode fazer. Entender esses limites é fundamental para usar o método corretamente nas suas APIs.

  • Corpo de requisição sem limite prático: diferente da query string, o corpo aceita JSON, XML ou qualquer Content-Type com estruturas complexas é aninhadas.
  • Semântica de leitura garantida: servidores, proxies é clientes HTTP sabem que QUERY não modifica dados, podem tomar decisões de segurança é cache baseadas nisso.
  • Idempotência nativa: repetir a mesma requisição QUERY com o mesmo corpo deve retornar o mesmo resultado, permitindo retry automático com segurança.
  • Cacheável por padrão: ao contrário do POST, respostas QUERY podem ser cacheadas sem configuração especial no servidor ou proxy.
  • Compatível com toda a infraestrutura HTTP: load balancers, CDNs é reverse proxies que entendem HTTP/1.1 é HTTP/2 suportam o método sem modificações.
Como começar ↓

Como começar: suporte é implementação

🔵 Nível 2 - Intermediário

O suporte ao método QUERY ainda está chegando nas principais bibliotecas é frameworks no momento em que este artigo foi escrito. A boa notícia é que a implementação é direta, pois a maior parte da infraestrutura HTTP já existe.

Em JavaScript com fetch, o método é especificado como qualquer outro:

// Requisicao QUERY com fetch API
const resposta = await fetch('/api/produtos', {
  method: 'QUERY',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  body: JSON.stringify({
    filtros: { categoria: 'eletronicos', preco_max: 2000 },
    ordenacao: 'preco_asc'
  })
});

const dados = await resposta.json();
console.log(dados);

No backend com Node.js é Express, o roteamento segue a mesma lógica:

// Express ainda não tem app.query() nativo
// Usar router.all() ou middleware personalizado
app.all('/api/produtos', (req, res, next) => {
  if (req.method === 'QUERY') {
    const filtros = req.body;
    // processar busca com filtros do corpo
    return buscarProdutos(filtros).then(r => res.json(r));
  }
  next();
});

Em .NET com ASP.NET Core, é possível adicionar suporte via atributo customizado enquanto o framework não tem suporte nativo completo:

// ASP.NET Core - aceitar metodo QUERY
[HttpMethod("QUERY", "api/produtos")]
public async Task BuscarProdutos(
  [FromBody] FiltrosProdutos filtros)
{
  var resultado = await _service.BuscarAsync(filtros);
  return Ok(resultado);
}

Exemplo prático: API de busca avançada

Imagine uma API de busca de imóveis onde o usuário pode filtrar por bairro, faixa de preço, número de quartos, área mínima é máxima, é ordenar por diferentes critérios. Com GET, isso seria um pesadelo de query string. Com QUERY, fica elegante:

QUERY /api/imoveis HTTP/2
Host: api.imobiliaria.com.br
Content-Type: application/json

{
  "bairros": ["Batel", "Agua Verde", "Bigorrilho"],
  "faixa_preco": { "min": 300000, "max": 800000 },
  "quartos": { "min": 2 },
  "area_m2": { "min": 60, "max": 150 },
  "caracteristicas": ["garagem", "piscina"],
  "ordenar_por": "preco_asc",
  "página": 1
}
💡
Cache com corpo

Se o mesmo usuário fizer a mesma busca duas vezes, o cache HTTP pode retornar o resultado armazenado sem bater no banco de dados. Com POST isso não funcionária automaticamente.

A resposta inclui os imóveis encontrados é metadados de paginação, é o servidor pode definir Cache-Control: max-age=60 para cachear resultados por 1 minuto, algo impossível de garantir com POST.

Comparação com alternativas

Antes do RFC 10008, os desenvolvedores tinham três opções, todas com compromissos ruins:

Antes: gambiarras

GET com query string longa que quebra em alguns servidores. POST com semântica errada que não é cacheável. GraphQL ou OData para resolver algo que deveria ser nativo no HTTP.

Agora: QUERY nativo

Um método com a semântica certa, corpo livre, idempotente é cacheável. Sem depender de camadas extras como GraphQL quando você só precisa de busca flexível.

Em relação ao GraphQL: o QUERY não é substituto do GraphQL. Se você precisa de seleção granular de campos, múltiplas queries em lote é schema tipado, GraphQL ainda é a escolha. O QUERY HTTP é mais baixo nível é complementar.

Em relação ao OData: o OData usa GET com query string para filtros avançados é tem seu nicho em APIs corporativas. O QUERY é mais simples é não impõe um dialeto de query específico.

Em relação ao POST para buscas: é a gambiarra mais comum. Funciona, mas não é semânticamente correto é os caches não sabem que podem armazenar a resposta.

Pontos positivos é limitações

O QUERY resolve um problema real é bem definido. Mas é importante entender o que ele não é.

  • Positivo: semântica HTTP correta para buscas complexas.
  • Positivo: cacheável nativamente, reduzindo carga no servidor.
  • Positivo: idempotente, permite retry seguro em falhas de rede.
  • Positivo: elimina o limite de tamanho da query string.
  • Limitação: suporte ainda chegando em frameworks é ferramentas (junho 2026).
  • Limitação: caches intermediários mais antigos podem não reconhecer o método.
  • Limitação: não resolve seleção granular de campos como GraphQL.
⚠️
Compatibilidade com proxies antigos

Proxies HTTP que não reconhecem o método QUERY podem bloqueá-lo ou tratá-lo como inválido. Verifique a compatibilidade do seu stack de infraestrutura antes de adotar em produção.

Casos de uso reais

O QUERY brilha em cenários específicos onde buscas complexas são parte central do produto.

  • É-commerce: busca de produtos com múltiplos filtros (categoria, marca, faixa de preço, avaliação, disponibilidade, frete grátis). Sem QUERY, a query string fica enorme ou você precisa de POST.
  • Portais imobiliários é de vagas: busca com filtros geográficos, faixas de valores é características múltiplas. Dados estruturados encaixam perfeitamente no corpo JSON.
  • APIs de analytics: consultas de métricas com filtros de data, dimensões, métricas agrupadas. Hoje feitas com POST, mas sem cache automático.
  • Sistemas de BI é relatórios: queries parametrizadas que precisam ser cacheadas por minutos ou horas para aliviar o banco de dados.

Dicas é boas práticas

Se você vai implementar QUERY em uma API nova ou migrar uma existente, algumas práticas vão te poupar de dores de cabeça.

🚀
Pro tip: versionar o schema do body

Inclua um campo version ou v no corpo do QUERY desde o início. Isso facilita a evolução do schema de filtros sem quebrar clientes antigos.

  • Sempre retorne Content-Type: application/json nas respostas para facilitar a integração.
  • Inclua Cache-Control explícito nas respostas. O padrão cacheável não significa que o cache vai durar para sempre.
  • Documente o schema do corpo com JSON Schema ou OpenAPI 3.1 (que tem suporte ao método QUERY).
  • Para compatibilidade com clientes que não suportam QUERY ainda, considere manter um endpoint POST /api/recurso/busca em paralelo.
🔒
Segurança: valide o corpo sempre

Nunca confie no conteúdo do corpo de uma requisição QUERY sem validação. Assim como em POST, o body pode conter dados maliciosos ou mal formatados. Use schema validation no servidor.

Vale a pena adotar o HTTP QUERY Method?

Se você está construindo uma API nova que terá buscas com múltiplos filtros, sim, vale estruturar pensando no QUERY. Mesmo que o suporte nativo dos frameworks ainda esteja chegando, implementar no nível do router é simples é você já garante a semântica correta desde o início.

Se você tem uma API existente usando POST para buscas, a migração faz sentido quando o cache for importante para você. Se os resultados das buscas puderem ser cacheados é isso reduzir carga no banco, o ganho justifica a mudança.

Para equipes que já usam GraphQL, o QUERY HTTP não substitui. São ferramentas com níveis de abstração diferentes. Use GraphQL quando precisar de flexibilidade no cliente para escolher campos, use QUERY quando quiser a simplicidade do REST com filtros complexos no corpo.

O próximo passo é acompanhar o suporte nos frameworks que você usa (Express, FastAPI, ASP.NET, Laravel) é ficar de olho no suporte nos clientes HTTP como Axios, HTTPx é Fetch API. A especificação já está definida, o ecossistema está convergindo.