# Versionamento API: URL vs header vs query param - qual escolher?

> O versionamento de API por URL, header ou query param apresenta diferenças técnicas significativas. URL versioning oferece simplicidade e visibilidade, mas quebra a semântica REST. Header versioning mantém URLs limpas, porém dificulta cache e testes. Query param versioning é flexível, mas polui a interface. A escolha depende do contexto: URL para APIs públicas, header para sistemas internos, query param para transições.

*Blog Sem Juízo · Destaques · 24 de julho de 2026 · Igor Bastos*

URL, header ou query param? Cada abordagem de versionamento de API resolve um problema, mas nenhuma é bala de prata. Veja o comparativo técnico para não errar na escolha.

## A escolha que assombra todo dev de API

Você terminou a primeira versão da API. Tudo lindo. Seis meses depois, precisa alterar o formato de resposta de um endpoint. Se não versionar, clientes antigos quebram. Se versionar, precisa decidir **como**. URL, header ou query param? Não existe resposta certa universal, existe a certa para o seu contexto.

O versionamento de API é a prática de gerenciar mudanças na interface sem quebrar consumidores existentes. Cada abordagem carrega compensações: legibilidade, aderência RESTful, facilidade de cache e custo de manutenção. Vou comparar as três de forma direta.

## Visão geral das três abordagens

| Critério | URL | Header | Query param | |---|---|---|---| | Exemplo prático | /v1/usuarios, /v2/usuarios | Accept: application/vnd.api+json;version=2 | /usuarios?version=2 | | Semântica RESTful | Baixa (URL identifica recurso, não versão) | Alta (negociação de conteúdo) | Média (recurso é o mesmo, versão é parâmetro) | | Cacheabilidade | Fácil (cada URL é única) | Difícil (cache por header exige configuração extra) | Fácil (URL diferente com query string) | | Legibilidade para humanos | Alta | Baixa (header invisível na URL) | Média | | Facilidade de implementação | Muito fácil | Média (exige parser de header) | Fácil |

## Facilidade de implementação

**URL** ganha disparado. Você cria uma nova rota, aponta para o novo controlador e pronto. Frameworks como Express, Spring Boot e Django têm suporte nativo para prefixos de rota. É a abordagem mais rápida de colocar no ar.

**Query param** também é simples: um parâmetro a mais na requisição. O problema aparece quando você esquece de tratá-lo em algum lugar, clientes podem receber a versão errada sem aviso.

**Header** exige mais código. Você precisa ler o header Accept ou customizado, fazer parsing e rotear internamente. Não é complexo, mas adiciona uma camada que frameworks não resolvem de fábrica.

## Aderência aos princípios REST

Se você é purista REST, **header** é a escolha correta. Roy Fielding, no paper original, define que a URL identifica o recurso, não a versão dele. A versão faz parte da negociação de conteúdo, assim como você negocia JSON vs XML.

Na prática, poucas APIs seguem isso à risca. **URL** é a abordagem mais comum no mercado: GitHub, Stripe, Google Maps, todas usam URL. O pragmatismo venceu a pureza.

**Query param** fica no meio do caminho. O recurso é o mesmo (/usuarios), mas a versão vira um parâmetro. Não viola REST de forma gritante, mas também não segue a especificação.

## Cacheabilidade e desempenho

**URL** e **query param** são naturalmente cacheadas. Cada combinação de URL + query string é uma chave única no cache HTTP. Proxies, CDNs e browsers tratam isso sem configuração extra.

**Header** quebra o cache padrão. A mesma URL /usuarios pode retornar corpos diferentes dependendo do header Accept. Para cachear corretamente, você precisa configurar Vary: Accept no servidor e garantir que proxies intermediários respeitem isso. Muita gente esquece e acaba com cache poluído.

## Manutenção de código e rotas

Com **URL**, você mantém duas (ou mais) implementações paralelas: /v1/usuarios e /v2/usuarios. O código duplica, mas fica explícito. Cada versão pode evoluir independentemente.

**Header** e **query param** tendem a concentrar a lógica de versão dentro do mesmo endpoint. Você acaba com condicionais do tipo if version == 1 espalhadas. Conforme as versões acumulam, o código fica difícil de ler.

Uma ressalva: dá para mitigar isso com estratégia de adaptadores ou handlers separados internamente. Mas exige disciplina de equipe.

## Experiência do desenvolvedor consumidor

Desenvolvedores que consomem sua API preferem **URL**. É visível, testável no navegador, documentável de forma direta. Um link como https://api.exemplo.com/v2/usuarios/123 não deixa dúvidas.

**Query param** é quase tão bom, mas pode gerar confusão se combinado com outros parâmetros. Já vi casos em que ?version=2 conflitava com ?page=2&version=1.

**Header** é o pior para o consumidor. Ele não vê a versão na URL, precisa lembrar de enviar o header correto, e ferramentas como Postman ou cURL exigem configuração extra. Documentação precisa ser mais explícita.

## Versionamento semântico e evolução

Nenhuma abordagem resolve o problema de **quando** versionar. Você pode usar URL e ainda assim versionar mal, criando /v1.1, /v1.2 que ninguém entende. O consenso é usar versionamento semântico (MAJOR.MINOR.PATCH) e expor apenas a major na API pública.

Independente da técnica, o importante é comunicar as mudanças com clareza. Uma changelog bem escrita vale mais que qualquer escolha técnica.

## Veredito: qual escolher?

**Para quem busca simplicidade e adoção rápida**: escolha **URL**. É a abordagem mais usada, mais fácil de implementar e mais amigável para consumidores. Você perde pureza REST, mas ganha produtividade.

**Para quem prioriza aderência RESTful e controle fino**: escolha **header**. Exige mais configuração de cache e documentação, mas segue a especificação. Útil em APIs públicas que precisam negociar múltiplos formatos.

**Para quem quer um meio-termo**: escolha **query param**. Fácil de implementar, cacheável, mas pode poluir a URL e gerar confusão com outros parâmetros. Funciona bem em APIs internas ou com poucos consumidores.

Minha recomendação pessoal: comece com URL. Você sempre pode adicionar header depois como alternativa. O contrário é mais difícil.

## Perguntas frequentes sobre versionamento de API

### Qual a diferença entre versionamento de API e versionamento semântico?

Versionamento de API é a técnica de expor diferentes versões da interface (URL, header, query param). Versionamento semântico é um esquema de números (MAJOR.MINOR.PATCH) que indica o tipo de mudança. Você pode usar semântico com qualquer abordagem técnica.

### Versionar pela URL é considerado anti-pattern?

Alguns puristas REST consideram, porque a URL deve identificar o recurso, não a versão. Na prática, é o padrão de mercado. Grandes APIs como GitHub, Stripe e Twilio usam URL. A menos que você precise de negociação de conteúdo complexa, não é problema.

### Como evitar duplicação de código com versionamento por URL?

Use adapters ou camadas de serviço. A rota /v1/usuarios e /v2/usuarios podem chamar o mesmo serviço interno, com transformações específicas da versão na camada de apresentação. Evite duplicar lógica de negócio.

### É possível usar mais de uma abordagem ao mesmo tempo?

Sim. Muitas APIs aceitam URL e header simultaneamente. Por exemplo, se o header não for enviado, usa a versão da URL. Isso dá flexibilidade para consumidores. Só tome cuidado para não criar comportamentos ambíguos.

### Query param version funciona com cache de CDN?

Funciona, porque cada combinação de URL + query string é uma chave única. Mas CDNs costumam ter limites no número de query strings que consideram para cache. Verifique a documentação da sua CDN.

### Qual abordagem é mais segura?

Nenhuma é inerentemente mais segura. O risco maior é expor versões antigas com vulnerabilidades. Independente da técnica, desabilite versões legadas após um período de transição e mantenha apenas as duas últimas versões ativas.

---

Fonte (canonical): https://blogsemjuizo.com.br/destaques/versionamento-api-url-vs-header-vs-query-param-qual-escolher/
