Chapitre 7.1Introduction aux API

L'interface de programmation entre les systèmes.

7 minutes de lecture

Pour être plus efficaces et concevoir des solutions plus robustes, les développeurs adoptent certains principes, parmi lesquels :

  • Séparer les responsabilités : le code est divisé en briques cohérentes. La plupart du temps, une brique est un lot de fonctionnalités autour d'un domaine métier. Elle assure un service en toute indépendance, masquant pour l'extérieur la complexité de ce qu'elle fait.

    Exemple : j'ai un site de e-commerce constitué d'un gestionnaire de commandes, d'un catalogue de produits, d'un module de paiement... Le gestionnaire de commandes se sert du module de paiement pour débiter le client, il n'a pas besoin de savoir en détail comment le paiement est réellement opéré, juste que c'est fait.
  • Ne pas réinventer la roue : plutôt que de perdre du temps à tout recoder nous-mêmes, on préfère s'appuyer sur le travail d'un tiers.

    Ce tiers peut être une autre entreprise, un service interne, une communauté etc. Le service rendu peut prendre différentes formes : gratuit vs payant, open-source vs propriétaire, bibliothèque de composants à télécharger vs service en ligne...

    Exemple : une bibliothèque que je peux intégrer directement dans mon code pour manipuler des dates dans différents fuseaux horaires.

    En règle générale, vu le temps que le tiers y a consacré et son expertise du sujet, le service qu'il délivre est de bien meilleure qualité que ce qu'on aurait nous-mêmes produit. Il connaît des règles de gestion qu'on ignore, il a déjà traité les cas tordus, et sa sécurité a été éprouvée par des milliers d'utilisateurs.

    Il y a des exceptions, des situations qui nous poussent à monter nos propres systèmes : le tiers vend son service trop cher et on a la capacité de le refaire en interne, on veut faire du sur-mesure, on ne veut pas mettre en danger le coeur de métier de l'entreprise...

Le logiciel, l'application, est donc composé de dizaines de sous-éléments (briques métiers, bibliothèques tierces...) qui doivent communiquer et travailler ensemble sans qu'ils ne connaissent en détail leur fonctionnement respectif.

Interface de Programmation de l'Application

Partons directement sur une analogie. Tu es en voiture, pour la conduire, le constructeur t'a mis à disposition différentes interfaces : pédales, levier de vitesse, volant, options électroniques... Chaque interface permet de contrôler un système sous-jacent (moteur, caméra de recul...) sans que tu n'aies besoin d'en connaître le détail. Le constructeur a d'ailleurs choisi de te cacher les composants, les courroies et les réservoirs sont complètement inaccessibles depuis l'habitacle.

Dans le monde du logiciel, c'est tout pareil. Le développeur d'un service va mettre à disposition une interface permettant d'utiliser son produit. Pour guider l'utilisateur, il va n'exposer publiquement que certains points d'entrée représentant les fonctionnalités principales et garder privés les détails du fonctionnement.

Ces points d'entrée publics représentent ce qu'on appelle l'API : Application Programming Interface.


En tant que développeur web, nous construisons et utilisons principalement deux types d'API :

1 - Les API des bibliothèques de composants ou des briques logicielles

Pendant leurs conceptions, les développeurs font ressortir dans leur code la notion de "contrat". C'est-à-dire qu'à travers les possibilités offertes par le langage de programmation, ils essaient de guider l'utilisation de leur brique.

Exemple :

Je développe une bibliothèque capable d'envoyer un email. Elle est vouée à être importée sur d'autres projets.

En interne, le composant central de ma bibliothèque, "EnvoyeurEmail", fait plein de choses : vérification de la validité des adresses email, encodage des pièces jointes... En tant que concepteur de la bibliothèque, je veux faire comprendre à ses utilisateurs qu'ils n'ont pas besoin de déclencher eux-mêmes ces fonctionnalités, tout est fait automatiquement. D'ailleurs, si possible, je leur bloque la possibilité de le faire en exposant publiquement qu'une fonction envoyerEmail.

Pour établir un contrat, je crée le fichier "CapableEnvoyerEmail" dans lequel j'explique comment envoyer un email : la fonction à appeler, ce qu'elle attend en entrée, ce qu'elle retourne. J'associe ensuite "EnvoyeurEmail" à "CapableEnvoyerEmail" pour qu'il respecte sa structure. À partir de là, on sait que "EnvoyeurEmail" est capable d'envoyer un email si on appelle telle fonction avec telle entrée.

Tous les contrats que respecte "EnvoyeurEmail" forment son API.

Pourquoi avoir représenté l'API dans des fichiers séparés, nous n'aurions pas simplement pu lire le code de "EnvoyeurEmail" ?

Dans le code, nous essayons au maximum de dépendre des contrats, pas directement des composants. C'est-à-dire que celui qui appelle la fonction "envoyerEmail" sait qu'il utilise quelque chose "capable d'envoyer un email" mais n'a pas conscience qu'il s'agit concrètement de "EnvoyeurEmail". Il accepterait d'utiliser n'importe quel autre composant qui respecte lui aussi le contrat.
Ça tombe bien, on aura justement besoin de créer un "faux envoyeur d'email" pour ne pas envoyer les emails lors des tests automatiques. On va créer un composant "FauxEnvoyeurEmail", qu'on va lui aussi associer à "CapableEnvoyerEmail".

Déclarer explicitement l'API ouvre donc la voie vers la portabilité. C'est-à-dire la liberté pour les clients de remplacer le prestataire de service en toute transparence, sans avoir besoin de modifier la moindre ligne de code.
Plusieurs communautés, par exemple le PHP Framework Interop Group, proposent des designs réfléchis pour les API des composants associés aux tâches les plus communes : envoyer une requête HTTP, mettre en cache, tracer les évènements dans un journal, demander l'heure... Bien qu'étant des propositions, ce sont implicitement devenues des normes. Les clients se sont mis à n'utiliser que les composants respectant ces API.

2 - Les API distantes

Elles servent à relier des systèmes à travers un réseau.

Exemple : ton casque bluetooth et ton smartphone mettent tous les deux à disposition une API pour qu'ils se détectent, se connectent, que tu puisses contrôler la lecture depuis un bouton sur ton casque...

Les API distantes les plus répandues sont les API web, qui passent par le protocole HTTP. Celui-ci intègre nativement toutes les fonctionnalités permettant un pilotage de ressources distantes. REST, l'un des styles d'architecture d'API les plus utilisés, est fondé sur HTTP, en particulier sur ses verbes : GET (obtenir une info), POST (créer), DELETE (supprimer), PUT / PATCH (mettre à jour).

Exemple : "GET /offre/42" permet d'obtenir les détails de l'offre n°42.


Depuis une quinzaine d'années, les API web ont connu une croissance spectaculaire.

Les startups ont massivement adopté des architectures dites API-first, dans lesquelles l'API est conçue avant même l'interface utilisateur. Des services comme Twilio (l'envoi de SMS), Stripe (le paiement) ou Algolia (le moteur de recherche) ont prouvé qu'une API peut être un produit à part entière, et donc un modèle économique en soi. Depuis, on entend parler tous les jours d'un nouveau service qui se lance sous le modèle Software as a Service (SaaS), c'est-à-dire un logiciel hébergé par son éditeur et vendu par abonnement plutôt qu'installé chez le client. La plupart de ces SaaS exposent une API web pour s'intégrer aux outils de leurs clients. Certains produits se sont d'ailleurs spécialisés dans l'interconnexion entre tous ces SaaS, comme Zapier ou Make. Ils permettent de monter des chaînes de traitement complètes sans écrire une ligne de code, ce qui a popularisé la mouvance no-code.


Aujourd'hui, l'amalgame est fait entre "API" et "API web" dans la plupart des esprits. Dans la suite de ce chapitre, j'utiliserai moi aussi simplement "API" indistinctement.

Design

Le I de API signifie Interface. Une interface implique qu'il y a un utilisateur. Un utilisateur implique que l'API doit être facile à utiliser, logique, évolutive... Elle doit être réfléchie et conçue avec une vision produit.

Dans le chapitre sur la programmation objet, nous avons évoqué le Domain Driven Design (DDD), l'approche de conception du code visant à calquer le domaine métier de la vie réelle. Il est crucial, avant un projet, de briefer au maximum les développeurs sur le domaine métier : son vocabulaire, ses concepts, son organisation, le besoin présent, les idées futures déjà envisagées...

La conception des API modernes suit exactement la même logique.

L'API et le code déclenché derrière étant en théorie pensés en même temps, en se basant sur les mêmes concepts métiers, nous essayons au maximum de développer un ensemble cohérent utilisant le même vocabulaire et la même organisation des données.

Mais il y a quand même quelques différences !

Prenons un exemple :

Un utilisateur se connecte sur ton site depuis son espace client. Pour construire la page, le front-end envoie une requête HTTP vers l'API du back-end afin d'obtenir son pseudo, ses préférences de communication, son historique d'abonnements, ses moyens de paiement etc... Le front-end a pris le parti de demander tout ça en une seule fois pour faire un seul appel réseau et économiser ainsi de précieuses secondes. Ça lui permet aussi de tout stocker d'un coup au même endroit dans le cache.

La réponse de l'API ressemble à quelque chose comme :

Réponse de l'API
{
    "utilisateur": {
        "pseudo": "toto",
        "communications": {
            "newsletter": true,
            "offresCommerciales": false
        },
        "abonnements": [
            {
                "offre": "premium",
                "dateDebut": "2026-03-01T09:32:00+01:00",
                "dateFin": "2027-03-01T09:32:00+01:00",
                "statut": "en cours"
            },
            {
                "offre": "famille",
                "dateDebut": "2024-07-01T18:04:00+02:00",
                "dateFin": "2025-02-14T18:04:00+01:00",
                "statut": "terminé"
            }
        ]
    }
}

Quelque part dans le back-end, existent aussi les entités métiers : utilisateur, abonnement, offre, communication...

Par contre :

  • L'entité "utilisateur" du back-end a des champs additionnels comme le mot de passe, la date d'inscription... Ils ne sont pas exposés dans le retour API.
  • La gestion des utilisateurs et celle des abonnements sont dans des briques logicielles totalement indépendantes. Aller chercher les abonnements d'un utilisateur coûte cher. Comme la grande majorité des cas d'utilisation n'ont pas besoin des abonnements, l'entité back-end "utilisateur" n'a pas d'attribut "abonnements". C'est spécifiquement lors de cet appel front-end que le gestionnaire des utilisateurs va interroger le gestionnaire des abonnements pour peupler l'attribut "abonnements" de l'entité "utilisateur" de l'API.
  • Les dates sont exprimées en heure française dans l'API alors que le back-end, lui, travaille en UTC.
  • Le back-end utilise des statuts d'abonnement techniques, "100" ou "200", alors que l'API expose quelque chose d'humainement intelligible : "en cours", "terminé".

Il y a donc des différences, nous avons besoin d'une couche d'abstraction, de traduction, entre l'API et ce qu'il se passe réellement dans le back-end. Ça permet de personnaliser le retour, mais surtout de faire évoluer l'un sans impacter l'autre.

Rien de pire qu'un back-end qui zappe cette traduction et expose directement son fonctionnement interne. Il devient impossible à modifier sans avoir d'abord vérifié les impacts pour tous les clients de l'API. Si tu croises ce type de back-end, il y a de fortes chances pour qu'en plus, les développeurs n'aient pas non plus mis de traduction entre le back-end et ses sources de données. L'API expose donc directement la structure et le vocabulaire des sources de données, y compris s'il s'agit d'un partenaire externe. Les clients se retrouvent liés directement à ce partenaire, impossible d'en changer ou de mettre à jour l'intégration sans avoir migré tout le monde.

Autant dire que ça prend des mois, voire des années !

Cet extrême, que j'ai personnellement rencontré plus d'une fois, représente parfaitement la nécessité de bien penser son API dès le début. Une fois ouverte aux clients, une mauvaise conception devient très compliquée à corriger.

Parmi les questions à se poser :

  • Quelles fonctionnalités proposer ?
  • Quelle stratégie pour la mettre à jour ? Faut-il mettre en place une gestion de versions ?
  • Quel enchaînement d'appels le client va-t-il devoir faire pour obtenir cette donnée ?
  • Est-ce que le vocabulaire et les concepts sont cohérents partout ?
  • Et la plus importante de toutes, est-ce qu'elle est intuitive et facilement intégrable ?

Une bonne façon de tester une API avant de la construire, c'est d'écrire sa documentation en premier, puis de la faire lire à quelqu'un qui n'a pas participé à la conception. Si cette personne ne devine pas dans quel ordre appeler les points d'entrée, ce n'est pas elle le problème.

À qui s'adresse ton API ?

Toutes les API ne se conçoivent pas de la même façon, parce qu'elles n'ont pas le même public. On distingue en général trois familles.

  • Les API privées : elles ne sont utilisées qu'à l'intérieur de l'entreprise, typiquement entre le front-end et le back-end d'un même produit. Comme tous les clients sont connus, on peut les faire évoluer relativement vite, quitte à prévenir deux équipes et à modifier leur code en même temps.
  • Les API partenaires : elles sont ouvertes à quelques entreprises identifiées, sous contrat. Chaque évolution se négocie, se planifie, et s'accompagne d'une période pendant laquelle l'ancienne et la nouvelle version cohabitent.
  • Les API publiques : n'importe qui peut créer un compte et s'y brancher. Tu ne sais ni qui sont tes clients, ni ce qu'ils en font, ni quand ils mettront leur intégration à jour. Autant dire que la moindre modification incompatible se paie très cher.

Plus le public est large et inconnu, plus la conception initiale doit être solide et plus la marge de manoeuvre est faible ensuite. C'est le paradoxe des API, on doit prendre les décisions les plus définitives au moment où on connaît le moins bien les usages.

L'API comme produit

Une API bien conçue est un avantage concurrentiel certain.
Mon exemple préféré reste Stripe, le gestionnaire de paiements. À son lancement, Stripe n'était ni le moins cher, ni le plus complet, ni le mieux implanté auprès des banques. Il a pourtant pris une place énorme sur le marché parce que brancher un paiement chez lui prenait un après-midi là où la concurrence demandait des semaines de dossiers, de recette et de documentation illisible.

C'est une bascule intéressante à comprendre quand on vient du produit ou du marketing. Sur un service technique, l'utilisateur à convaincre n'est pas l'acheteur, c'est le développeur qui va faire l'intégration. Il essaie l'API en dix minutes un mardi soir, et son verdict remonte ensuite à la direction. Une API pénible ne perd pas un ticket de support, elle perd un client.


Les API constituent un sujet extrêmement vaste, que nous explorerons à travers une série de chapitres. Nous verrons d'abord les grands styles d'architecture avec REST et GraphQL, puis les communications asynchrones avec les files de messages et le découpage en microservices, avant de terminer par la sécurité, la monétisation et la documentation.

PrécédentLa programmation objet Tous les chapitres