Versionamento de API REST: URL, header ou query, qual serve
7 min de leitura
Versionamento de API REST é a forma como uma API diz a um chamador qual contrato uma requisição está usando, para que o servidor possa mudar o contrato sem quebrar os chamadores que ainda não migraram. Há três lugares onde a versão pode ficar: o caminho da URL (/v2/orders), um header da requisição (Accept: application/vnd.acme.v2+json ou um Api-Version: 2026-10-01 personalizado), ou um parâmetro de query (/orders?version=2). O caminho é o mais comum porque é visível em todo lugar, o header é o mais limpo para a URL, e a query string é a que a maioria das equipes se arrepende de escolher. Qual serve depende de quem são seus chamadores e de como vocês planejam avisá-los sobre mudanças.
| Onde a versão fica | Exemplo | Visto por | Cacheável por padrão | Usado por |
|---|---|---|---|---|
| Caminho da URL | GET /v2/orders | Todo log, link, proxy e navegador | Sim | Twitter, Shopify, a maioria das APIs públicas |
| Header personalizado | Api-Version: 2026-10-01 | Só clientes que o enviam | Com Vary: Api-Version | Stripe (Stripe-Version), GitHub (X-GitHub-Api-Version) |
| Header Accept | Accept: application/vnd.acme.v2+json | Só clientes que o enviam | Com Vary: Accept | Media types do GitHub, algumas APIs corporativas |
| Parâmetro de query | GET /orders?api-version=2 | Logs e links, misturado aos filtros | Sim, mas polui as chaves de cache | APIs REST do Azure |
| Sem versão | GET /orders mais só mudanças aditivas | Ninguém | Sim | APIs internas e no estilo GraphQL |
O que são v1 e v2 em uma API REST?
v1 e v2 são rótulos para duas versões do contrato da API: os mesmos recursos, alcançáveis em caminhos diferentes, onde v2 pode renomear campos, mudar tipos, remover endpoints ou alterar formatos de erro dos quais os chamadores de v1 dependem. Uma requisição a /v1/orders continua recebendo o formato antigo enquanto v1 for suportada; uma requisição a /v2/orders recebe o novo. O número é uma promessa de compatibilidade, e a promessa é o que o torna útil. Incrementá-lo a cada release transforma o rótulo em ruído.
A maioria das APIs só precisa de uma nova versão major para uma mudança que quebra chamadores existentes. Adicionar um campo, um endpoint novo ou um parâmetro opcional novo pode sair sob a versão atual, porque um cliente bem escrito ignora o que não conhece. Quando versionar uma API, e o que fazer em vez disso cobre a decisão; este artigo é sobre onde a versão fica no versionamento de API REST depois que vocês decidiram incrementá-la.
O versionamento de API REST deve ir na URL ou em um header?
Coloque na URL se seus chamadores incluem pessoas digitando requisições em um navegador, copiando exemplos da documentação ou lendo logs; coloque em um header se vocês querem uma URL estável por recurso e seus chamadores são todos SDKs ou código que vocês controlam. O caminho da URL é explícito como nada mais é: um ticket de suporte com a linha da requisição já diz a versão. Um header precisa ser enviado em toda requisição, é invisível em um link e se perde fácil em um proxy, e é por isso que APIs versionadas por header sempre definem um padrão para requisições que não o enviam.
A abordagem por header tem uma vantagem real além de URLs arrumadas: ela separa a identidade do recurso de sua representação, que é como o HTTP foi desenhado. A RFC 9110 descreve a negociação de conteúdo via Accept, e um media type como application/vnd.github.v3+json é uma versão expressa dessa forma. Na prática, a pureza do design importa menos do que se os seus chamadores lembram de enviar o header.
Como funciona o versionamento por data?
Em vez de v1 e v2, a versão é uma data, e cada breaking change ganha uma data nova. O chamador fixa a data contra a qual integrou, geralmente uma vez no nível da conta, e mantém esse comportamento até decidir migrar. O header Stripe-Version do Stripe e o X-GitHub-Api-Version do GitHub funcionam assim.
O custo está na implementação. Cada breaking change vira uma pequena camada de transformação que converte entre a data fixada e o formato atual, e o servidor as empilha: uma requisição fixada dois anos atrás passa por toda mudança desde então. Isso é mais pesado de construir do que uma segunda cópia dos handlers, e recompensa uma API que muda raramente. Equipes que lançam um breaking change por mês acabam com dezenas de transformações. Versionamento de API do Stripe olha o modelo pelo lado do chamador, incluindo o que o changelog precisa carregar.
Por que o versionamento por query string é desaconselhado?
Porque ele mistura o contrato com os filtros. /orders?status=open&api-version=2 faz a versão parecer um refinamento opcional, e não a coisa que decide o formato de cada campo da resposta. É também o mais fácil de perder sem querer, já que query strings são reconstruídas por bibliotecas de cliente, removidas por alguns proxies e editadas à mão por pessoas. A própria orientação de design de REST API da Microsoft documenta a forma por parâmetro de query que o Azure usa, e o ecossistema de SDKs gerados ao redor dela é o que torna isso viável; sem essas ferramentas, um chamador que esquece o parâmetro recebe a versão padrão em silêncio.
O que acontece com a versão antiga?
Ela continua rodando, com uma data em que para. O propósito do versionamento é deixar os chamadores migrarem no próprio ritmo, e isso só é verdade se a versão antiga continua disponível por tempo suficiente para isso e eles são avisados de quando ela acaba. A orientação de versionamento de API do Google descreve o ciclo de vida que ele usa para as próprias APIs: uma versão estável é suportada até uma data de depreciação publicada, com a substituta disponível durante toda a janela de depreciação.
O anúncio é a parte que a maioria das equipes constrói de menos. Um caminho ou header novo só é útil para chamadores que sabem que ele existe, sabem o que mudou e sabem quando v1 vai embora. São três fatos, e cada um precisa de um lugar: uma entrada datada no changelog da API com as diferenças no nível de campo, um aviso de depreciação que declara a data final, e um guia de migração que percorre cada mudança para um chamador ainda na versão antiga. Encerrar uma versão de API cobre o passo final, incluindo o header Sunset que deixa um cliente descobrir a data em toda resposta.
Dá para evitar o versionamento de API REST por completo?
Sim, enquanto toda mudança for aditiva. Adicione campos, nunca remova nem renomeie; adicione endpoints, nunca mude o que um existente retorna; aceite parâmetros opcionais novos, nunca mude o significado de um antigo. Muitas APIs internas rodam por anos só com essa regra, e é a regra que esquemas GraphQL seguem por design. O custo é um contrato que só cresce, com campos depreciados que precisam ficar porque alguém, em algum lugar, ainda os lê.
Quando uma mudança aditiva é impossível, a versão é a ferramenta. A escolha entre caminho, header e data decide o que os chamadores veem e como a mudança é anunciada; o que permanece constante é que a mudança precisa ser escrita em algum lugar que um chamador vá ler. Para uma API com chamadores externos esse lugar é o changelog, e o artigo sobre breaking changes cobre o que conta como um.
FAQ
Qual é a melhor forma de versionar uma API REST? Uma versão major no caminho da URL é a mais amplamente entendida e a mais difícil de errar, o que a torna o padrão para uma API pública. Uma versão em header mantém as URLs estáveis e serve a APIs orientadas a SDK; um header baseado em data serve a APIs que mudam raramente e querem que os chamadores fixem o comportamento.
O que é v1 na URL de uma API?
É a primeira versão major do contrato da API. Requisições a /v1/... têm a promessa do formato documentado para a versão 1, mesmo depois que um /v2/ existe com campos ou comportamento diferentes.
Preciso de uma nova versão de API a cada mudança? Não. Mudanças aditivas como campos, endpoints e parâmetros opcionais novos podem sair sob a versão existente. Só uma mudança que quebra chamadores existentes precisa de uma nova.
Por quanto tempo uma versão antiga de API deve ser suportada? Tempo suficiente para os chamadores migrarem, o que para uma API pública costuma ser de seis a doze meses depois que a substituta está disponível, com a data publicada no anúncio e repetida no aviso de depreciação.
As afirmações técnicas deste artigo não foram revisadas de forma independente. Se algo estiver errado, avise a gente e vamos corrigir.