API REST : concevoir, sécuriser et maintenir

Se connecter pour s'inscrire

Contrat, contrôle d'accès, limites et exploitation

Construire une API qui tient dans la durée : un contrat écrit avant le code, une spécification exécutée comme test, le contrôle d'accès par objet, les limites de débit, l'idempotence, et les règles de versionnement qui évitent de casser les clients.

  1. Public cible

    Débutants, étudiants et professionnels qui souhaitent acquérir une pratique structurée dans ce domaine.

  2. Objectifs

    Comprendre les notions essentielles et les appliquer dans un projet vérifiable.

  3. Prérequis

    Aucune connaissance préalable n’est strictement obligatoire ; les prérequis détaillés sont précisés dans les ateliers.

  4. Niveau

    Tous niveaux

  5. Ressources

    • Documentation officielle et références citées dans les ateliers.
    • Exercices, examens et projet de synthèse du catalogue.
  6. Validation des compétences

    La validation repose sur les évaluations actives et les livrables pratiques du cours.

  7. Besoins techniques

    Un ordinateur, un navigateur et les outils indiqués dans le premier atelier sont suffisants pour commencer.

Exercices, examens et projets

Concevoir une API : contrat, ressources et statuts

Exercice

Atelier API

Écrire la spécification OpenAPI puis un test de contrat qui l'exécute.

Obligatoire Consulter
Examen

Examen API REST

Auditer une API pour le contrôle d'accès, les limites et l'idempotence.

Obligatoire Consulter

Sécurité d'API et données

Exercice

Atelier API

Écrire la spécification OpenAPI puis un test de contrat qui l'exécute.

Obligatoire Consulter
Examen

Examen API REST

Auditer une API pour le contrôle d'accès, les limites et l'idempotence.

Obligatoire Consulter

Tester une API et la mettre en service

Exercice

Atelier API

Écrire la spécification OpenAPI puis un test de contrat qui l'exécute.

Obligatoire Consulter
Examen

Examen API REST

Auditer une API pour le contrôle d'accès, les limites et l'idempotence.

Obligatoire Consulter
  1. Concevoir une API : contrat, ressources et statuts

    1. Le contrat : ce qui engage, et envers qui

      Une API est un contrat commercial autant que technique. Toute forme de compatibilité promise devient une dette que l'on portera.

      Le contrat minimal qui tient

      • les ressources, nommées et non « les actions ». On manipule des objets, pas des verbes : la méthode HTTP exprime déjà l'action ;
      • les champs, leurs types, leur caractère obligatoire, et ce qui est modifiable par l'appelant ;
      • les codes de statut, par situation ;
      • la forme des erreurs, toujours la même, quelle que soit la route ;
      • les limites : taille maximale d'une requête, nombre d'éléments par page, débit.

      Un contrat qui omet ces cinq points produit des surprises, et chaque surprise se négocie au pire moment : à la mise en production d'un client.

      La forme d'erreur, décidée une fois

      Le format d'erreur est la partie la plus souvent improvisée, et la plus coûteuse. Il faut un format unique, valable pour toutes les routes, avec au minimum : un code stable que le client peut tester, un message destiné à être lu par un humain, et des champs de détail par valeur invalide. Le code d'erreur ne doit jamais être une phrase traduite : les clients testent sur le code, et un message d'erreur destiné aux utilisateurs finira par changer de formulation, ce qui cassera le client.

      La description machine de l'API

      Une spécification en OpenAPI décrit les routes, les paramètres, les types et les réponses dans un document structuré. Trois bénéfices concrets, dans cet ordre : un test qui vérifie que l'implémentation respecte la spécification, une documentation générée donc jamais périmée, et la possibilité d'un client généré automatiquement. Le dernier est le moins intéressant en soi — un client généré reste un client qu'on écrit.

    2. Modeler les ressources, et non les actions

      La manière dont on nomme et découpe les ressources détermine l'evolution future de l'API. Une mauvaise structure de ressources ne se corrige pas sans casser les clients.

      L'erreur à ne pas commettre

      Une API qui expose POST /creerClient, POST /modifierClient, POST /supprimerClient n'expose pas des ressources : elle expose un RPC sur HTTP. Elle fonctionnera, et elle empêchera toute évolution, parce que chaque nouvelle opération imposera une nouvelle route ad hoc.

      La forme correcte expose des ressources — ici des clients — et laisse la méthode HTTP exprimer l'action. Ce changement n'est pas cosmétique : il est la différence entre une API qui évolue et une API qui s'épuise.

      Les Sept de REST, et leur usage réel

      • ressources nommées au pluriel : l'identifiant est dans le chemin ou dans la requête, jamais dans le corps d'un POST ;
      • sans état : chaque requête porte ce qu'elle doit savoir. C'est ce qui permet de passer d'un serveur à trois sans changer le client ;
      • un identifiant par ressource : un identifiant lisible n'est pas une mesure de sécurité, seulement de commodité ;
      • un code de statut par situation, pas un 200 accompagné d'un message d'erreur dans le corps ;
      • le bon contrat : en pratique, un schéma déclaré et vérifié ;
      • un seul point d'entrée pour une ressource, donc pas de GET et un POST qui font la même chose ;
      • les liens d'état : la documentation et les transitions d'état explicites, parce qu'un client ne devine pas ce qu'il peut faire ensuite.

      Ce sont des principes de conception, pas une checklist à cocher ligne par ligne. Une API peut tranquillement en violer trois et rester parfaitement exploitable ; l'erreur est de les violer par accident, sans savoir pourquoi.

    3. Codes de statut et gestion d'erreur

      Les codes de statut sont la partie du contrat la plus sous-estimée. C'est pourtant le seul canal qui dise au client ce qu'il doit faire, sans qu'il ait à deviner.

      Le minimum à distinguer

      CodeSituationCe que fait un bon client
      400demande invalidecorriger, ne pas réessayer à l'identique
      401non authentifiéobtenir un jeton, réessayer une fois
      403authentifié mais interditne pas réessayer, avertir l'utilisateur
      404ressource absentene pas réessayer
      409conflit d'étatrelire l'état, résoudre, réessayer
      429débit dépasséattendre et réessayer, en respectant l'en-tête de délai
      500erreur serveurréessayer avec temporisation croissante

      401 et 403 se confondent très souvent, et le client ne peut pas les traiter de la même façon. Un 401 doit déclencher une procédure de renouvellement de jeton ; un 403 ne le doit pas, et réessayer indéfiniment sur un 403 est exactement le comportement d'un client mal écrit. Le même raisonnement vaut pour 404 et 409.

      Ce qui n'est pas un code de statut

      Répondre 200 avec un corps {"erreur": "non autorisé"} est l'erreur la plus répandue des API internes. Elle rend l'API inexploitable pour tout client qui s'appuie sur le code — c'est-à-dire tous les clients générés, les bibliothèques de monitoring, les passerelles, et pour finir les humains.

  2. Sécurité d'API et données

    1. Authentification, autorisation et le défaut qui vient

      L'API a une surface d'attaque que le site n'a pas : elle est interrogeable par quiconque connaît son URL. Les contrôles du navigateur ne la protègent pas.

      Le contrôle d'accès par objet : l'erreur numéro un

      Le défaut le plus répandu des API n'est pas l'absence d'authentification, c'est l'absence de vérification de propriété. Un utilisateur authentifié demande /factures/1042 : le serveur vérifie qu'il est connecté, et lui renvoie la facture. Elle appartient à quelqu'un d'autre.

      Ce défaut figure en tête du Top 10 de la sécurité des API de l'OWASP, et il n'est détectable ni par un test de charge ni par une revue superficielle : il faut le chercher explicitement, en tentant d'accéder aux objets d'un autre utilisateur. La parade est une règle unique : toute requête qui porte un identifiant d'objet vérifie que l'appelant a le droit sur cet objet. Une vérification faite sur l'identifiant de la requête ne suffit pas.

      Les deux autres défauts du Top 10 des API

      • l'authentification des masseurs : identifiants par défaut, clés de test, mots de passe faibles, absence de limitation des tentatives. Sur une API, ce défaut est exploitable à distance par un robot ;
      • l'excès de données : renvoyer systématiquement l'objet complet au lieu du champ demandé expose des informations que le client n'a pas besoin de voir — et que l'appelant legitime n'aurait pas dû obtenir. Le principe du moindre privilège s'applique aussi à la forme de la réponse.

      Le troisième défaut est la validation des entrées : une API reçoit des données d'une source externe, et les valide côté serveur. La validation du côté client n'est pas une validation, c'est un confort d'affichage.

    2. Limites, pagination et gestion de la charge

      Une API publique sans limite est une API qui tombera, et son indisponibilité sera attribuée à la conception du service, pas à l'appelant.

      Les quatre limites à mettre en place

      1. le débit : nombre de requêtes par utilisateur et par période, avec une réponse explicite — pas un échec silencieux, mais un 429 et un en-tête indiquant quand réessayer ;
      2. la taille des requêtes : un corps posté doit avoir une taille maximale, appliquée avant tout traitement ;
      3. la profondeur des filtres : une recherche qui accepte un nombre libre de critères permet de générer des requêtes coûteuses par construction ;
      4. la pagination : une liste sans pagination est un appel qui ramène la table entière en mémoire. Deux modes : par numéro de page, simple mais instable quand la liste change ; par curseur, plus stable et le bon choix par défaut sur une liste qui bouge.

      La pagination par curseur, et sa vraie raison

      Sur une liste qui reçoit des écritures pendant que l'utilisateur parcourt les pages, la pagination par numéro produit un défaut silencieux : un élément inséré entre deux lectures décale toutes les pages suivantes, et l'utilisateur voit un enregistrement deux fois, ou n'en voit aucun. Le curseur n'a pas ce problème, parce qu'il décrit une position stable dans le flux et non un décalage.

      Les seuils : un coût, pas qu'un réglage

      Chaque limite doit être choisie, pas laissée par défaut. Le critère n'est pas « quelle valeur semble raisonnable » mais « quelle valeur l'infrastructure supporte-t-elle, et que se passe-t-il quand on la dépasse ? ». Une limite trop basse rend l'API inutilisable ; une limite trop haute la rend indisponible pour tous. Un seuil doit être un compromis assumé et documenté, pas une valeur posée au hasard pour faire taire une alerte.

    3. Idempotence, reprises et cohérence

      Réseaux non fiables signifie qu'une requête peut arriver au serveur et que la réponse peut se perdre. L'API doit alors pouvoir être rejouée sans créer d'effet de bord.

      Ce que garantit le protocole

      La méthode GET doit être idempotente : la répéter ne doit pas changer l'état du serveur. C'est aussi ce qui autorise le cache et la pré-chargement. En revanche, PUT et DELETE sont eux aussi idempotents par convention : répéter une suppression, c'est supprimer quelque chose qui n'existe déjà pas, ce qui doit réussir sans effet supplémentaire. POST n'est pas idempotent : c'est la seule méthode où répéter pose problème.

      La clé d'idempotence

      La parade pour POST est un identifiant fourni par l'appelant, que le serveur mémorise. Si la même clé arrive deux fois, la seconde requête renvoie le résultat de la première au lieu d'en créer un second. C'est ce qui rend une reprise après coup de perte de connexion possible sans créer de doublon — le défaut le plus signalé sur les systèmes de paiement et de commande.

      Le timeout est un choix de conception

      Un appel qui expire chez l'appelant a peut-être été exécuté côté serveur. Toute opération non idempotente crée donc une incertitude réelle. La conception doit la traiter explicitement : soit l'opération est idempotente par construction, soit elle est réversible, soit elle fournit un moyen de savoir si elle a abouti. Une conception qui ignore ce cas produit des doublons, pas des erreurs visibles.

  3. Tester une API et la mettre en service

    1. Tester une API : ce que les tests doivent couvrir

      Une API se teste plus facilement qu'une interface, parce que son comportement est entièrement décrit par ses entrées et ses sorties. Cela ne dispense pas de tester les cas que personne n'écrit.

      La pyramide appliquée à une API

      1. unitaire : la validation d'entrée, la logique métier, la construction de la réponse. Millisecondes, aucun serveur ;
      2. d'intégration : une vraie base, un vrai serveur d'application, la pile complète. C'est ici que naissent les défauts d'authentification et de sérialisation ;
      3. de contrat : la spécification exécutée comme un test. Un test de contrat échoue si l'implémentation s'écarte de la spécification, dans les deux sens — une route documentée mais absente compte autant qu'une route non documentée. C'est le seul moyen d'empêcher la spécification de périmer, et c'est la réponse au reproche classique « la documentation est fausse » ;
      4. de bout en bout : les parcours critiques, en nombre très réduit.

      Les cas que tout le monde oublie

      • l'objet d'un autre utilisateur : le test le plus important d'une API, et le plus rarement écrit. Il doit exister et échouer si la vérification d'accès a été retirée ;
      • les entrées hostiles : champ attendu mais absent, type inattendu, valeur aux limites, chaîne très longue, caractère non attendus ;
      • les trois états de toute dépendance : réponse lente, réponse en erreur, dépendance indisponible. Une API qui n'est testée que dans le cas nominal n'est pas testée ;
      • la répétition : la même requête rejouée, en particulier sur une création, doit produire le comportement documenté.
    2. Mise en service, observation et versionnement

      Une API publiée est un contrat qui vit : il faut la surveiller, la faire évoluer et savoir ce qu'elle fait réellement.

      Ce qu'il faut observer

      • le taux d'erreur par code de statut, par route et par version. Une hausse de 401 sur une seule route signale un problème de jeton, pas une panne générale ;
      • la latence au 95ᵉ et au 99ᵉ centile. La moyenne est inutile : une moyenne correcte avec un 99ᵉ centile à trente secondes donne l'impression que tout va bien jusqu'à la première plainte ;
      • le débit par client : il révèle les clients dont l'usage a changé, souvent avant tout le reste ;
      • le nombre de requêtes en erreur par cause, pas seulement en nombre. C'est le chiffre qui permet d'agir, contrairement au total.

      Faire évoluer sans casser

      Trois règles, dans cet ordre :

      1. ne jamais supprimer ni changer la forme d'un champ existant. Ajouter est correct ; changer le sens d'un champ ne l'est pas, même si le nom reste le même — c'est la pire rupture possible, parce qu'elle est silencieuse ;
      2. versionner dans l'URL lorsque le changement est incompatible. Le numéro de version dans l'URL est moins élégant que dans un en-tête, et c'est le seul qui fonctionne partout, y compris dans un journal de serveur ou une URL de navigateur ;
      3. prévoir le retrait. Une version dépréciée doit avoir une date de fin communiquée. Une version annoncée « temporaire » sans date est définitive, et le client le découvre à la mauvaise heure.

      La documentation, conditionnée par l'usage

      Une documentation d'API publiée est un service : elle évolue, elle a des versions, et elle a des lecteurs pressés. Les trois erreurs habituelles sont de la documenter une fois à la livraison, d'en écrire trois pages là où une suffit, et d'omettre la section la plus utile de toutes — les exemples complets et exécutables, un par cas d'usage courant. Un exemple qui marche remplace un paragraphe entier.

    3. Projet final et évaluation

      Le projet

      Concevoir et implémenter l'API d'un service métier de son choix : spécification OpenAPI rédigée avant l'implémentation, authentification par jeton, contrôle d'accès par objet, pagination, limites de débit, idempotence sur la création, et suite de tests dont un test de contrat exécuté contre la spécification.

      Les huit critères d'évaluation

      1. la spécification précède le code, et le test de contrat s'exécute dans l'intégration continue ;
      2. le contrôle d'accès par objet est testé explicitement, et le test échoue si la vérification est retirée. C'est le critère numéro un ;
      3. les codes de statut distinguent 401 et 403, et aucun 200 ne porte une erreur dans son corps ;
      4. le format d'erreur est unique, avec un code stable et un détail par champ ;
      5. la pagination et les limites existent et renvoient un 429 exploitable quand le débit est dépassé ;
      6. la création est idempotente grâce à une clé fournie par l'appelant, et le comportement est testé par répétition ;
      7. les cas d'erreur sont testés : validation, dépendance indisponible, délai dépassé ;
      8. le découplage des états : la documentation le dit, les en-têtes le permettent, et le client n'a pas à deviner.

      Le critère qui départage

      Le jury retient ceci : l'API reste-t-elle utilisable par quelqu'un qui n'a jamais vu son code ? Test final à faire passer : donner la spécification à un collègue et lui demander de créer une ressource sans poser de question. Les questions qu'il pose sont exactement les zones d'ombre de l'API — et une API qui exige de poser des questions n'est pas terminée.

Sources et documentation de reference

Atelier guidé

Ecrire la specification avant le code, puis la faire executer comme un test.

  1. Contrat : rediger la specification OpenAPI, puis le test de contrat qui s’exécute dessus.
  2. Acces : tester l’acces a l’objet d’un autre compte, et verifier que le test echoue si la verification est retiree.
  3. Limites : pagination par curseur, et reponse 429 avec l’en-tete de delai quand le debit est depasse.
  4. Idempotence : creer avec une cle fournie par l’appelant, et rejouer la requete deux fois.

Restitution de l’atelier

  • La specification, et le test qui la verifie dans l’integration continue.
  • Le tableau des codes de statut, avec le code 200 sans erreur déguisée.
  • La note de versionnement : ce qu’on peut changer sans casser, et ce qu’on ne peut pas.
Validation : Un collegue jamais venu sur le projet cree une ressource depuis la specification, sans poser de question.

Publié le 29/09/2026