
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 ayant créé ou utilisé régulièrement une API le réalise tôt ou tard, les changements disruptifs sont très mauvais et peuvent constituer une tache très sérieuse sur une API autrement utile. Un changement disruptif est une modification du comportement d'une API qui peut rompre l'intégration d'un utilisateur et entraîner beaucoup de frustration et une perte de confiance entre le fournisseur de l'API et l'utilisateur. Les changements disruptifs exigent que les utilisateurs soient informés à l'avance (avec des excuses accompagnantes) plutôt qu'un changement qui apparaît simplement, comme une nouvelle fonctionnalité agréable. La façon d'éviter cette frustration est de versionner une API avec des assurances 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-il difficile de versionner une API ? La vérité est que ça ne l'est pas, mais ce qui est difficile, c'est de conserver un minimum de stabilité en n'entrant pas inutilement dans un nombre vertigineux de versions et de sous-versions appliquées à travers des dizaines de points d'accès API avec des compatibilités peu claires.
Nous avons introduit la v1 de l'API il y a trois ans et nous n'avions pas réalisé qu'elle serait encore aussi forte à ce jour. Alors, comment avons-nous continué à fournir la meilleure API de livraison d'e-mails pendant plus de deux ans tout en maintenant la même version de l'API ? Cette stabilité est cruciale pour les développeurs d'applications avec des API d'e-mail dans l'infrastructure cloud, où la fiabilité et la cohérence sont primordiales. Bien qu'il y ait de nombreuses opinions différentes sur la façon de versionner les API REST, j'espère que l'histoire de notre humble mais puissant v1 pourra vous guider sur le chemin de l'éclaircissement du versionnement API.
REST is Best
API Governance
Avec une convention de versionnage sélectionnée, nous avons eu plus de questions. Quand devrions-nous augmenter la version ? Qu'est-ce qu'un changement majeur ? Devons-nous revérifier toute l'API ou juste certains points de terminaison ? Chez SparkPost, nous avons plusieurs équipes qui travaillent sur différentes parties de notre API. Au sein de ces équipes, les gens 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. Cela était plus important 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 de produit et notre CTO. Ce groupe est chargé d'établir, de documenter et d'appliquer nos conventions d'API à travers toutes les équipes. Un canal Slack de gouvernance d'API 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 point de terminaison API
Un nouveau paramètre optionnel
Un changement à un point de terminaison API non public
Une nouvelle clé optionnelle dans le corps du POST JSON
Une nouvelle clé renvoyée dans le corps de réponse JSON
Inversement, un changement majeur inclut tout ce qui pourrait casser l'intégration d'un utilisateur, comme :
Un nouveau paramètre requis
Une nouvelle clé requise dans les corps de POST
Suppression d'un point de terminaison existant
Suppression d'une méthode de requête de point de terminaison existante
Un comportement interne sensiblement 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 modifications majeures à l'API, car gérer plusieurs versions ajoute pas mal de surcharge. Nous avons décidé qu'il y avait quelques éléments que nous devions corriger dans notre API avant de nous engager à « v1 ».
Envoyer un simple e-mail demandait beaucoup trop d'efforts. Pour « garder les choses simples », nous avons mis à jour le corps POST pour garantir que les cas d'utilisation simples et complexes soient pris en charge. Le nouveau format était également plus à l'épreuve du futur. Ensuite, nous avons résolu un problème avec l'endpoint Metrics. Cet endpoint utilisait un paramètre « group_by » qui changeait le format du corps de la réponse GET de sorte que la première clé soit la valeur du paramètre group by. Cela ne semblait pas très RESTful, nous avons donc divisé chaque group by en un endpoint séparé. Enfin, nous avons audité chaque endpoint et avons apporté quelques modifications mineures ici et là pour garantir qu'ils respectaient les normes.
Documentation Précise
Il est important de disposer d'une documentation API précise et utilisable pour éviter les changements cassants, qu'ils soient délibérés ou involontaires. Nous avons décidé d'utiliser une approche simple de documentation API en exploitant un langage Markdown appelé API Blueprint et gérer nos docs dans Github. Notre communauté contribue et améliore ces docs open source. Nous maintenons également un ensemble de documents non publics dans Github pour les API et les endpoints internes.
Initialement, nous avons publié nos docs sur Apiary, un excellent outil pour le prototypage et la publication de docs API. Cependant, l'intégration d'Apiary dans notre site web ne fonctionne pas sur les appareils mobiles, nous utilisons donc maintenant Jekyll pour générer des docs statiques. Nos derniers SparkPost API docs se chargent désormais 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.