Aikido

Como evitar a quebra de contratos de API públicas: manter a compatibilidade com as versões anteriores

Capacidade de manutenção

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, TypeScript

Introduçã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.

FAQs

Tem perguntas?

Quais são as alterações consideradas de rutura?

Remover campos das respostas, mudar o nome dos campos, alterar os tipos de campos (de cadeia para número), tornar obrigatórios os parâmetros opcionais, alterar os códigos de estado HTTP para condições existentes, alterar os requisitos de autenticação e modificar os formatos de resposta a erros. A adição de novos parâmetros de pedido obrigatórios ou a remoção completa de pontos de extremidade também são alterações de rutura.

Como é que adiciono novos campos obrigatórios sem quebrar os clientes?

Tornar o novo campo opcional inicialmente com uma predefinição sensata. Documentar a alteração e dar tempo aos clientes para a adoptarem. Após tempo suficiente (6-12 meses para APIs públicas), torne o campo obrigatório numa nova versão da API. Nunca torne os campos opcionais existentes obrigatórios sem controlo de versão.

Qual é a diferença entre o controlo de versões da API e a depreciação?

O controle de versão cria um novo ponto de extremidade (/v2/users) ao lado do antigo, permitindo que ambos coexistam. A depreciação marca um ponto de extremidade ou campo antigo como obsoleto, mantendo-o funcional, com uma linha de tempo para uma eventual remoção. Utilize o controlo de versões para as principais alterações e a descontinuação para a eliminação gradual de funcionalidades menores.

Durante quanto tempo devo manter versões de API obsoletas?

Para APIs públicas, manter versões obsoletas durante pelo menos 12-18 meses. Para APIs internas, coordene com as equipas de clientes para obter um calendário de migração. Forneça sempre um aviso prévio (mínimo de 3-6 meses) antes de remover pontos de extremidade obsoletos. Monitorizar as métricas de utilização para garantir que os clientes migraram antes do encerramento.

Posso alterar a ordem dos campos de resposta?

Sim, a ordem dos campos do objeto JSON não faz parte do contrato da API. Clientes bem escritos analisam o JSON pelo nome do campo, não pela posição. No entanto, faça testes minuciosos, pois alguns clientes mal escritos podem depender da ordem dos campos. Para matrizes, a ordem geralmente é importante e não deve ser alterada, a menos que esteja documentada.

Como é que faço uma versão das APIs sem alterar o caminho do URL?

Utilizar cabeçalhos HTTP: Accept: application/vnd.myapi.v2+json ou cabeçalhos personalizados como API-Version: 2. Os parâmetros de consulta também funcionam: /api/users?version=2. A negociação de conteúdo por meio de cabeçalhos é mais limpa, mas mais difícil de testar em navegadores. Escolha uma estratégia e use-a de forma consistente.

Obter segurança gratuitamente

Proteja seu código, nuvem e tempo de execução em um sistema central.
Encontre e corrija vulnerabilidades rapidamente de forma automática.

Não é necessário cartão de crédito | Resultados do scan em 32secs.