API Versioning no Node.js organiza mudanças incompatíveis sem quebrar imediatamente clientes existentes. Uma API evolui: campos são adicionados, regras mudam, formatos de erro são corrigidos e operações antigas precisam ser aposentadas. O versionamento define como essas mudanças são comunicadas e por quanto tempo versões diferentes coexistem.
Nem toda alteração exige uma nova versão. Adicionar um campo opcional ou um novo endpoint geralmente é compatível. Renomear propriedades, mudar significado, tornar campo obrigatório ou alterar códigos de status pode quebrar consumidores e precisa de estratégia explícita.
O que é breaking change?
- remover ou renomear campo;
- mudar tipo de dado;
- alterar semântica de uma propriedade;
- tornar parâmetro obrigatório;
- remover valor de enum;
- alterar autenticação;
- trocar códigos de erro esperados;
- reduzir limites ou comportamento sem transição.
Versionamento na URL
GET /v1/orders/123
GET /v2/orders/123É simples de entender, documentar e rotear. A versão aparece em logs, caches e métricas. A desvantagem é incentivar duplicação de controllers quando a equipe copia toda a API.
app.use('/v1', createV1Router(dependencies));
app.use('/v2', createV2Router(dependencies));Compartilhe casos de uso e domínio. A versão deve ficar principalmente nos adapters de entrada e nos DTOs.
Versionamento por header
Accept: application/vnd.example.order.v2+jsonO URI permanece estável e o formato é negociado. Porém, debugging e testes ficam menos óbvios, e caches precisam considerar Vary: Accept.
Header próprio
X-API-Version: 2026-10-01É fácil de implementar, mas headers proprietários exigem documentação e suporte cuidadoso em proxies e SDKs.
Versões por data
Datas comunicam uma fotografia do contrato e funcionam bem quando mudanças são agrupadas.
API-Version: 2026-10-01Não use a data como desculpa para mudanças frequentes sem migração. O cliente ainda precisa de prazo, documentação e testes.
Escolhendo uma estratégia
Para APIs públicas, URL ou header explícito são previsíveis. Para APIs internas, pode ser melhor evoluir contratos de forma compatível e usar versionamento apenas quando necessário. Evite misturar várias estratégias no mesmo produto.
Separando contrato e domínio
function toOrderV1(order) {
return {
id: order.id,
total: order.totalCents / 100
};
}
function toOrderV2(order) {
return {
id: order.id,
amount: {
value: order.totalCents,
currency: order.currency
}
};
}O domínio continua único. Cada versão possui serializers e validators próprios.
Validação por versão
const schemas = {
v1: orderRequestV1,
v2: orderRequestV2
};
function validateRequest(version, body) {
const schema = schemas[version];
if (!schema) throw new Error('Versão não suportada');
return schema.parse(body);
}Consulte JSON Schema no Node.js.
OpenAPI por versão
Mantenha uma especificação para cada contrato suportado ou gere documentos a partir de componentes compartilhados.
openapi-v1.yaml
openapi-v2.yamlO CI pode detectar breaking changes antes do merge. Veja OpenAPI no Node.js.
Banco de dados
Não associe versão da API diretamente a uma versão rígida do schema. Durante a transição, o banco deve suportar leitores e escritores antigos e novos.
Use expand and contract:
- adicione nova coluna ou estrutura;
- publique código que entende ambos os formatos;
- faça backfill;
- migre clientes;
- pare de escrever o formato antigo;
- remova a estrutura legada depois do prazo.
Consulte Database Migrations no Node.js.
Depreciação
Uma versão antiga precisa de política clara:
- data de anúncio;
- data de fim de suporte;
- guia de migração;
- diferenças de contrato;
- canal de suporte;
- métricas de uso.
Headers podem informar depreciação e links para documentação, conforme padrões adotados pela organização.
Roteamento
function resolveVersion(req) {
const raw = req.headers['api-version'] ?? '2026-01-01';
const allowed = new Set(['2026-01-01', '2026-10-01']);
if (!allowed.has(raw)) {
const error = new Error('Versão não suportada');
error.statusCode = 400;
throw error;
}
return raw;
}Nunca carregue módulos ou execute código com base em string arbitrária de versão.
Versão padrão
Uma versão implícita facilita o início, mas pode impedir clientes de perceber mudanças. Para APIs críticas, exija versão explícita ou congele a versão padrão por longos períodos.
Erros consistentes
Mesmo quando payloads de sucesso evoluem, preserve uma estrutura de erro previsível. Mudanças em códigos e campos de erro também afetam integrações.
Idempotência entre versões
Uma chave idempotente deve identificar a mesma intenção, mas o fingerprint precisa considerar a versão e o corpo normalizado.
const fingerprint = hash({
version,
method: req.method,
path: req.route.path,
body: normalizedBody
});Veja Idempotency Keys no Node.js.
Cache
Se a versão vem por header, inclua o header em Vary e na chave do cache. Uma resposta v2 não pode ser servida para um cliente v1.
res.setHeader('Vary', 'API-Version, Accept-Encoding');Eventos e webhooks
Eventos também são contratos e precisam de versão no tipo ou envelope.
{
"type": "order.created.v2",
"id": "evt-1",
"data": { }
}Não altere silenciosamente o significado de um evento existente.
SDKs
SDKs podem fixar uma versão por release. Documente quais versões da API cada SDK suporta e mantenha testes de contrato.
Testes
- requests válidos de cada versão;
- versão ausente;
- versão desconhecida;
- serialização de respostas;
- autorização igual entre versões;
- cache separado;
- migração de banco compatível;
- clientes antigos durante rollout;
- documentação sincronizada.
Observabilidade
Inclua versão em logs, traces e métricas. Monitore tráfego, erros e latência por versão. Antes de remover uma versão, confirme que uso residual é conhecido.
Erros comuns
- criar versão nova para qualquer mudança;
- duplicar todo o código;
- mudar semântica sem versionar;
- não medir clientes antigos;
- remover versão sem prazo;
- esquecer cache e webhooks;
- acoplar domínio à versão;
- não testar banco durante coexistência.
Checklist
- breaking changes definidos;
- estratégia única escolhida;
- DTOs por versão;
- domínio compartilhado;
- OpenAPI atualizado;
- CI detecta incompatibilidades;
- depreciação documentada;
- métricas por versão;
- cache isolado;
- migration compatível.
Conclusão
API Versioning no Node.js é uma disciplina de compatibilidade, não apenas um prefixo na URL. O objetivo é permitir evolução previsível enquanto clientes migram com segurança.
Versione somente mudanças incompatíveis, mantenha domínio compartilhado, meça uso e ofereça uma janela de depreciação. Com contratos testados e migrations compatíveis, versões coexistem sem transformar a aplicação em várias bases de código independentes.
Consulte a especificação OpenAPI e o RFC de semântica HTTP.




