
Alors, à quel point cela peut-il être difficile de versionner une API ? La vérité est que ce n'est pas si compliqué, mais ce qui est difficile, c'est de maintenir un semblant de bon sens en évitant de se perdre dans un nombre vertigineux de versions et de sous-versions appliquées à des dizaines de points de terminaison d'API avec des compatibilités floues.
Breaking Changes Mauvais! API Versioning Bon!
Comme toute personne qui a construit ou utilise régulièrement une API s'en rend compte tôt ou tard, les changements incompatibles sont très mauvais et peuvent être une tache très sérieuse sur une API par ailleurs utile. Un changement incompatible est une modification du comportement d'une API qui peut briser l'intégration d'un utilisateur et entraîner beaucoup de frustration et de perte de confiance entre le fournisseur de l'API et l'utilisateur. Les changements incompatibles nécessitent que les utilisateurs soient informés à l'avance (avec des excuses accompagnantes) plutôt qu'un changement qui apparaît simplement, tel qu'une nouvelle fonctionnalité agréable. La façon d'éviter cette frustration est de versionner une API avec la garantie de la part du propriétaire de l'API qu'il n'y aura pas de changements surprenants introduits dans une seule version.
Alors, à quel point est-ce difficile de versionner une API ? La vérité est que ce n'est pas difficile, mais ce qui l'est, c'est de maintenir un certain bon sens en ne plongeant pas inutilement dans un nombre vertigineux de versions et de sous-versions appliquées à travers des dizaines de points de terminaison API avec des compatibilités peu claires.
Nous avons introduit v1 de l'API il y a trois ans et nous n'avions pas réalisé qu'elle serait toujours aussi forte aujourd'hui. Alors comment avons-nous continué à fournir la meilleure API de livraison d'e-mail pendant plus de deux ans tout en maintenant la même version de l'API ? Bien qu'il y ait de nombreux avis différents sur la manière de versionner les API REST, j'espère que l'histoire de notre modeste mais puissante v1 pourrait vous guider sur votre chemin vers l'illumination du versionnage d'API.
REST is Best
API Governance
Avec une convention de versionnage sélectionnée, nous avions plus de questions. Quand devrions-nous faire évoluer la version ? Qu'est-ce qu'un changement majeur ? Allons-nous réviser toute l'API ou juste certains points de terminaison ? Chez SparkPost, nous avons plusieurs équipes travaillant sur différentes parties de notre API. Au sein de ces équipes, les personnes travaillent sur différents points de terminaison à différents moments. Par conséquent, il est très important que notre API soit cohérente dans l'utilisation des conventions. C'était plus grand que le versionnage.
Nous avons établi un groupe de gouvernance comprenant des ingénieurs représentant chaque équipe, un membre de l'équipe de gestion des produits, et notre CTO. Ce groupe est responsable d'établir, de documenter et de faire respecter nos conventions API sur toutes les équipes. Un canal de gouvernance API sur Slack est également utile pour des débats animés sur le sujet.
Le groupe de gouvernance a identifié un certain nombre de façons dont les changements peuvent être introduits dans l'API qui sont bénéfiques pour l'utilisateur et ne constituent pas un changement majeur. Ceux-ci incluent :
Une nouvelle ressource ou un nouvel endpoint API
Un nouveau paramètre optionnel
Un changement vers un point de terminaison API non public
Une nouvelle clé optionnelle dans le corps du POST JSON
Une nouvelle clé retournée dans le corps de la réponse JSON
Inversement, un changement majeur incluait tout ce qui pourrait casser l'intégration d'un utilisateur, tel que :
Un nouveau paramètre requis
Une nouvelle clé requise dans les corps POST
Suppression d'un endpoint existant
Suppression d'une méthode de requête d'un point de terminaison existant
Un comportement interne matériellement différent d'un appel API – tel qu'un changement du comportement par défaut.
The Big 1.0
Comme nous avons documenté et discuté de ces conventions, nous sommes également arrivés à la conclusion qu'il était dans l'intérêt de tout le monde (y compris le nôtre !) d'éviter de faire des changements majeurs à l'API, car gérer plusieurs versions ajoute pas mal de surcharge. Nous avons décidé qu'il y avait quelques choses que nous devrions corriger avec notre API avant de nous engager sur la « v1 ».
L'envoi d'un simple email nécessitait beaucoup trop d’efforts. Pour « garder les choses simples », nous avons mis à jour le corps POST pour s'assurer que les cas d'utilisation simples et complexes sont pris en charge. Le nouveau format était également plus pérenne. Deuxièmement, nous avons résolu un problème avec le point de terminaison Metrics. Ce point de terminaison utilisait un paramètre "group_by" qui modifiait le format de la réponse GET de sorte que la première clé soit la valeur du paramètre group by. Cela ne paraissait pas très RESTful, donc nous avons séparé chaque group by dans un point de terminaison distinct. Enfin, nous avons audité chaque point de terminaison et fait des modifications mineures ici et là pour nous assurer qu'ils respectaient les normes.
Documentation Précise
Il est important d'avoir une documentation API précise et utilisable pour éviter les changements qui cassent, qu'ils soient délibérés ou non. Nous avons décidé d'utiliser une approche simple de documentation API en exploitant un langage Markdown appelé API Blueprint et gérer nos documents dans Github. Notre communauté contribue et améliore ces documents open source. Nous maintenons également un ensemble de documents non publics dans Github pour les API internes et les points de terminaison.
Initialement, nous avons publié nos documents sur Apiary, un excellent outil pour prototyper et publier des documents API. Cependant, intégrer Apiary dans notre site Web ne fonctionne pas sur les appareils mobiles, nous utilisons donc maintenant Jekyll pour générer des documents statiques à la place. Nos derniers SparkPost API docs se chargent maintenant rapidement et fonctionnent bien sur les appareils mobiles, ce qui est important pour les développeurs qui ne sont pas toujours assis à leur ordinateur.
Séparer le déploiement de la sortie
Nous avons appris très tôt l'astuce précieuse de séparer un déploiement d'une mise en production. De cette façon, il est possible de déployer fréquemment des modifications lorsqu'elles sont prêtes par le biais de la livraison continue et du déploiement, mais nous ne les annonçons pas toujours publiquement ou ne les documentons pas toujours en même temps. Il n'est pas rare que nous déployions un nouvel endpoint d'API ou une amélioration d'un endpoint d'API existant et l'utilisions depuis l'interface utilisateur ou avec des outils internes avant de le documenter et de le prendre en charge publiquement. Ainsi, nous pouvons y apporter quelques ajustements pour l'améliorer en termes d'utilisabilité ou de conformité aux normes sans avoir à craindre d'introduire un changement majeur redouté. Une fois que nous sommes satisfaits du changement, nous l'ajoutons à notre documentation publique.
Doh !
Il est juste d'admettre qu'il y a eu des fois où nous n'avons pas respecté nos idéaux de « no breaking changes » et qu'il est important d'en tirer des leçons. Une fois, nous avons décidé qu'il serait préférable pour les utilisateurs si une certaine propriété était par défaut à true au lieu de false. Après avoir déployé la modification, nous avons reçu plusieurs plaintes de la part des utilisateurs car le comportement avait changé de manière inattendue. Nous avons annulé la modification et ajouté un paramètre au niveau du compte – une approche bien plus conviviale, c'est certain.
Parfois, nous sommes tentés d'introduire des modifications majeures à la suite de corrections de bugs. Cependant, nous avons décidé de laisser ces idiosyncrasies tranquilles plutôt que de risquer de casser l’intégration des clients pour le simple fait de la cohérence.
Il y a des cas rares où nous avons pris la décision importante d'apporter une modification majeure – comme déprécier une ressource ou une méthode API – dans l'intérêt de l'ensemble de la communauté des utilisateurs et seulement après avoir confirmé qu'il n'y a que peu ou pas d'impact pour les utilisateurs. Par exemple, nous avons délibérément fait le choix de modifier le comportement de réponse de la Suppression API mais seulement après avoir soigneusement pesé les avantages et les impacts pour la communauté et avoir communiqué la modification à nos utilisateurs. Cependant, nous ne introduirons jamais une modification qui pourrait avoir la moindre possibilité d'impacter directement l'envoi d'un email en production d'un utilisateur.