39 points par GN⁺ 2025-08-25 | Aucun commentaire pour le moment. | Partager sur WhatsApp
  • En ingénierie logicielle, les API sont un outil central, et une bonne API a idéalement pour caractéristique d’être familière et simple au point d’en devenir presque ennuyeuse
  • Comme une API est difficile à modifier une fois publiée, le principe de ne pas casser l’environnement utilisateur (WE DO NOT BREAK USERSPACE) est essentiel
  • Lorsqu’un changement est inévitable, une gestion de versions (versioning) est nécessaire, mais c’est un mal nécessaire qui augmente fortement la complexité et les coûts de maintenance
  • La qualité d’une API dépend au final de la valeur du produit lui-même, et un produit mal conçu rend difficile la création d’une bonne API
  • Pour la stabilité et l’évolutivité, il faut prendre en compte l’authentification par clé d’API, l’idempotence, la limitation de débit, la pagination basée sur des curseurs, etc.

Introduction : l’importance et le contexte de la conception d’API

  • L’une des tâches principales des ingénieurs logiciel modernes consiste à interagir avec des API
  • L’auteur a lui aussi de l’expérience dans la conception, l’implémentation et l’usage de diverses API publiques et internes, sous forme de REST, GraphQL, outils en ligne de commande, etc.
  • Les conseils existants sur la conception d’API ont souvent tendance à s’obséder sur des concepts complexes (la définition de REST, HATEOAS, etc.)
  • Cet article rassemble des principes pratiques de conception d’API fondés sur l’expérience réelle

L’équilibre entre familiarité et flexibilité : la première condition d’une bonne API

  • Une bonne API est une API “ordinaire et ennuyeuse”, c’est-à-dire dont l’usage ressemble à celui d’API déjà rencontrées
  • Les utilisateurs se concentrent avant tout sur l’atteinte de leur objectif plutôt que sur l’API elle-même, d’où la nécessité d’une conception avec une faible barrière à l’entrée
  • Une API publiée une fois est très difficile à modifier, ce qui impose de la prudence dès la phase de conception initiale
  • Les développeurs veulent une API aussi concise que possible, tout en conservant une flexibilité à long terme
  • Au final, le défi central est l’équilibre entre familiarité et flexibilité à long terme

Ne jamais casser l’espace utilisateur (WE DO NOT BREAK USERSPACE)

  • Dans la plupart des cas, ajouter des champs à une structure de réponse existante ne pose pas de problème
  • En revanche, supprimer des champs, ou modifier les types ou la structure, casse le code de tous les consommateurs
  • Les mainteneurs d’API ont la responsabilité de ne pas casser volontairement les logiciels des utilisateurs existants
  • Même la faute de frappe du header HTTP "referer" n’est pas corrigée en raison d’une culture de préservation de l’espace utilisateur

Faire évoluer une API sans la casser : stratégie de gestion de versions

  • Les changements cassants dans une API ne doivent être autorisés que lorsqu’ils sont indispensables, et dans ce cas la gestion de versions est la bonne réponse
  • Il faut faire coexister l’ancienne et la nouvelle version afin d’encourager une transition progressive
  • L’identifiant de version peut être porté de différentes façons, comme dans l’URL (/v1/) ou dans les headers, ce qui permet aux utilisateurs de migrer à leur propre rythme
  • La gestion de versions a des inconvénients : énormes coûts de maintenance (multiplication des endpoints, tests, support) et confusion côté utilisateur
  • Même avec une couche interne de traduction comme chez Stripe, la complexité fondamentale ne disparaît pas
  • Introduire une gestion de versions d’API doit rester un dernier recours

Les facteurs de succès d’une API dépendent entièrement de la valeur du produit

  • Une API n’est au fond rien d’autre que l’interface d’un véritable produit métier
  • Même pour des API comme OpenAI ou Twilio, ce que voulaient les utilisateurs, c’était avant tout la fonctionnalité fournie par l’API elle-même
  • Si le produit a de la valeur, les gens l’utiliseront même si l’API est peu pratique
  • La qualité d’une API est une caractéristique de "marge" : elle ne devient un critère de choix que lorsque la compétitivité intrinsèque est similaire
  • À l’inverse, un produit sans API constitue en soi un obstacle majeur pour les utilisateurs techniques

Si la conception du produit est mauvaise, l’API ne peut pas devenir bonne

  • Même avec une API techniquement très aboutie, cela n’a pas de sens si le produit n’a pas de valeur sur le marché
  • Plus important encore, si la structure fondamentale des ressources est illogique ou inefficace, cela se verra aussi dans l’API
  • Par exemple, un système qui stocke les commentaires sous forme de liste chaînée rend difficile une conception RESTful naturelle
  • Les problèmes techniques qui peuvent être masqués dans l’UI sont tous exposés par l’API, et imposent inutilement aux utilisateurs de comprendre le système en profondeur

Authentification (Authenticaton) et diversité des utilisateurs

  • Il faut impérativement prendre en charge une authentification par clé d’API à longue durée de vie
  • Même si l’on ajoute aussi des méthodes plus sûres comme OAuth, la barrière à l’entrée d’une clé d’API est de loin plus faible
  • Les consommateurs d’API ne sont pas seulement des ingénieurs, mais aussi des non-développeurs (commerciaux, chefs de produit, étudiants, développeurs hobbyistes, etc.)
  • Des exigences d’authentification difficiles ou complexes (comme OAuth) deviennent une barrière pour les utilisateurs non spécialistes

Idempotence et gestion des tentatives de nouvelle exécution

  • Pour les requêtes d’action (par ex. paiement, changement d’état, etc.), la sécurité des retries en cas d’échec est essentielle
  • L’idempotence signifie qu’envoyer plusieurs fois la même requête garantit que le résultat n’est traité qu’une seule fois
  • La méthode standard consiste à transmettre une "clé d’idempotence" en paramètre ou dans un header pour empêcher les traitements en double
  • Pour stocker ces clés d’idempotence, un simple magasin clé/valeur comme Redis suffit, et dans la plupart des cas une expiration périodique convient
  • En général, ce n’est pas nécessaire pour les requêtes de lecture/suppression (dans une approche REST)

Sécurité des API et limitation de débit (Rate limiting)

  • Les requêtes API envoyées par du code peuvent arriver à une vitesse bien supérieure aux actions manuelles d’un utilisateur
  • Une API déployée sans y penser peut être utilisée d’une manière non prévue (par exemple dans un système de chat à grande échelle)
  • La limitation de débit (ratelimit) est indispensable, et doit être plus stricte pour les opérations coûteuses
  • La désactivation temporaire de l’API pour un client donné (killswitch) doit aussi être envisagée
  • Il faut indiquer les informations de limitation de débit dans les headers de réponse (X-Limit-Remaining, Retry-After, etc.)

Stratégie de pagination

  • Pour renvoyer efficacement de grands ensembles de données (par ex. des millions de tickets), la pagination est indispensable
  • La pagination basée sur les offsets est simple, mais devient progressivement plus lente sur de gros volumes
  • La pagination basée sur des curseurs reste efficace même sur de très grands jeux de données, sans dégradation des performances des requêtes
  • L’approche par curseur est un peu plus difficile à implémenter et à utiliser, mais elle a de fortes chances d’être nécessaire à long terme
  • Il est judicieux d’inclure dans la réponse un champ comme next_page afin d’indiquer clairement le curseur pour la requête suivante

Champs optionnels et point de vue sur GraphQL

  • Les champs coûteux ou lents doivent être exclus de la réponse par défaut et ajoutés de manière optionnelle seulement si nécessaire
  • Il est possible d’inclure des données liées via un paramètre comme includes
  • GraphQL présente l’avantage d’une structure de données flexible, mais pose aussi des problèmes : accessibilité réduite pour les non-développeurs, complexité accrue du caching et des edge cases, difficulté d’implémentation côté backend
  • D’après l’expérience de terrain, adopter GraphQL ne convient que lorsqu’il est vraiment nécessaire

Particularités des API internes

  • Les API internes à l’entreprise diffèrent des API externes publiques sur de nombreux points
  • Leurs consommateurs sont pour la plupart des ingénieurs logiciel professionnels, ce qui permet une authentification plus complexe ou des changements cassants
  • Malgré cela, les principes de conception pour l’idempotence, la prévention des incidents et la réduction de la charge opérationnelle restent valables

Résumé

  • Une API est difficile à modifier et doit être facile à utiliser
  • Ne pas casser l’espace utilisateur est le devoir le plus important du mainteneur d’API
  • La gestion de versions d’API est coûteuse et ne doit être utilisée qu’en dernier recours
  • Au final, la qualité d’une API est déterminée par la valeur intrinsèque du produit
  • Un produit mal conçu ne peut être corrigé qu’à la marge au niveau de l’API
  • Il est important de prendre en charge une méthode d’authentification simple, d’assurer l’idempotence pour les requêtes d’action essentielles, ainsi que de prévoir des mesures de stabilité comme la limitation de débit et la pagination
  • Les API internes demandent une stratégie différente selon leur usage et leur public, mais la prudence dans la conception reste nécessaire
  • REST, JSON, OpenAPI et autres formats ne sont pas le sujet essentiel. Une documentation claire est plus importante

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.