Aller au contenu

Prise en main d'Express : trois exercices d'API

Ces trois exercices servent à prendre en main Express.js. pour la construction d’APIs. Chaque exercice ajoute une notion : d’abord les opérations de base, ensuite la validation des données reçues, enfin la mise à jour d’une ressource avec la question « qui a le droit de la modifier ».

Au terme de ces exercices, tu devrais pouvoir :

  1. Définir des routes Express pour les principaux verbes HTTP et répondre en JSON.
  2. Valider les données d’une requête et renvoyer des erreurs claires.
  3. Mettre à jour une ressource en tenant compte de son propriétaire.
  • Node.js installé (version 18 ou plus récente).
  • npm (fourni avec Node.js).
  • Un client HTTP pour envoyer des requêtes : Bruno ou Postman.

Crée un dossier de projet, puis installe Express :

Fenêtre de terminal
mkdir table-api
cd table-api
npm init -y
npm install express

Crée un fichier server.js avec un serveur minimal :

import express from 'express';
const app = express();
app.use(express.json()); // interprète le corps JSON des requêtes
app.get('/', (req, res) => {
res.json({ message: 'Le serveur répond.' });
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Serveur démarré sur http://localhost:${PORT}`);
});

Lance le serveur avec node server.js, puis envoie une requête GET http://localhost:3000/ depuis Bruno ou Postman. Tu devrais recevoir le message JSON.

Arborescence suggérée pour toute la page (un seul fichier suffit au début) :

table-api/
package.json
server.js

Ces termes reviennent dans les trois exercices.

  • Route (ou endpoint, point d’accès) : l’association d’un verbe HTTP et d’un chemin, par exemple GET /students. C’est l’adresse à laquelle le client s’adresse.
  • Verbe HTTP : l’action demandée. On utilise surtout GET (lire), POST (créer), PUT (remplacer), DELETE (supprimer).
  • Code de statut : un nombre à trois chiffres qui résume le résultat. Par exemple 200 (succès), 201 (créé), 400 (requête invalide), 404 (introuvable), 403 (interdit).
  • En mémoire (in-memory) : les données sont stockées dans une variable JavaScript. Elles disparaissent quand le serveur redémarre. C’est suffisant pour s’entraîner, sans base de données.

Objectif. Construire les quatre opérations de base sur une ressource.

Crée une API permettant de gérer une liste d’étudiants stockée en mémoire. Chaque étudiant possède un id (généré par le serveur), un nom et un courriel. Expose les cinq routes suivantes :

  • GET /students : renvoie la liste complète.
  • GET /students/:id : renvoie un étudiant, ou 404 s’il n’existe pas.
  • POST /students : ajoute un étudiant et renvoie l’objet créé avec le code 201.
  • PUT /students/:id : remplace nom et courriel, ou 404 s’il n’existe pas.
  • DELETE /students/:id : supprime l’étudiant, ou 404 s’il n’existe pas.

Étapes suggérées.

  1. Déclare la structure de données et un compteur d’identifiants :

    let students = [];
    let nextId = 1;
  2. Écris les routes une à une, en testant chacune dans ton client avant de passer à la suivante.

  3. Pour retrouver un étudiant, students.find(s => s.id === Number(req.params.id)). Le paramètre d’URL arrive sous forme de texte, d’où la conversion en nombre.

Vérification
  • POST /students avec { "nom": "Ada", "courriel": "ada@exemple.ca" } répond 201 et renvoie l’objet avec un id.
  • GET /students répond 200 et contient l’étudiant créé.
  • GET /students/1 répond 200 ; GET /students/999 répond 404.
  • PUT /students/1 avec de nouvelles valeurs répond 200 et les modifications sont visibles au prochain GET.
  • DELETE /students/1 répond 200 (ou 204) ; un second DELETE /students/1 répond 404.

Objectif. Refuser proprement les données invalides.

La Brasserie Pete organise des ateliers et veut recueillir les inscriptions. Une inscription comporte un nom, un courriel et une cohorte.

Expose une route POST /inscriptions qui n’enregistre l’inscription que si les données sont valides :

  • nom : présent et non vide.
  • courriel : présent et contenant un @.
  • cohorte : présente et faisant partie de la liste autorisée, par exemple ["matin", "soir"].

En cas d’erreur, réponds avec le code 400 et un corps qui décrit tous les problèmes rencontrés, pas seulement le premier :

{
"errors": [
{ "champ": "courriel", "message": "Le courriel doit contenir un @." },
{ "champ": "cohorte", "message": "La cohorte doit être matin ou soir." }
]
}

Si tout est valide, enregistre l’inscription en mémoire et réponds 201 avec l’objet créé.

Vérification
  • POST /inscriptions avec un objet complet et valide répond 201.
  • Un courriel sans @ fait répondre 400 avec une erreur sur le champ courriel.
  • Une cohorte absente ou hors liste fait répondre 400 avec une erreur sur le champ cohorte.
  • Une requête à la fois sans nom et sans courriel répond 400 avec deux erreurs.

Objectif. Mettre à jour une ressource en vérifiant qui en est l’auteur.

Crée une API qui gère une liste de commentaires en mémoire. Chaque commentaire a un id, un author (le nom de l’auteur) et un text. Expose :

  • GET /comments : renvoie tous les commentaires.
  • POST /comments : crée un commentaire à partir de { author, text }, répond 201.
  • PUT /comments/:id : remplace le text du commentaire, mais seulement si celui qui demande la modification est l’auteur.

Pour identifier le demandeur de façon simple, attends un champ author dans le corps de la requête PUT. Compare-le à l’auteur enregistré :

  • Commentaire introuvable : 404.
  • author du corps différent de l’auteur enregistré : 403 (interdit).
  • Sinon : remplace le texte et réponds 200.
Vérification
  • POST /comments avec { "author": "Ada", "text": "Bonne idée." } répond 201.
  • PUT /comments/1 avec { "author": "Ada", "text": "Excellente idée." } répond 200 et le texte est modifié au prochain GET.
  • PUT /comments/1 avec { "author": "Bob", "text": "..." } répond 403 et le texte reste inchangé.
  • PUT /comments/999 répond 404.

  1. Une route associe un verbe HTTP et un chemin ; la réponse porte toujours un code de statut, qui a autant de sens que le corps.
  2. Le CRUD couvre les quatre opérations de base et se traduit par les verbes GET, POST, PUT, DELETE.
  3. La validation se fait avant l’enregistrement et signale les refus par un code 4xx, idéalement en listant toutes les erreurs d’un coup.
  4. Distinguer 404 (la ressource n’existe pas) de 403 (elle existe, mais l’action n’est pas permise) aide le client à réagir correctement.
  5. Garder la logique (validation, recherche) dans des fonctions séparées des routes rend le code plus lisible et plus facile à faire évoluer, par exemple lorsqu’on passera à plusieurs services.