01
Versionar a URL não é versionar o contrato
A primeira reação de quase todo time diante desse problema é criar um prefixo de versão e prometer que a partir de agora toda mudança entra em uma versão nova. A promessa dura até a terceira mudança. Manter duas versões completas de uma API significa manter dois caminhos de código, dois conjuntos de testes, duas rotinas de correção de bug e duas superfícies de segurança, e o custo disso é alto o suficiente para que a segunda versão sempre acabe sendo um repasse fino para a mesma implementação da primeira. No momento em que isso acontece, a versão na URL virou decoração: a mudança de comportamento vaza para os dois lados porque só existe um lado de verdade.
O contrato de uma API não é a rota, é o conjunto de suposições que o cliente faz sobre o que ele recebe e o que ele pode mandar. Um cliente que lê o campo de total supõe que ele existe, que é um número, que está em centavos, que não é nulo em pedido concluído, e que o valor cabe no tipo usado para desserializar. Nenhuma dessas suposições aparece na URL, e qualquer uma delas pode ser violada sem trocar de versão. A pergunta útil não é qual versão o cliente chama, é quais dessas quatro suposições a sua mudança está prestes a violar.
| Mudança no payload | Compatível? | O que realmente decide |
|---|---|---|
| Adicionar campo opcional na resposta | Quase sempre | Só quebra se o cliente valida esquema fechado ou desserializa em modo estrito |
| Adicionar campo obrigatório na requisição | Não | Todo cliente que ainda não manda o campo passa a receber erro de validação |
| Remover campo da resposta | Não | Quebra na hora, mas de forma visível e rastreável |
| Renomear campo mantendo os dois | Sim, temporariamente | Vira incompatível no dia da remoção, não no dia da renomeação |
| Trocar número por texto com o mesmo valor | Não | Desserialização tipada falha mesmo com o valor idêntico |
| Adicionar valor novo a um campo enumerado | Depende | Quebra todo cliente que mapeia o enumerado para um tipo fechado |
| Relaxar uma validação de entrada | Sim na entrada, não na saída | O dado mais permissivo que entra hoje sai amanhã para quem não espera por ele |
As duas linhas que costumam surpreender são a do enumerado e a do relaxamento de validação. Adicionar o status de entrega parcial a um campo que antes só tinha três valores parece a mudança mais inofensiva possível, e derruba todo cliente escrito em linguagem com tipos fechados ou com um desvio condicional sem ramo padrão. Relaxar a validação de um campo de texto de cinquenta para quinhentos caracteres não quebra ninguém na entrada, e quebra o cliente que reserva cinquenta caracteres no banco dele no dia em que alguém usar os quinhentos. As duas têm a mesma assinatura: a mudança é aditiva do lado do servidor e restritiva do lado de quem consome.