Regra
Evitar quebrar pública API contratos.
Alterações para públicos API endpoints que poderia quebrar
existentes cliente pedidos são de rutura mudanças.
Pense de a API contrato como a promessa - mudando
a promessa depois de clientes dependem dele dela quebra o seu código.
Linguagens suportadas: PHP, Java, C#, Python, JavaScript, TypeScriptIntrodução
As APIs públicas são contratos entre o seu serviço e os seus consumidores. Uma vez que os clientes dependem do formato de pedido, da estrutura de resposta ou do comportamento de um ponto de extremidade, alterá-lo quebra o seu código. As alterações de rutura obrigam todos os clientes a actualizarem-se simultaneamente, o que é muitas vezes impossível quando não se controla os clientes. As aplicações móveis não podem ser actualizadas à força, as integrações de terceiros necessitam de tempo de migração e os sistemas antigos podem nunca ser actualizados.
Porque é importante
Interrupção e confiança do cliente: As alterações de rutura da API causam falhas imediatas nas aplicações cliente de produção. Os utilizadores sofrem erros, perda de dados ou interrupções completas do serviço. Isto prejudica a confiança entre os fornecedores de API e os consumidores e viola o contrato implícito de que as APIs estáveis permanecem estáveis.
Custos de coordenação: A coordenação de alterações radicais em várias equipas de clientes é dispendiosa e lenta. Cada equipa precisa de tempo para atualizar o código, testar as alterações e implementá-las. Para APIs públicas com clientes desconhecidos (aplicações móveis, integrações de terceiros), a coordenação é impossível.
Proliferação de versões: As alterações de rutura mal geridas levam à manutenção de várias versões da API em simultâneo. Cada versão requer caminhos de código, testes, documentação e correcções de erros separados, multiplicando exponencialmente a carga de manutenção.
Exemplos de código
Não conforme:
// Version 1: Original API
app.get('/api/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
res.json({ id: user.id, name: user.name });
});
// Version 2: Breaking change - renamed field
app.get('/api/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
res.json({
id: user.id,
fullName: user.name // Breaking: 'name' renamed to 'fullName'
});
});
Porque é que está errado: Renomear name para fullName quebra todos os clientes existentes que esperam o campo name. O código do cliente que acede a response.name receberá um valor indefinido, causando erros. Esta alteração obriga todos os clientes a actualizarem simultaneamente ou falham.
Conformidade:
// Version 2: Additive change - keeps old field, adds new
app.get('/api/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
res.json({
id: user.id,
name: user.name, // Keep for backward compatibility
fullName: user.name // Add new field (deprecated 'name')
});
});
// Or use API versioning
app.get('/api/v2/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
res.json({ id: user.id, fullName: user.name });
});
Porque é que isto é importante: Manter o antigo nome mantém a compatibilidade com as versões anteriores e acrescenta fullName para novos clientes. Em alternativa, a criação de um novo ponto final com controlo de versão (/api/v2/) permite efetuar alterações sem afetar os clientes existentes que ainda utilizam /api/v1/.
Conclusão
Evolua as APIs através de alterações aditivas: adicione novos campos, adicione novos pontos finais, adicione parâmetros opcionais. Quando as alterações de rutura forem inevitáveis, utilize o controlo de versões da API para executar versões antigas e novas em simultâneo. Elimine os campos antigos com prazos claros e guias de migração antes de os remover.
.avif)
