Versionamento de API: como mudar um contrato sem quebrar quem já usa

Entenda por que uma API precisa de versionamento, as três formas mais comuns de versionar (URL, header, query parameter) e como depreciar um endpoint antigo com aviso em vez de derrubar quem ainda depende dele.

tecnico backend api 4 min de leitura

Já falei aqui sobre o que é uma API e sobre o que um júnior precisa saber sobre elas, mas ficou faltando uma pergunta que só aparece depois que a API já está em produção, sendo consumida por alguém: como você muda o formato de uma resposta sem quebrar quem já depende do formato antigo?

O problema de mudar um contrato em produção

Uma API é um contrato. Quem consome ela (um app mobile, um frontend, um parceiro externo) escreve código esperando um formato específico de resposta. Se você renomeia um campo, remove algo que existia, ou muda o tipo de um valor, qualquer código escrito contra o formato antigo quebra na hora, sem aviso nenhum.

// antes
{ "nome": "Ana", "ativo": 1 }
 
// depois de uma mudança sem cuidado
{ "nomeCompleto": "Ana", "ativo": true }

O problema fica pior com app mobile: diferente de um site, que atualiza assim que você faz deploy, um aplicativo instalado no celular de alguém pode continuar rodando uma versão antiga por meses, porque a pessoa não atualizou. Se a API muda de um jeito incompatível, esse aplicativo antigo simplesmente para de funcionar, sem nenhum controle seu sobre quando isso vai ser corrigido do lado do usuário.

Versionamento por URL

A forma mais comum e mais direta de versionar é incluir a versão na própria URL:

GET /v1/usuarios/123
GET /v2/usuarios/123

Isso deixa claro, só de olhar a URL, qual contrato está sendo usado. O /v1 continua respondendo do jeito antigo pra quem ainda não migrou, enquanto o /v2 já pode ter o formato novo, os dois rodando ao mesmo tempo, sem conflito.

Versionamento por header

Uma alternativa mais discreta é não mexer na URL, e sim informar a versão desejada num header customizado:

GET /usuarios/123
Accept-Version: 2

Isso mantém uma URL só pra cada recurso, o que agrada quem acha várias URLs pra mesma coisa poluído, mas exige que todo cliente lembre de mandar o header certo, e fica menos visível numa olhada rápida de log ou de documentação, comparado com a versão aparecendo direto na URL.

Versionamento por query parameter

Uma terceira opção, menos usada, é a versão como parâmetro de busca:

GET /usuarios/123?versao=2

Funciona, mas mistura o conceito de versão de contrato com filtro de busca, que é o que query parameters normalmente representam, então costuma confundir mais do que ajudar.

Na prática, versionamento por URL é o mais comum hoje, principalmente por ser o mais visível e o mais fácil de testar direto no navegador ou no Postman, sem precisar configurar header nenhum.

Depreciar em vez de simplesmente remover

Trocar de versão resolve o problema de quebrar quem ainda usa o formato antigo, mas não resolve pra sempre: em algum momento, manter /v1 e /v2 rodando ao mesmo tempo, pra sempre, também não é sustentável. O caminho certo é depreciar com aviso, não remover de surpresa.

Um jeito simples de sinalizar isso é um header de aviso na própria resposta da versão antiga:

HTTP/1.1 200 OK
Deprecation: true
Sunset: Sat, 31 Jan 2027 00:00:00 GMT
Link: <https://api.exemplo.com/v2/usuarios>; rel="successor-version"

Isso avisa, de forma programática, que aquele endpoint vai deixar de existir numa data específica, e já indica onde está a versão nova. Ferramentas de monitoramento do lado de quem consome podem detectar esse header e alertar o time antes da data chegar, em vez de descobrir o problema só quando o endpoint já sumiu.

O que muda o suficiente pra precisar de versão nova

Nem toda mudança exige uma versão nova. Adicionar um campo novo numa resposta, sem remover nem renomear nada que já existia, geralmente é seguro: um cliente bem escrito ignora campo que não conhece. O que exige versão nova é mudança que quebra o que já existia: remover campo, renomear campo, mudar o tipo de um valor, mudar o significado de um código de erro. A regra prática é: se um cliente que já funciona hoje pararia de funcionar com a mudança, isso pede uma versão nova, não uma alteração direto na versão atual.

Fechando

Versionar API não é sobre exibir profissionalismo, é sobre reconhecer que, uma vez publicada, uma API vira um compromisso com quem já construiu algo em cima dela. Escolher entre URL, header ou query parameter importa menos do que o hábito por trás: nunca quebrar um contrato de surpresa, e sempre dar um caminho de saída avisado quando uma versão precisar ser desligada.