Evolvere l'API con il controllo della versione

I connettori personalizzati per app per la logica di Azure, Microsoft Power Automate, o Microsoft Power Apps devono fornire un file delle specifiche OpenAPI. Questa specifica OpenAPI definisce i singoli punti di ingresso noti come operazioni. A ogni operazione è associato un valore univoco di operationId e a una combinazione univoca di urlPath e HttpVerb.

{
    "/items": {
        "get": {
            "summary": "Get rows",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems"
        },
        "post": {
            "summary": "Insert row",
            "description": "This operation inserts an item.",
            "operationId": "PostItem"
        }
    }
}

Queste operazioni possono crescere e cambiare nel corso del tempo con l'aggiunta o l'espansione di funzionalità. Alcune modifiche sono semplicemente additive e non interrompono necessariamente il contratto esistente tra client e server. In questa categoria potrebbe rientrare l'aggiunta di nuovi parametri, la restituzione di più dati o l'uso di input più flessibili.

Tuttavia, molte modifiche potrebbero effettivamente interrompere il contratto descritto nella specifica OpenAPI. La rimozione di parametri, la rimozione del supporto per determinati input e la modifica del significato e del comportamento di un input, di un output o dell'operazione stessa rientrano nella categoria delle "modifiche che causano un interruzione".

Per l'evoluzione sicura di un'API, è importante seguire un criterio che possa essere applicato dai client. È responsabilità dell'API mantenere la compatibilità con le versioni precedenti, comunicare l'intenzione e delineare gli attributi di controllo delle versioni. È responsabilità del client mostrare o nascondere le operazioni deprecate, scadute o che possono avere versioni più recenti. In questo modo, le operazioni possono aumentare e svilupparsi nel tempo senza causare un'inutile fragilità alle applicazioni che si basano su di esse.

Annotazione API

OpenAPI non include il supporto intrinseco per il controllo operativo delle versioni. Per realizzare l'obiettivo previsto, gran parte del lavoro viene eseguito tramite l'oggetto x-ms-api-annotation, che viene applicato sia nell'ambito globale sia in quello dell'operazione. L'oggetto globale contiene proprietà che si applicano all'API nel suo complesso:

{
    "x-ms-api-annotation": {
        "status": "Preview"
    }
}
Proprietà Valori Impostazione predefinita Descrizione
status "Preview" "Production" "Preview" Stato dell'API nel complesso: avvio in anteprima e passaggio in produzione in base al livello raggiunto in termini di utilizzo e stabilità

Nell'ambito operativo questo oggetto contiene proprietà più dettagliate. All'esterno dell'oggetto esistono anche altre proprietà che applicano e contribuiscono al processo evoluzionario di controllo delle versioni:

{
    "deprecated": true,
    "x-ms-api-annotation": {
        "status": "Production",
        "family": "MyOperation",
        "revision": 2
    }
}
Proprietà Valori Valore predefinito Descrizione
deprecated null false true false Indica se l'operazione è o meno deprecata
x-ms-visibility null "" "Important" "Advanced" "Internal" "" La visibilità e la preminenza previste per questa operazione, dove null o "" implica uno stato Normale
status "Preview" "Production" "Production" Stato dell'operazione: può essere diverso dallo stato dell'API stessa, ma se non viene specificato eredita dallo stato dell'API di livello superiore
family {nome comune operazione} operationName Il nome che si applica a ogni revisione di questa operazione
revision numerico (1,2,3...) 1 La revisione della famiglia di operazioni specificata
expires Data ISO8601 (nessuno) Suggerimento facoltativo per indicare al client la fine prevista del supporto

Deprecato si può impostare su true se l'uso di questa operazione non è più auspicabile per i client. Questa proprietà è disponibile nella specifica dei campi fissi di OpenAPI.

Visibilità è un indicatore della preminenza relativa prevista per l'operazione. Un valore di visibilità "Important" indica che l'operazione dovrà essere inserita verso l'inizio dell'elenco, visualizzata in modo preminente. Un valore di visibilità normale, indicato da null o da una stringa vuota "", è l'impostazione predefinita e significa che l'operazione verrà inserita nell'elenco, probabilmente dopo le operazioni classificate come importanti. Un valore di visibilità "Advanced" indica che l'operazione potrebbe essere inserita verso la fine dell'elenco o anche essere inizialmente nascosta dietro un controllo Espandi/Comprimi. Le operazioni identificate come Advanced possono essere quelle più difficili da usare, meno diffuse o meno applicabili. Un valore di visibilità "Internal" indica che l'operazione non dovrà essere esposta agli utenti ma usata solo internamente. Le operazioni di questo tipo sono utili e preziose a livello di programmazione, ma non sono destinate agli utenti finali. Possono anche essere contrassegnate come tali per nasconderle nell'interfaccia utente durante il processo di deprecazione senza effettivamente rimuoverle dall'API, perché altrimenti si genererebbe una modifica che causa un'interruzione.

Status indica la stabilità dell'API o dell'operazione. "Preview" indica che l'operazione o l'API è nuova e potenzialmente non comprovata. Tale valore indica che i sistemi di produzione devono eseguire un'attenta valutazione prima di assumere una dipendenza. Quando l'operazione o l'API diventa maggiormente consolidata e dimostra di soddisfare gli standard in termini di affidabilità, percentuale di riuscita e scalabilità, il relativo stato può essere esplicitamente aggiornato a "Production".

Per assegnare lo stato "Production" alle operazioni, si applicano in genere i requisiti delle metriche seguenti:

  • 80% di percentuale di riuscita per un periodo di tre settimane
    • Come percentuale dei codici di risposta HTTP nell'intervallo 2xx
  • 99,9% di affidabilità costante per un periodo di tre settimane
    • Come percentuale dei codici di risposta HTTP non compresi nell'intervallo 5xx (i codici 502, 504 e 520 sono esclusi da questo calcolo)

Family indica la relazione tra operazioni che sono concettualmente identiche, ma hanno revisioni diverse con potenziali modifiche che causano un'interruzione tra una e l'altra. Più operazioni condivideranno lo stesso nome di famiglia se devono essere considerate revisioni una dell'altra e vengono identificate in sequenza da numeri di revisione univoci.

Revision indica l'ordine evoluzionario dell'operazione all'interno della famiglia. Ogni operazione all'interno di una famiglia avrà una revisione corrispondente a un indice integrale che implica la sequenza. Una revisione vuota verrà considerata con il numero 1. Quando sono disponibili nuove revisioni di un'operazione, i client dovranno visualizzarle in modo più preminente e raccomandarle esplicitamente pur consentendo la selezione di revisioni possibilmente meno recenti che non siano ancora deprecate.

Data di scadenza è una proprietà facoltativa e indica una potenziale scadenza di fine vita per cui il supporto dell'operazione non è più garantito. Dovrebbe essere impostata solo per le operazioni deprecate e non è attualmente indicata in nessuna interfaccia.

Durata operativa

Le operazioni hanno una durata prevedibile che può essere mostrata con l'esempio.

Punto di partenza

Inizialmente, le operazioni non devono necessariamente indicare informazioni sulle revisioni. A queste operazioni sono applicate le impostazioni predefinite. Sono pertanto considerate come revisione 1 in un nome della famiglia equivale a operationId.

{
    "/{list}/items": {
        "get": {
            "summary": "Get rows",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems"
        }
    }
}

La definizione equivalente più esplicita è la seguente:

{
    "/{list}/items": {
        "get": {
            "summary": "Get rows",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems",
            "deprecated": false,
            "x-ms-api-annotation": {
                "status": "Production",
                "family": "GetItems",
                "revision": 1
            }
        }
    }
}

Inizio delle operazioni

La maggior parte delle evoluzioni di un'API è costituita dall'aggiunta di un'operazione, ad esempio nuovi metodi e nuove revisioni di quelli esistenti. Per iniziare in sicurezza una nuova revisione, la specifica OpenAPI viene modificata in questo modo:

{
    "/{list}/items": {
        "get": {
            "summary": "Get rows (V1 - downplayed)",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems",
            "deprecated": false,
            "x-ms-visibility": "advanced",
            "x-ms-api-annotation": {
                "status": "Production",
                "family": "GetItems",
                "revision": 1
            }
        }
    }
    "/v2/{list}/items": {
        "get": {
            "summary": "Get rows (V2 - new hotness)",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems_V2",
            "deprecated": false,
            "x-ms-api-annotation": {
                "status": "Preview",
                "family": "GetItems",
                "revision": 2
            }
        }
    }
}

Importante

GetItems v2 ha un valore univoco di operationId e presenta inizialmente lo stato Preview. Inoltre, GetItems v1 ha ora una visibilità Advanced, quindi non verrà visualizzata in modo preminente.

Deprecazione delle operazioni

A volte i punti di ingresso v1 esistenti rimangono a tempo indefinito se continuano a offrire valore e non esistono motivi convincenti per terminarli. Tuttavia, molti punti di ingresso v2 sostituiscono esplicitamente il punto di ingresso v1. In questo caso, ai fini della sicurezza, tutto il traffico diretto all'operazione originale dovrà raggiungere lo zero nominale. Quando la telemetria conferma questa circostanza, è possibile apportare la modifica seguente:

{
    "/{list}/items": {
        "get": {
            "summary": "Get rows (deprecated)",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems",
            "deprecated": true,
            "x-ms-api-annotation": {
                "status": "Production",
                "family": "GetItems",
                "revision": 1
            }
        }
    }
    "/v2/{list}/items": {
        "get": {
            "summary": "Get rows",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems_V2",
            "deprecated": false,
            "x-ms-api-annotation": {
                "status": "Production",
                "family": "GetItems",
                "revision": 2
            }
        }
    }
}

Importante

Si noti che GetItems V1 è ora contrassegnata come deprecata. Si tratta della transizione finale per la deprecazione delle operazioni. GetItems v2 ha ora completamente sostituito GetItems v1.

Perché preoccuparsi?

Esistono diversi motivi per aderire al controllo operativo delle versioni. In primo luogo, in questo modo ci si assicura che i client come App per la logica di Azure e Power Automate continuino a funzionare correttamente quando gli utenti integrano operazioni di connettori nei loro flussi di dati. Per le operazioni è consigliabile usare il controllo delle versioni con il metodo indicato sopra ogni volta che:

  • Viene aggiunta una nuova revisione di un'operazione
  • Vengono aggiunti o rimossi parametri da un'operazione esistente
  • Un'operazione esistente modifica in modo significativo l'input o l'output

In conclusione

In determinate circostanze si può evitare di applicare il controllo delle versioni, ma in tal caso è necessario procedere con cautela e svolgere numerosi test per assicurarsi di non aver sottovalutato casi limite in cui si potrebbero verificare interruzioni impreviste per gli utenti. Ecco un breve elenco di situazioni prudenti in cui si può evitare il controllo delle versioni:

  • L'aggiunta di una nuova operazione.

    Questa modifica non interrompe in modo specifico i client esistenti.

  • Viene aggiunto un nuovo parametro facoltativo a un'operazione esistente.

    Le chiamate esistenti non verranno interrotte, ma è necessario valutare il caso con attenzione.

  • Il comportamento di un'operazione esistente cambia leggermente.

    Le chiamate esistenti potrebbero non essere interrotte in base alla natura della modifica e ai requisiti degli utenti. Si tratta del caso più precario di tutti, perché una differenza significativa in termini di accettazione dell'input, generazione dell'output, tempistica o elaborazione potrebbe avere effetti sul comportamento dell'operazione tali da complicare la verifica del rischio associato alla modifica.

Quando si apportano modifiche non banali alle API, è sempre consigliabile peccare per eccesso di prudenza ed eseguire l'iterazione di una revisione.

Inviare commenti

L'invio da parte degli utenti di feedback sui problemi riscontrati con la piattaforma di connettori o di idee su nuove funzionalità è molto apprezzato. Per fornire un feedback, vai a Inviare problemi o ottenere assistenza per i connettori e seleziona il tipo di commenti.