Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

Chapitre 415 minIntermédiaire

Principes REST : ressources, URI et contraintes

Par Josselyn C., prof de BTS SIO. Mis à jour le .

À la fin de ce chapitre, tu sauras

  • énoncer les contraintes d'une architecture REST ;
  • situer une API sur le modèle de maturité de Richardson ;
  • nommer des URI de ressources selon les conventions ;
  • exposer une action métier qui n'est pas du CRUD.

3 exercices corrigés1 schéma

REST (Representational State Transfer) est un style d'architecture pour les applications en réseau : le serveur expose des ressources identifiées par des URI, et le client les manipule en échangeant des représentations (un document JSON, par exemple) avec les méthodes standard de HTTP. Une API qui respecte ses contraintes est dite RESTful. Ce chapitre présente les six contraintes de Roy Fielding, le modèle de maturité de Richardson, les règles pour nommer les URI et la façon de traiter les actions qui ne sont pas de simples lectures ou écritures.

Ressource et représentation

Une ressource est tout ce qui mérite un nom dans ton application : un visiteur, une fiche de frais, la liste des fiches d'octobre, un justificatif, et même un concept comme « le profil de l'utilisateur connecté ». Elle a une identité stable, son URI : /v1/fiches/12.

Une représentation est l'état de la ressource à un instant donné, dans un format donné. La fiche 12 peut être représentée en JSON pour le front, en PDF pour l'impression, en CSV pour un export comptable. Le client ne manipule jamais la ressource elle-même (une ligne de la base, un objet en mémoire) : il reçoit une représentation avec GET, et en envoie une pour la créer ou la modifier avec POST, PUT ou PATCH. D'où le nom : transfert d'état par représentation.

Les six contraintes de Fielding

Dans sa thèse de 2000, Roy Fielding définit REST par six contraintes. Une API qui les respecte toutes gagne en simplicité, en performance et en capacité à grandir.

ContrainteCe qu'elle imposeCe qu'elle apporte
Client-serveurL'interface (le client) est séparée du stockage et des traitements (le serveur)Chaque côté évolue seul ; plusieurs clients partagent le même serveur
Sans état (stateless)Chaque requête contient tout ce qu'il faut pour être comprise ; le serveur ne garde aucun contexte de session entre deux requêtesN'importe quel serveur traite n'importe quelle requête : on ajoute des serveurs quand la charge monte
Mise en cache (cacheable)Chaque réponse dit si elle peut être mise en cache, et combien de tempsMoins de requêtes, des réponses plus rapides
Interface uniformeToutes les ressources se manipulent de la même façon (voir ci-dessous)Un développeur qui connaît une API REST comprend vite les autres
Système en couchesLe client ne sait pas s'il parle au serveur final ou à un intermédiaire (reverse proxy, cache, passerelle d'API, répartiteur de charge)On ajoute de la sécurité, du cache ou de la répartition sans toucher au client
Code à la demande (facultative)Le serveur peut envoyer du code exécutable au client (du JavaScript)Rarement utilisée par les API

L'interface uniforme est la contrainte qui distingue REST des autres styles. Elle se décompose en quatre règles :

  1. Identification des ressources : chaque ressource a son URI.
  2. Manipulation par les représentations : le client modifie une ressource en envoyant une représentation (le JSON de la fiche), pas en appelant une fonction.
  3. Messages autodescriptifs : chaque message dit comment le lire (la méthode, le Content-Type, le code de statut), sans connaissance cachée.
  4. L'hypermédia comme moteur de l'état de l'application (HATEOAS, Hypermedia As The Engine Of Application State) : les réponses contiennent des liens vers les actions possibles, comme une page web contient des liens.

Le modèle de maturité de Richardson

Leonard Richardson a proposé une échelle en quatre niveaux pour situer une API par rapport à REST. Elle est pratique pour analyser une API existante.

NiveauCe que fait l'APIExemple
0 : le tunnel HTTPUne seule URI, une seule méthode (POST) ; l'action est écrite dans le corpsPOST /service avec {"action":"lireFiche","id":12}
1 : les ressourcesUne URI par ressource, mais toujours la même méthodePOST /fiches/12/lire, POST /fiches/12/supprimer
2 : les méthodes HTTPLes ressources et les méthodes et codes de statut de HTTPGET /fiches/12 → 200 ; DELETE /fiches/12 → 204
3 : les contrôles hypermédiaLe niveau 2, plus des liens dans les réponses (HATEOAS)La fiche renvoie un lien cloturer tant qu'elle est en cours de saisie

La grande majorité des API professionnelles sont au niveau 2. C'est la cible de ton projet de BTS : des ressources bien nommées, les bonnes méthodes, les bons codes de statut.

Voici à quoi ressemble une réponse de niveau 3 : le serveur annonce les actions permises dans l'état actuel de la fiche, et le client n'a pas à coder la règle « on ne clôture qu'une fiche en cours ».

json
{
  "id": 12,
  "mois": "2026-10",
  "etat": "CR",
  "_links": {
    "self": { "href": "/v1/fiches/12" },
    "lignes-forfait": { "href": "/v1/fiches/12/lignes-forfait" },
    "cloturer": { "href": "/v1/fiches/12", "method": "PATCH" }
  }
}

Nommer les URI

Une URI bien choisie se lit comme une phrase et ne change jamais. Les conventions suivantes ne sont pas imposées par une norme, mais tu les retrouveras dans presque toutes les API sérieuses.

  1. Des noms, pas des verbes. Le verbe, c'est la méthode HTTP. On écrit DELETE /v1/fiches/12, pas GET /v1/supprimerFiche?id=12.
  2. Des noms au pluriel pour les collections, suivis de l'identifiant pour un élément : /v1/fiches et /v1/fiches/12. Reste cohérent dans toute l'API.
  3. Des minuscules et des tirets pour séparer les mots : /v1/frais-hors-forfait, pas /v1/FraisHorsForfait ni /v1/frais_hors_forfait. Le chemin d'une URL est sensible à la casse.
  4. La hiérarchie pour les relations de composition, sur deux niveaux au plus : /v1/fiches/12/frais-hors-forfait (les frais de la fiche 12). Au-delà, l'URI devient fragile et longue.
  5. La chaîne de requête pour filtrer, trier et paginer, pas le chemin : /v1/fiches?etat=CL&mois=2026-10, pas /v1/fiches/cloturees/octobre.
  6. Pas d'extension de fichier ni de détail technique : pas de .php, .json, ni de nom de table. Le format se négocie avec Accept, et l'implémentation peut changer.
  7. Pas de barre oblique finale : /v1/fiches, pas /v1/fiches/. Choisis une forme et redirige ou refuse l'autre.
  8. Des identifiants stables et non devinables si possible : l'identifiant d'une ressource ne doit pas changer, et un UUID (/v1/justificatifs/3f1c9a2e-…) ne permet pas de deviner les ressources voisines comme un entier qui s'incrémente. Ce n'est pas une protection suffisante, mais une défense complémentaire.
À éviterPourquoiÀ écrire
GET /v1/getFichesVerbe dans l'URIGET /v1/fiches
POST /v1/fiches/creerVerbe ; POST sur la collection suffitPOST /v1/fiches
GET /v1/fiche/12 puis GET /v1/fichesSingulier et pluriel mélangésGET /v1/fiches/12
GET /v1/fiches.php?id=12Extension et technologie exposéesGET /v1/fiches/12
GET /v1/Visiteurs/7/FichesFraisMajuscules, casse incohérenteGET /v1/visiteurs/7/fiches
GET /v1/fiches/etat/CL/mois/2026-10Des filtres déguisés en hiérarchieGET /v1/fiches?etat=CL&mois=2026-10
GET /v1/visiteurs/7/fiches/12/frais-hors-forfait/58/justificatifHiérarchie trop profondeGET /v1/frais-hors-forfait/58/justificatif

Collection et élément : le tableau CRUD

Chaque ressource s'expose en général sous deux formes : la collection (/v1/fiches) et l'élément (/v1/fiches/12). Les opérations CRUD (Create, Read, Update, Delete) se répartissent ainsi :

OpérationMéthode et URICode de succèsSQL équivalent
Lister (avec filtres)GET /v1/fiches?etat=CL200SELECT … WHERE etat = 'CL'
Lire un élémentGET /v1/fiches/12200SELECT … WHERE id = 12
CréerPOST /v1/fiches201 + LocationINSERT
RemplacerPUT /v1/fiches/12200 ou 204UPDATE de toutes les colonnes
Modifier en partiePATCH /v1/fiches/12200 ou 204UPDATE de quelques colonnes
SupprimerDELETE /v1/fiches/12204DELETE

Les méthodes qui n'ont pas de sens sur une URI renvoient 405 : on ne fait ni PUT ni DELETE sur toute la collection /v1/fiches, ni POST sur un élément /v1/fiches/12 (sauf si l'élément contient lui-même une collection).

Les ressources d'AppliFrais

Partons du besoin. Un visiteur crée une fiche par mois, y saisit des frais forfaitisés (étapes, kilomètres, nuitées, repas) et des frais hors forfait avec leur justificatif, puis la clôture. Un comptable consulte les fiches clôturées, les valide et les met en paiement. Les ressources qui en découlent :

/v1/visiteursGET, POST/{id}GET, PATCH, DELETE/moiGET, PATCH/fichesGET, POST/{id}GET, PATCH, DELETE/lignes-forfaitGET, PUT/frais-hors-forfaitGET, POST/frais-hors-forfait/{id}GET, PATCH, DELETE/justificatifGET, PUT, DELETEcollectionélément ou sous-ressourceméthodes permises
Les ressources d'AppliFrais : des collections, des éléments, deux niveaux de hiérarchie au plus
RessourceURIMéthodes
Visiteurs (gérés par l'administrateur)/v1/visiteurs, /v1/visiteurs/{id}GET, POST ; GET, PATCH, DELETE
Profil de l'utilisateur connecté/v1/moiGET, PATCH
Fiches de frais/v1/fiches, /v1/fiches/{id}GET, POST ; GET, PATCH, DELETE
Frais forfaitisés d'une fiche/v1/fiches/{id}/lignes-forfaitGET, PUT (on remplace les quatre quantités d'un coup)
Frais hors forfait d'une fiche/v1/fiches/{id}/frais-hors-forfaitGET, POST
Un frais hors forfait/v1/frais-hors-forfait/{id}GET, PATCH, DELETE
Justificatif d'un frais/v1/frais-hors-forfait/{id}/justificatifGET, PUT, DELETE

Remarque le choix pour les frais hors forfait : on les crée sous leur fiche (POST /v1/fiches/12/frais-hors-forfait, la relation est claire), mais on les manipule ensuite par leur propre URI, plus courte. Les deux formes coexistent souvent.

Les actions qui ne sont pas du CRUD

Clôturer une fiche, la valider, la mettre en paiement : ce ne sont ni des créations, ni des suppressions. Trois façons de les exposer, de la plus « REST » à la plus pragmatique.

Modifier un attribut d'état. La clôture est un changement de l'attribut etat :

http
PATCH /v1/fiches/12 HTTP/1.1
Content-Type: application/json

{"etat":"CL"}

L'API vérifie que la transition est permise (CR vers CL, CL vers VA, VA vers MP) et renvoie 409 sinon. C'est simple, mais une seule route porte des règles de droits différentes selon la valeur envoyée : le visiteur peut clôturer, seul le comptable peut valider.

Créer une ressource qui représente l'action. Une validation est un événement qui a une date, un auteur, un montant validé : elle mérite d'être une ressource.

http
POST /v1/fiches/12/validations HTTP/1.1
Content-Type: application/json

{"montantValide": 389.20, "commentaire": "Repas du 14 refusé : justificatif illisible"}

L'API crée la validation (201), passe la fiche à l'état VA et garde une trace de qui a validé quoi. Les droits sont simples à poser : seuls les comptables peuvent faire POST sur /validations.

Une sous-ressource d'action, avec un verbe. POST /v1/fiches/12/cloture. Ce n'est pas pur, mais c'est lisible, et de nombreuses API publiques le font (GitHub, Stripe). Si tu choisis cette forme, garde POST et réserve-la aux vraies actions métier.

REST face au style RPC

Le style RPC (Remote Procedure Call, appel de procédure distante) expose des fonctions plutôt que des ressources : POST /lireFiche, POST /validerFiche. SOAP, gRPC et JSON-RPC en sont des exemples. Ce n'est pas une erreur en soi : gRPC est un excellent choix entre microservices (chapitre 12). Mais une API qui mélange les deux styles sans le dire est déroutante.

Style RESTStyle RPC
Ce qu'on exposeDes ressources (des noms)Des procédures (des verbes)
L'actionDans la méthode HTTPDans le nom de la procédure
Les erreursDans le code de statut HTTPSouvent dans le corps, avec un 200
Le cache HTTPFonctionne naturellement sur les GETInutilisable si tout passe par POST
ExempleGET /v1/fiches/12POST /rpc avec {"method":"lireFiche","params":{"id":12}}

Exercices

Exercice 1 sur 3 Corriger des URI Réussi À revoir

Réécris chaque route dans le style REST (méthode et URI), en conservant le sens.

  1. GET /api/getAllVisiteurs
  2. POST /api/visiteur/delete?id=7
  3. GET /api/fiches/visiteur/7/mois/2026-10
  4. POST /api/updateFiche.php avec {"id":12,"etat":"CL"}
  5. GET /api/Fiches/12/LignesForfait
  6. GET /api/rechercherFiches?montantMin=500
Voir la réponseMasquer la réponse de l'exercice 1
  1. GET /v1/visiteurs
  2. DELETE /v1/visiteurs/7
  3. GET /v1/fiches?visiteur=7&mois=2026-10 : le visiteur et le mois sont des filtres. GET /v1/visiteurs/7/fiches?mois=2026-10 est aussi acceptable.
  4. PATCH /v1/fiches/12 avec {"etat":"CL"}
  5. GET /v1/fiches/12/lignes-forfait
  6. GET /v1/fiches?montantMin=500 : une recherche est une lecture filtrée de la collection.

Tu avais trouvé ?

Exercice 2 sur 3 Situer une API sur l'échelle de Richardson Réussi À revoir

Donne le niveau de maturité de chaque API et justifie.

  1. Toutes les requêtes passent par POST /api.php avec un champ "action" dans le corps ; la réponse est toujours 200, avec un champ "succes": true ou false.
  2. L'API expose /clients, /clients/5, /commandes ; tout se fait en GET (y compris GET /clients/5/supprimer).
  3. L'API utilise GET, POST, PATCH et DELETE sur des ressources, et renvoie 201, 404, 409 à bon escient.
  4. Comme la 3, et chaque commande renvoie des liens annuler ou payer selon son état.
Voir la réponseMasquer la réponse de l'exercice 2
  1. Niveau 0 : une seule URI, une seule méthode, les erreurs cachées dans le corps.
  2. Niveau 1 : des ressources identifiées, mais pas les méthodes HTTP. Et GET /clients/5/supprimer est dangereux, car GET doit être sûr : un robot qui suit le lien supprime le client.
  3. Niveau 2 : ressources, méthodes et codes de statut. C'est le niveau visé par la plupart des API.
  4. Niveau 3 : les contrôles hypermédia (HATEOAS) guident le client.

Tu avais trouvé ?

Exercice 3 sur 3 Concevoir les ressources d'un cas Réussi À revoir

La médiathèque d'une commune veut une API pour son application mobile. Un adhérent consulte le catalogue (livres, DVD), réserve un document, voit ses prêts en cours et prolonge un prêt une fois. Un bibliothécaire enregistre les prêts et les retours.

  1. Liste les ressources et leurs URI.
  2. Donne la méthode et l'URI pour : chercher les documents dont le titre contient « Dune » ; réserver le document 314 ; voir mes prêts en cours ; prolonger le prêt 88 ; enregistrer le retour du prêt 88.
  3. Quel code renvoyer si l'adhérent prolonge une deuxième fois le même prêt ?
Voir la réponseMasquer la réponse de l'exercice 3
  1. /v1/documents et /v1/documents/{id} (le catalogue) ; /v1/adherents/{id} ou /v1/moi (le profil) ; /v1/reservations et /v1/reservations/{id} ; /v1/prets et /v1/prets/{id}.
  2. Une proposition :
    • recherche : GET /v1/documents?titre=Dune
    • réservation : POST /v1/reservations avec {"documentId":314} (l'adhérent est celui du jeton)
    • prêts en cours : GET /v1/moi/prets?statut=en-cours, ou GET /v1/prets?statut=en-cours, l'API ne renvoyant que les prêts de l'adhérent connecté
    • prolongation : POST /v1/prets/88/prolongations (une ressource qui garde la trace), ou PATCH /v1/prets/88 avec la nouvelle date de retour
    • retour : PATCH /v1/prets/88 avec {"dateRetour":"2026-11-02"}, ou POST /v1/prets/88/retour, réservé au rôle bibliothécaire
  3. 409 Conflict : la demande est bien formée, mais contredit l'état du prêt (déjà prolongé une fois). Le corps de l'erreur explique la règle.

Tu avais trouvé ?

Chapitre terminé !

Fais les 3 exercices avant de passer à la suite : c'est en t'entraînant que tout se fixe.

chapitres
–
de série
–
du cours
–
Chapitre suivant : JSON, XML et CSV : les formats d'échange de donnéesRevoir le sommaire du cours