Faire évoluer votre API avec le contrôle des versions

Les connecteurs personnalisés pour Azure Logic Apps, Microsoft Power Automate ou Microsoft Power Apps doivent fournir un fichier de spécifications OpenAPI. Cette spécification OpenAPI définit des points d’entrée individuels appelés opérations. Chaque opération a un operationId unique et une combinaison urlPath et HttpVerb unique.

{
    "/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"
        }
    }
}

Ces opérations peuvent évoluer et changer au fil du temps à mesure que des fonctionnalités sont ajoutées ou développées. Certaines modifications sont simplement additives et ne rompent pas nécessairement le contrat qui lie les clients et les serveurs. L’ajout de nouveaux paramètres, le renvoi de plus de données ou l’autorisation d’entrées plus flexibles peuvent entrer dans cette catégorie.

Toutefois, de nombreuses modifications peuvent réellement rompre le contrat décrit dans la spécification OpenAPI. La suppression de paramètres, la fin de la prise en charge de certaines entrées ou la modification de la signification et du comportement d’une entrée, d’une sortie ou de l’opération elle-même appartiennent à la catégorie « modification avec rupture ».

Pour pouvoir faire évoluer une API en toute sécurité, il est important de suivre un modèle qui peut être parcouru par les clients. La responsabilité de l’API consiste à maintenir la compatibilité descendante, à communiquer l’intention et à délimiter les attributs de la gestion de versions. Il incombe au client d’afficher ou de masquer les opérations dépréciées, arrivées à expiration ou susceptibles de présenter des versions plus récentes. De cette manière, les opérations peuvent évoluer et se développer au fil du temps sans provoquer de fragilité excessive sur les applications qui en dépendent.

Annotation API

OpenAPI n’offre pas de prise en charge intrinsèque de la gestion de version opérationnelle. Pour atteindre notre objectif, une grande partie du travail est effectuée au moyen de l’objet x-ms-api-annotation, qui est appliqué à la fois au niveau général et au niveau de l’opération. L’objet général contient des propriétés qui s’appliquent à l’API dans son ensemble :

{
    "x-ms-api-annotation": {
        "status": "Preview"
    }
}
Property Valeurs Default Description
statut "Preview" "Production" "Preview" État de l’API dans son ensemble : depuis la préversion jusqu’à la production, en fonction de l’utilisation et de la stabilité requises

Au niveau de l’étendue opérationnelle, cet objet contient des propriétés plus détaillées. Il existe également des propriétés supplémentaires en dehors de l’objet qui s’appliquent et participent au processus d’évolution de la gestion de versions :

{
    "deprecated": true,
    "x-ms-api-annotation": {
        "status": "Production",
        "family": "MyOperation",
        "revision": 2
    }
}
Propriété Valeurs Default Description
déconseillé null false true false Indique si l’opération est déconseillée
x-ms-visibility null "" "Important" "Advanced" "Internal" "" Visibilité et importance prévues de cette opération, où null ou "" implique un état Normal
statut "Preview" "Production" "Production" État de l’opération : il peut être différent de l’état de l’API elle-même, mais, s’il n’est pas indiqué, il est hérité de l’état de l’API de niveau supérieur
famille {nom courant de l’opération} operationName Nom qui s’applique à chaque révision de cette opération
révision numérique (1,2,3...) 1 Révision de la famille opérationnelle indiquée
expire Date ISO8601 (aucun) Indication facultative de la fin prévue de la prise en charge à l’intention du client

Deprecated peut être défini sur true quand il n’est plus souhaitable que les clients utilisent cette opération. Cette propriété existe dans la spécification Champs fixes OpenAPI.

Visibilité est un indicateur de l’importance relative prévue de l’opération. Une visibilité "Important" indique que l’opération doit se trouver vers le haut de la liste, affichée en évidence. Une visibilité normale (indiquée par null ou une chaîne vide "") est la valeur par défaut et signifie que l’opération s’affiche dans la liste, probablement après les opérations importantes. Une visibilité "Advanced" indique que l’opération peut se trouver vers le bas de la liste ou même être masquée initialement derrière un contrôle expand (développer). Les opérations avancées peuvent être plus difficiles à utiliser, moins populaires ou plus restrictives. Une visibilité "Internal" indique que l’opération ne doit pas être exposée aux utilisateurs et ne doit être utilisée qu’en interne. Les opérations internes sont utiles au niveau programmatique, mais ne sont pas destinées aux utilisateurs finaux. Les opérations internes peuvent également être marquées comme telles afin de les masquer pour tout type d’interface utilisateur pendant le processus de dépréciation sans réellement les supprimer de l’API, ce qui entraînerait une modification avec rupture.

Statut indique la stabilité de l’API ou de l’opération. "Preview" indique que l’opération ou l’API est nouvelle et potentiellement non éprouvée. Préversion indique que les systèmes de production doivent être prudents s’ils considèrent une dépendance. Une fois que l’opération ou l’API est plus établie et a prouvé qu’elle répond aux normes de fiabilité, au taux de réussite et à la scalabilité, elle peut être intentionnellement mise à niveau vers l’état "Production".

Les exigences métriques suivantes s’appliquent généralement aux opérations cherchant à obtenir l’état "Production" :

  • Taux de réussite de 80 % pendant trois semaines
    • défini en tant que pourcentage de codes de réponse HTTP dans la plage 2xx
  • Fiabilité de 99,9 % maintenue pendant trois semaines
    • définie en tant que pourcentage de codes de réponse HTTP dans la plage non 5xx (502, 504 et 520 sont exclus de ce calcul)

Famille indique la relation entre les opérations qui sont conceptuellement identiques, mais qui représentent des révisions différentes potentiellement séparées par des changements cassants. Plusieurs opérations partagent le même nom de famille si elles doivent être considérées comme des révisions les unes des autres et sont séquencées par leurs numéros de révision uniques.

Révision indique l’ordre d’évolution de l’opération au sein de la famille d’opérations. Chaque opération d’une famille comporte une révision qui correspond à un index intégral impliquant une séquence. Une révision vide est considérée comme une révision 1. Lorsque des révisions plus récentes d’une opération sont disponibles, les clients doivent les afficher plus en évidence et les recommander de manière plus intentionnelle, tout en permettant la sélection de révisions potentiellement plus anciennes qui ne sont pas encore dépréciées.

Expire est une valeur facultative et indique une échéance potentielle de fin de vie où la prise en charge de l’opération n’est plus garantie. Cette valeur ne doit être définie que pour les opérations dépréciées et elle n’est actuellement reflétée dans aucune interface.

Durée de vie opérationnelle

Les opérations ont une durée de vie prévisible qui peut être affichée par exemple.

Point de départ

Initialement, les opérations n’indiquent pas nécessairement quoi que ce soit sur les révisions. Ces opérations, auxquels s’appliquent des valeurs par défaut, sont considérées en tant que revision 1 dans un nom de famille équivalant à operationId.

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

Cela équivaut à la définition plus explicite :

{
    "/{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
            }
        }
    }
}

Lancement de l’opération

La plupart des évolutions d’une API constituent l’ajout d’une opération. Par exemple, de nouvelles méthodes et de nouvelles révisions des méthodes existantes. Pour lancer en toute sécurité une nouvelle révision, ajustez ainsi la spécification OpenAPI :

{
    "/{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
            }
        }
    }
}

Important

Comme on peut le constater, la révision GetItems V2 comporte un operationId unique et apparaît initialement à l’état de préversion. Notez également que la révision GetItems v1 a désormais une visibilité avancée ; elle ne s’affichera donc pas au premier plan.

Dépréciation de l’opération

Parfois, les points d’entrée V1 existants restent indéfiniment s’ils continuent à fournir de la valeur et qu’il n’existe aucune raison de les supprimer. Toutefois, de nombreux points d’entrée V2 remplacent intentionnellement le point d’entrée V1. Pour y parvenir en toute sécurité, tout le trafic doit atteindre un zéro nominal pour l’opération d’origine. Une fois que la télémétrie confirme cette situation, la modification suivante peut être apportée :

{
    "/{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
            }
        }
    }
}

Important

Notez que GetItems V1 est désormais marquée comme dépréciée. Il s’agit de la transition finale pour les opérations qui sont dépréciées. GetItems V2 a maintenant complètement remplacé GetItems V1.

Pourquoi s’en soucier ?

Il existe de nombreuses raisons d’adhérer à la gestion de version opérationnelle. En premier lieu, cela permet de s’assurer que les clients comme Azure Logic Apps et Power Automate continuent de fonctionner correctement lorsque les utilisateurs intègrent des opérations de connecteur dans leurs flux de données. Les opérations doivent être soumises à la gestion de version à l’aide de la méthode ci-dessus dans les cas suivants :

  • Une nouvelle révision d’une opération est ajoutée
  • Une opération existante ajoute ou supprime des paramètres
  • une opération existante modifie significativement l’entrée ou la sortie

Strictement parlant

Dans certains cas, on peut se passer de la gestion de version, mais il faut alors être très prudent et effectuer de nombreux tests pour être sûr de ne pas avoir négligé les cas limites où les utilisateurs peuvent se retrouver bloqués de manière inattendue. Voici la liste succincte des cas où vous pouvez ne pas utiliser le contrôle de version :

  • Une nouvelle opération est ajoutée.

    Cela ne doit pas bloquer spécifiquement les clients existants.

  • Un nouveau paramètre facultatif est ajouté à une opération existante.

    Cela ne doit pas interrompre les appels existants, mais doit être soigneusement pris en compte.

  • Le comportement d’une opération existante change légèrement.

    Cela peut ne pas interrompre les appelants existants en fonction de la nature de la modification et de ce que les utilisateurs utilisent. C’est le cas le plus précaire, car une différence significative en matière d’acceptation d’entrée, de génération de sortie, de synchronisation ou de traitement peut avoir un impact sur le comportement de l’opération de manière à ce qu’il soit difficile de déterminer le risque associé à la modification.

Il est toujours recommandé d’agir avec prudence et d’itérer une révision lorsque vous apportez une modification non triviale à l’API.

Fournir des commentaires

Nous apprécions grandement les commentaires sur les problèmes liés à notre plateforme de connecteurs ou les idées de nouvelles fonctionnalités. Pour fournir des commentaires, accédez à Soumettre des problèmes ou obtenir de l’aide avec les connecteurs et sélectionnez votre type de commentaire.