Aikido

Come evitare di violare i contratti delle API pubbliche: garantire la retrocompatibilità

Manutenibilità

Regola

Evitare di pubblicare API .
Modifiche ai pubblici API endpoint che potrebbero comprometterebbero
i richieste richieste sono stanno modifiche.
Pensate a l’ API contratto come una promessa  che si trasforma
la dopo clienti dipendono da esso si rompe il codice.

Linguaggi supportati: PHP, Java, C#, Python, JavaScript, TypeScript

Introduzione

Le API pubbliche sono contratti tra il proprio servizio e i suoi utenti. Quando i clienti fanno affidamento sul formato delle richieste, sulla struttura delle risposte o sul comportamento di un endpoint, qualsiasi modifica a tali elementi comporta la rottura del loro codice. Le modifiche che comportano una rottura costringono tutti i clienti ad aggiornarsi contemporaneamente, cosa spesso impossibile quando non si ha il controllo sui clienti stessi. Le app mobili non possono essere aggiornate forzatamente, le integrazioni di terze parti richiedono tempo per la migrazione e i sistemi legacy potrebbero non essere mai aggiornati.

Perché è importante

Interruzioni del servizio e fiducia dei clienti: le modifiche alle API causano guasti immediati nelle applicazioni client in produzione. Gli utenti riscontrano errori, perdita di dati o interruzioni totali del servizio. Ciò compromette la fiducia tra fornitori e utenti delle API e viola il contratto implicito secondo cui le API stabili devono rimanere tali.

Costi di coordinamento: coordinare le modifiche che comportano incompatibilità tra più team di clienti è costoso e richiede tempo. Ogni team ha bisogno di tempo per aggiornare il codice, testare le modifiche e procedere alla distribuzione. Nel caso delle API pubbliche con clienti sconosciuti (app mobili, integrazioni di terze parti), il coordinamento è impossibile.

Proliferazione delle versioni: una gestione inadeguata delle modifiche compatibilità rompono porta a dover gestire contemporaneamente più versioni dell'API. Ogni versione richiede percorsi di codice, test, documentazione e correzioni di bug distinti, moltiplicando in modo esponenziale l'onere di manutenzione.

Esempi di codice

❌ Non 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'
    });
});

Perché è sbagliato: rinominare "name" in "fullName" compromette il funzionamento di tutti i client esistenti che si aspettano il campo "name". Il codice client che accede a "response.name" riceverà il valore "undefined", causando errori. Questa modifica costringe tutti i client ad aggiornarsi contemporaneamente, pena il malfunzionamento.

✅ Conforme:

// 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 });
});

Perché è importante: Conservare il vecchio nome Il campo mantiene la compatibilità con le versioni precedenti, aggiungendo al contempo nomeCompleto per i nuovi clienti. In alternativa, è possibile creare un nuovo endpoint con versione (/api/v2/) consente di apportare modifiche che comportano incompatibilità senza influire sui client esistenti che continuano a utilizzare /api/v1/.

Conclusione

Fai evolvere le API attraverso modifiche incrementali: aggiungi nuovi campi, nuovi endpoint e parametri opzionali. Quando le modifiche che comportano incompatibilità sono inevitabili, ricorri al versioning delle API per far funzionare contemporaneamente la versione precedente e quella nuova. Indica chiaramente i tempi e fornisci guide alla migrazione prima di rimuovere i campi obsoleti.

Domande frequenti

Hai delle domande?

Quali modifiche sono considerate "rompenti"?

La rimozione di campi dalle risposte, la ridenominazione dei campi, la modifica dei tipi di campo (da stringa a numero), la trasformazione di parametri facoltativi in obbligatori, la modifica dei codici di stato HTTP per condizioni esistenti, l’alterazione dei requisiti di autenticazione e la modifica dei formati delle risposte di errore. Anche l’aggiunta di nuovi parametri di richiesta obbligatori o la rimozione completa di endpoint costituiscono modifiche che comportano incompatibilità.

Come posso aggiungere nuovi campi obbligatori senza causare problemi ai clienti?

Inizialmente, rendi il nuovo campo facoltativo, assegnandogli un valore predefinito ragionevole. Documenta la modifica e concedi ai clienti il tempo necessario per adottarla. Trascorso un periodo di tempo sufficiente (6-12 mesi per le API pubbliche), rendi il campo obbligatorio in una nuova versione dell'API. Non rendere mai obbligatori i campi facoltativi esistenti senza effettuare un aggiornamento di versione.

Qual è la differenza tra il versioning delle API e la loro deprecazione?

Il versioning crea un nuovo endpoint (/v2/users) accanto a quello precedente, consentendo la coesistenza di entrambi. La deprecazione contrassegna un vecchio endpoint o campo come obsoleto, pur mantenendolo funzionante, con una tempistica per la sua eventuale rimozione. Utilizza il versioning per le modifiche significative e la deprecazione per l'eliminazione graduale delle funzionalità minori.

Per quanto tempo dovrei mantenere le versioni obsolete delle API?

Per le API pubbliche, mantenere le versioni deprecate per almeno 12-18 mesi. Per le API interne, coordinarsi con i team dei clienti per definire una tempistica di migrazione. Fornire sempre un preavviso (minimo 3-6 mesi) prima di rimuovere gli endpoint deprecati. Monitorare le metriche di utilizzo per assicurarsi che i clienti abbiano completato la migrazione prima della disattivazione.

Posso modificare l'ordine dei campi di risposta?

Sì, l'ordine dei campi in un oggetto JSON non fa parte del contratto API. I client ben scritti analizzano il JSON in base al nome dei campi, non alla loro posizione. Tuttavia, è opportuno eseguire test approfonditi, poiché alcuni client scritti in modo non corretto potrebbero basarsi sull'ordine dei campi. Per gli array, l'ordine è solitamente importante e non dovrebbe cambiare, salvo diversamente specificato nella documentazione.

Come posso gestire le versioni delle API senza modificare il percorso URL?

Utilizza le intestazioni HTTP: Accept: application/vnd.myapi.v2+json oppure intestazioni personalizzate come API-Version: 2. Anche i parametri di query funzionano: /api/users?version=2. La negoziazione dei contenuti tramite intestazioni è più pulita, ma più difficile da testare nei browser. Scegli una strategia e utilizzala in modo coerente.

Metti in sicurezza ora

Metti in sicurezza il tuo codice, il cloud e il runtime in un unico sistema centralizzato.
Trova e risolvi le vulnerabilità rapidamente e automaticamente.

Nessuna carta di credito richiesta | Risultati della scansione in 32 secondi.