O HTTP te força a mentir
Você precisa buscar dados. A query tem filtros, ranges de data, campos aninhados. É uma leitura — não muda nada no servidor.

Qual método HTTP você usa?
O dilema que todo dev enfrenta
Seção intitulada “O dilema que todo dev enfrenta”GET é o método correto semanticamente. É safe. É idempotent. Proxies podem cachear. Browsers podem prefetch.
Mas GET não aceita body.
Então você enfia tudo na query string:
GET /api/orders?status=pending&created_after=2026-01-01&created_before=2026-06-30&customer_id=8841&include=items,shipping,payment&sort=-created_at&fields=id,status,total,customer.name,items.sku,items.qty&page=2&per_page=50 HTTP/1.1Funciona. Até não funcionar.
Agora imagina um filtro de dashboard real — com 15 facetas, 3 levels de nesting, e operadores lógicos:
GET /api/analytics/events?filter[0][field]=event_name&filter[0][op]=in&filter[0][value]=page_view,click,scroll&filter[1][field]=timestamp&filter[1][op]=gte&filter[1][value]=2026-01-01T00:00:00Z&filter[2][field]=timestamp&filter[2][op]=lte&filter[2][value]=2026-06-30T23:59:59Z&filter[3][field]=properties.country&filter[3][op]=in&filter[3][value]=BR,US,DE,JP,FR,GB,CA,AU,IN,MX&filter[4][field]=properties.device&filter[4][op]=neq&filter[4][value]=bot&group_by=event_name,properties.country&metrics=count,unique_users,avg_duration&having[0][metric]=count&having[0][op]=gte&having[0][value]=100&sort=-count&limit=500&offset=0&timezone=America/Sao_Paulo HTTP/1.1São 742 caracteres. Num caso real, com UUIDs e nomes de campo de verdade, passa de 2000 fácil.
Problema 1: URLs têm limite — e ninguém concorda no tamanho
Seção intitulada “Problema 1: URLs têm limite — e ninguém concorda no tamanho”A spec HTTP (RFC 9110) recomenda que servidores aceitem pelo menos 8.000 octets na request-line.
Na prática:
| Componente | Limite real |
|---|---|
| Chrome | ~2 MB (mas quebra em outros lugares antes) |
| Apache (padrão) | 8.190 bytes |
| Nginx (padrão) | 4.096–8.192 bytes |
| IIS | 16.384 bytes |
| CDNs (Cloudflare, AWS ALB) | 8.192–16.384 bytes |
| Proxies corporativos | Imprevisível — frequentemente 2.048 |
O problema não é o browser. É o caminho entre o browser e o seu servidor.
“In the wild, your link has to survive a gauntlet of browsers, proxies, CDNs, and ancient server configurations. If any one of those links in the chain decides your URL is too long, the whole thing snaps.”
Um proxy corporativo decide que sua URL é longa demais? 414 Request-URI Too Long. Sem retry. Sem fallback. Tela branca pro usuário.
Problema 2: POST mente sobre o que está acontecendo
Seção intitulada “Problema 2: POST mente sobre o que está acontecendo”Quando a URL fica grande demais, todo mundo faz o mesmo:
POST /api/orders/search HTTP/1.1Content-Type: application/json
{ "status": "pending", "created_after": "2026-01-01", "created_before": "2026-06-30", "customer_id": 8841, "include": ["items", "shipping", "payment"], "sort": "-created_at", "page": 2}Resolve o limite de URL. Mas agora você está mentindo.
POST significa “este request pode causar efeitos colaterais.” Intermediários, CDNs, e browsers não podem cachear. Se a conexão cair no meio, não podem reenviar automaticamente. Service meshes vão tratar como escrita. Ferramentas de observabilidade vão classificar como mutação.
Toda a infraestrutura HTTP — construída ao longo de 30 anos — interpreta POST como “cuidado, isso muda estado.”
Você não está mudando estado. Está lendo. Mas o protocolo inteiro acha que você está escrevendo.
Problema 3: Intermediários são hostis a GET com body
Seção intitulada “Problema 3: Intermediários são hostis a GET com body”“Tá, mas e se eu mandar GET com body?”
Tecnicamente, HTTP/1.1 não proíbe. Mas:
- RFC 9110 (§9.3.1): “content within a GET request has no defined semantics”
- Proxies descartam o body silenciosamente — seu filtro complexo simplesmente some
- WAFs bloqueiam — “GET request with body? Likely malicious”
- Client libraries ignoram — muitas descartam o body de um GET sem aviso
- Caches não consideram o body — requests diferentes retornam respostas iguais do cache
“There is software that expects GET to not have a body, so if it encounters such an aberration, it may decide it is a bad request.” — u/azhder, r/programming (112 upvotes)
O resultado? Bug silencioso. O request chega sem body, retorna dados errados, e você leva horas debugando por que o filtro “não funciona em produção mas funciona local.”
Quem sofre com isso todos os dias
Seção intitulada “Quem sofre com isso todos os dias”GraphQL
Seção intitulada “GraphQL”O caso mais visível. Uma query GraphQL é uma string potencialmente enorme:
query GetDashboardData($orgId: ID!, $dateRange: DateRangeInput!, $filters: [FilterInput!]!) { organization(id: $orgId) { analytics(dateRange: $dateRange, filters: $filters) { events { name count uniqueUsers avgDuration } topPages(limit: 20) { path views bounceRate } funnels { name steps { label conversionRate dropoff } } } users(filter: { active: true, role: ADMIN }) { edges { node { id email lastSeen permissions } } } }}Com variáveis, serializada e URL-encoded num GET, pode passar de 4KB facilmente. Por isso o GraphQL over HTTP spec recomenda POST para queries. Ou seja — o padrão da indústria é aceitar que o HTTP está quebrado e usar o método errado.
Elasticsearch
Seção intitulada “Elasticsearch”POST /products/_search HTTP/1.1Content-Type: application/json
{ "query": { "bool": { "must": [ { "match": { "title": "wireless headphones" } }, { "range": { "price": { "gte": 50, "lte": 200 } } }, { "terms": { "brand": ["Sony", "Bose", "Apple", "JBL"] } } ], "filter": [ { "term": { "in_stock": true } }, { "geo_distance": { "distance": "50km", "location": "-23.55,-46.63" } } ] } }, "aggs": { "price_ranges": { "range": { "field": "price", "ranges": [...] } }, "brands": { "terms": { "field": "brand", "size": 20 } } }, "sort": [{ "_score": "desc" }, { "created_at": "desc" }], "size": 20, "from": 40}Elasticsearch usava GET com body por anos. Até que não deu mais — proxies e API gateways quebravam. Agora aceitam tanto GET quanto POST. A documentação oficial diz: “Both HTTP GET and HTTP POST can be used to execute search with body.”
Isso é a definição de gambiarra institucionalizada.
APIs de busca com filtros de dashboard
Seção intitulada “APIs de busca com filtros de dashboard”Todo SaaS com um painel de analytics, toda plataforma com busca avançada, todo e-commerce com filtro de produtos — todos enfrentam a mesma escolha:
- URL gigante → quebra em proxies e CDNs
- POST /search → perde caching, retry, e semântica correta
- GET com body → bug silencioso em produção
Não existe opção boa. Até agora.
30 anos de crime semântico
Seção intitulada “30 anos de crime semântico”“Every time you filter a database or build a dashboard, you are committing an HTTP crime.” — Byte Pint, YouTube
Não é drama. É a realidade arquitetural. Estamos usando um protocolo de 1996 que nunca previu queries estruturadas no corpo de uma requisição safe.
A comunidade sabia disso. A IETF sabia disso. O primeiro draft de um método para resolver esse problema — na época chamado SEARCH — é de 2015. Foram mais de 10 anos de discussão, revisões, e debates sobre semântica.
“The whole process (from its inception as SEARCH) took more than 10 years.” — u/Nimelrian, r/programming (337 upvotes)
Em junho de 2026, saiu o RFC 10008. O método se chama QUERY.
Safe. Idempotent. Cacheable. Com body.
Próximo: Como funciona →
O QUERY resolve cada um desses problemas. Veja a semântica, o caching, e o que muda na prática.