Cette page permet de vérifier ses acquis avant l’intra. Sur le plan du contenu, les deux pages les plus déterminantes sont Concevoir une API et Choisir une stratégie de persistance.
1. HTTP : sémantique et limites
- HTTP repose sur un modèle client-serveur. Il structure la communication entre un client et un serveur autour de requêtes envoyées par le client et de réponses retournées par le serveur.
- Le protocole est sans état : HTTP ne garde pas automatiquement le souvenir des échanges précédents. Chaque requête doit donc contenir les informations nécessaires à son traitement.
- Chaque méthode possède une sémantique convenue :
GETpour la lecture,POSTpour créer,PUTpour remplacer une ressource,PATCHmodifie partiellement une ressource,DELETEpour supprimer. - Le code de statut qualifie le résultat :
2xxsuccès (200,201,204),4xxerreur imputable au client (400,404,409),5xxdéfaillance du serveur,304ressource non modifiée. - Les en-têtes transportent les métadonnées de l’échange (type de contenu, authentification, cache), distinctes du corps de la requête ou de la réponse.
- L’URI identifie la ressource visée ; le couple méthode + URI exprime l’intention de l’opération.
Vérification« HTTP est sans état » : que signifie cette propriété, et quelle conséquence pratique en découle ?
Le serveur ne conserve aucun souvenir d’une requête à l’autre ; chaque requête doit porter le contexte nécessaire (identifiants, jeton). Il en résulte que n’importe quel serveur peut traiter n’importe quelle requête, ce qui facilite la mise à l’échelle ; en contrepartie, un mécanisme explicite (cookie, jeton) est requis pour reconnaître un utilisateur d’un appel à l’autre.
VérificationPOST /boites crée une boîte avec succès : quel statut retourner ? Et si le JSON est invalide ?
Création réussie → 201 Created (accompagné de la ressource créée ou d’un en-tête Location).
JSON invalide ou champ manquant → 400 Bad Request. Le statut 200 est à proscrire dans les deux cas :
il ne distingue pas une création d’une simple lecture et masque l’erreur.
VérificationPour ne modifier que le quartier d'une boîte, emploie-t-on PUT ou PATCH ? Et pour remplacer l'intégralité de sa représentation ?
PATCH /boites/12 convient à une modification partielle : seul le champ quartier est transmis, le reste est conservé.
PUT /boites/12 correspond à un remplacement intégral : tous les champs doivent être fournis, faute de quoi un champ omis serait perdu.
Le choix dépend donc de l’intention : retoucher un attribut ou réécrire la ressource.
VérificationGET /boites/9999 vise une boîte inexistante. Quel statut convient, et quelle réponse faut-il éviter ?
404 Not Found. La réponse à éviter est 200 OK accompagné d’un corps vide : elle simule un succès,
induit le client en erreur et peut altérer les caches. Le statut doit refléter la réalité : la ressource n’existe pas.
2. Augmenter HTTP
- Dans sa forme élémentaire, HTTP ne couvre pas tous les besoins applicatifs ; on l’augmente par des mécanismes complémentaires, sans le remplacer.
- Gestion de session : sur un protocole sans état, l’identité de l’utilisateur est rétablie à chaque requête au moyen d’un témoin (cookie) ou d’un jeton.
- Jeton signé (JWT) : un jeton autoporteur contient l’identité et ses attributs, assortis d’une signature que le serveur vérifie ; l’authentification demeure ainsi sans état.
- Ces extensions enrichissent le protocole tout en préservant ses propriétés fondamentales.
VérificationSur un protocole sans état, comment reconnaître qu'un utilisateur est connecté d'une requête à l'autre ?
Le client renvoie un cookie ou un jeton à chaque requête ; le serveur l’examine pour identifier l’utilisateur.
VérificationQu'est-ce qu'un JWT, et comment permet-il une authentification sans état ?
Un JWT (JSON Web Token) est un jeton signé contenant des informations (claims) : identité de l’utilisateur, droits, échéance.
Le serveur l’émet lors de la connexion ; le client le renvoie ensuite à chaque requête (généralement dans l’en-tête Authorization: Bearer …).
Le serveur en vérifie la signature à l’aide de sa clé : si elle est valide, il se fie au contenu, sans conserver d’état de session.
3. REST : contraintes et conséquences
- REST est un style architectural défini par un ensemble de contraintes, et non par le simple emploi d’un verbe HTTP.
- Les contraintes principales sont : architecture client-serveur, communication sans état, réponses cacheables, interface uniforme et organisation en couches.
- L’interface uniforme repose sur des ressources identifiées par une URI (des noms), manipulées au moyen des verbes standards et échangées sous forme de représentations (typiquement JSON).
- L’action s’exprime par la méthode, jamais dans le chemin de l’URI :
DELETE /boites/12, et non/boites/supprimer/12. - Le paramètre de route (
/boites/:id) identifie une ressource précise ; le paramètre de requête (/boites?quartier=Plateau) exprime un critère de filtrage, de tri ou de pagination sur une collection.
VérificationPourquoi DELETE /boites/12 plutôt que GET /boites/supprimer/12 ?
DELETE /boites/12 nomme la ressource et signifie sa suppression. GET /boites/supprimer/12 place l’action dans le chemin et
recourt à GET.
VérificationSoit les routes GET /getBoites, POST /boites/42/modifier et GET /boites/supprimer/42. Quelle en est la version RESTful ?
GET /boites (lister), PATCH /boites/42 ou PUT /boites/42 (modifier) et DELETE /boites/42 (supprimer).
Une ressource identifiée par son URI, des verbes standards portant l’intention, et aucune action dans le chemin :
« getBoites », « modifier » et « supprimer » disparaissent.
VérificationLire une boîte précise, puis filtrer les boîtes d'un quartier : paramètre de route ou de requête pour chacun ?
Boîte précise → paramètre de route : /boites/:id identifie une ressource.
Filtre par quartier → paramètre de requête : /boites?quartier=Plateau exprime un critère sur la collection.
En règle générale, la route désigne quelle ressource, la requête précise comment filtrer, trier ou paginer.
VérificationQu'est-ce qui distingue une API « qui parle HTTP » d'une API véritablement RESTful ?
« Parler HTTP » revient à employer le transport (POST, GET) sans respecter les contraintes :
action dans l’URI, verbe unique pour toute opération, absence de véritables ressources (par exemple POST /api?action=create).
Une API RESTful repose sur des ressources identifiées par URI, une interface uniforme (verbes standards, statuts appropriés, représentations),
le caractère sans état et la possibilité de mise en cache (par exemple POST /boites, GET /boites/12).
La distinction tient au respect des contraintes, non à l’usage de HTTP.
4. Conception d’API
- Concevoir une API commence par les questions auxquelles elle doit répondre, puis par les ressources du domaine (des noms) et leurs attributs.
- Chaque ressource s’expose comme une collection (
/boites) et des éléments (/boites/:id), manipulés par les verbes standards. - Une relation se traduit, lorsque c’est naturel, par un chemin imbriqué (
/boites/:id/emprunts), sans empiler les niveaux à l’excès. - Chaque opération a un code de statut attendu, en succès comme en erreur (création
201, ressource absente404, données invalides400). - Une bonne API est prévisible et cohérente : mêmes conventions de nommage, de pluriel et de format d’un endpoint à l’autre.
- Concevoir, c’est raconter une histoire lisible : à la seule lecture des endpoints, on devine le domaine et les usages.
VérificationPar quoi commence la conception d'une API, avant d'écrire le moindre endpoint ?
Par les questions auxquelles l’API doit répondre, puis par les ressources du domaine (les noms : station, boîte, mesure) et leurs attributs. Les endpoints en découlent : ils donnent accès à ces ressources. Partir des endpoints sans avoir nommé les ressources mène à une API d’actions hétéroclites plutôt qu’à un modèle cohérent.
VérificationL'API Lino doit lister les boîtes d'un quartier, consulter une boîte précise, et consulter les emprunts d'une boîte. Proposez les endpoints.
GET /boites?quartier=Plateau (collection filtrée), GET /boites/:id (un élément précis) et GET /boites/:id/emprunts (la relation, en chemin imbriqué). Verbes standards, filtre exprimé en paramètre de requête, relation rendue par l’imbrication du chemin.
VérificationPour exposer un historique d'emprunts potentiellement très long, comment concevoir l'endpoint afin qu'il reste utilisable ?
GET /boites/:id/emprunts avec pagination et filtres en paramètres de requête (?depuis=2026-05-01&page=2&taille=50), au lieu de renvoyer tout l’historique d’un coup. On borne la taille de la réponse et on laisse le client demander la suite, ce qui protège le serveur comme le client d’une réponse démesurée.
VérificationConcevez le flux d'échanges pour ce scénario : Alice repère une boîte de son quartier, consulte les livres qui y sont disponibles, puis en emprunte un.
Une séquence d’échanges requête-réponse, du repérage vers l’écriture :
GET /boites?quartier=Rosemontrépond200avec les boîtes du quartier.GET /boites/12/livres?disponible=truerépond200avec les livres disponibles de la boîte choisie.POST /boites/12/emprunts(corps :{ "livre_id": 87 }) répond201 Createdavec l’emprunt enregistré. Chaque étape est un échange complet et autosuffisant : HTTP étant sans état, la requête d’emprunt porte elle-même les identifiants nécessaires, sans dépendre d’un état conservé entre les appels. Le flux progresse des lectures (GET) vers la création (POST), et chaque réponse fournit au client de quoi décider de l’étape suivante.
5. Stratégies de persistance
- La persistance répond à une question : où et comment conserver les données au-delà d’une seule requête, sur un protocole qui, lui, ne retient rien.
- Les données peuvent reposer sur plusieurs cibles complémentaires : le client, la mémoire du serveur, une base de données, un cache.
- Côté client (cookie, jeton, stockage du navigateur ou de l’application) : identité, préférences, fonctionnement hors-ligne; jamais de donnée sensible en clair.
- Mémoire du serveur : accès rapide, mais volatile et local à un processus; adaptée à un état temporaire et non critique.
- Base de données : durable, partagée entre serveurs et interrogeable, au prix d’une latence.
- Cache : conserve les résultats fréquemment lus afin de répondre sans solliciter la BD à chaque fois.
- Le choix d’une cible se justifie par les accès attendus : durabilité, fréquence des lectures et des écritures, évolution du volume.
VérificationUn serveur conserve ses boîtes dans un tableau en mémoire ; après un redémarrage, tout a disparu. Que faut-il changer, et quelle en est la conséquence sur le code ?
Il convient d’adopter une base de données pour la durabilité (et le partage entre serveurs). La mémoire reste appropriée pour un état temporaire ou non critique.
VérificationLa préférence de thème d'un utilisateur, et l'inventaire des boîtes interrogeable par quartier : sur quelle cible conserver chacun ?
Préférence de thème → côté client (cookie ou stockage du navigateur) : donnée propre à l’utilisateur, non critique, qui n’a pas à transiter par le serveur. Inventaire des boîtes → base de données : donnée durable, partagée et interrogeable (filtrer par quartier, trier, paginer). Le critère décisif est l’usage : préférence locale et jetable d’un côté, donnée de référence interrogeable de l’autre.
VérificationImbrication ou référence : quel est le compromis, en une phrase ?
L’imbrication permet une lecture en un seul accès, mais entraîne duplication possible et croissance du document. La référence évite la duplication et préserve l’indépendance des entités, mais la lecture des données liées exige une jointure. Le choix dépend du mode de lecture : données lues ensemble → imbrication ; données lues séparément ou de volume illimité → référence.
6. Express.js : mécanique d’une API
- Express achemine les requêtes vers des gestionnaires associés à une méthode et à un chemin (
app.get,app.post, etc.). express.json()est un middleware qui analyse le corps JSON entrant et alimentereq.body; en son absence,req.bodydemeure indéfini.- Les paramètres de route se lisent dans
req.params(segments tels que:id), les paramètres de requête dansreq.query(après le?), et le corps dansreq.body. - La réponse se construit avec
res.status(code).json(...)oures.send(...); le statut par défaut est200et doit être ajusté explicitement (201,404, etc.). - Pour supporter un accès à la BD asynchrone, le gestionnaire emploie
async/awaitet traite explicitement l’absence de résultat ainsi que les erreurs.
VérificationLa route app.get('/stations/:id') reçoit /stations/12?detail=complet. Comment lire 12 puis complet ?
req.params.id vaut "12" (segment de route) et req.query.detail vaut "complet" (paramètre situé après le ?).
La route capture l’identité de la ressource ; la requête en précise les options.
VérificationUn gestionnaire POST observe req.body indéfini alors que le client transmet du JSON. Quelle est la cause probable, et le correctif ?
Sans app.use(express.json()), Express n’analyse pas le corps JSON, d’où un req.body indéfini.
Il convient également de vérifier que le client envoie l’en-tête Content-Type: application/json.
VérificationÉcrire la route qui renvoie une boîte par son identifiant, avec un 404 lorsqu'elle est absente.
app.get("/boites/:id", async (req, res) => {
const boite = await Boite.findById(req.params.id);
if (!boite) {
return res.status(404).json({ erreur: "Boîte introuvable" });
}
res.json(boite);
});La lecture en base de données est asynchrone (await) ; en l’absence de résultat, le gestionnaire répond explicitement 404 plutôt que de renvoyer null avec un statut 200.
VérificationPour une création réussie, puis pour une ressource absente, quels statuts retourner ?
Création réussie → res.status(201).json(cree). Ressource absente → res.status(404).json({ erreur: "..." }).
Express ne déduit pas le statut (il applique 200 par défaut) : il revient au gestionnaire de fixer le code approprié au résultat.