Premier serveur Express 5 : routes, requêtes et réponses

Première leçon du cours API avec Express, en accès libre : environ 15 minutes, 3 exercices et 3 questions de quiz. C'est la leçon de base du catalogue ; dans l'espace étudiant, elle est réécrite pour ton profil.

Objectifs

  • Créer une application Express 5 et définir des routes
  • Lire les paramètres de chemin, de requête et le corps d'une requête
  • Renvoyer des réponses JSON avec le bon code de statut

Application ExpressRoutageCodes de statut HTTP

Express est le framework web le plus utilisé de l’écosystème Node.js. Il s’appuie sur le module http et ajoute un routage lisible, des middlewares et des aides pratiques comme res.json. La version 5 est la version actuelle : c’est elle qu’installe npm install express.

Un serveur minimal

// src/server.js (projet en ES modules : "type": "module" dans package.json)
import express from "express";

const app = express();
app.use(express.json());           // analyse les corps JSON -> req.body

app.get("/health", (req, res) => {
  res.json({ status: "ok" });      // statut 200 par défaut, Content-Type JSON
});

const port = Number(process.env.PORT ?? 3000);
app.listen(port, () => console.log(`API sur http://localhost:${port}`));

Lancez avec node --watch src/server.js et testez avec curl http://localhost:3000/health.

Lire la requête

const notes = [{ id: 1, titre: "Courses", fait: false }];

// Paramètre de chemin : /notes/42 -> req.params.id === "42" (une CHAÎNE)
app.get("/notes/:id", (req, res) => {
  const id = Number(req.params.id);
  const note = notes.find((n) => n.id === id);
  if (!note) return res.status(404).json({ error: "Note introuvable" });
  res.json(note);
});

// Chaîne de requête : /notes?fait=true -> req.query.fait === "true"
app.get("/notes", (req, res) => {
  const { fait } = req.query;
  const resultat = fait === undefined ? notes : notes.filter((n) => String(n.fait) === fait);
  res.json(resultat);
});

// Corps JSON : nécessite app.use(express.json())
app.post("/notes", (req, res) => {
  const note = { id: notes.length + 1, titre: req.body.titre, fait: false };
  notes.push(note);
  res.status(201).location(`/notes/${note.id}`).json(note);
});

Trois sources de données, trois objets : req.params, req.query, req.body. Toutes viennent du client : jamais fiables, toujours à valider (leçon 3).

Les codes de statut essentiels

Code Usage
200 OK Lecture ou modification réussie
201 Created Ressource créée (avec l’en-tête Location)
204 No Content Suppression réussie, pas de corps (res.status(204).end())
400 Bad Request Données invalides
401 / 403 Non authentifié / non autorisé
404 Not Found Ressource inexistante
500 Erreur du serveur

Chaque requête doit recevoir une seule réponse. Le return devant res.status(404)... évite d’en envoyer une seconde (erreur Cannot set headers after they are sent).

Regrouper avec express.Router

// src/routes/notes.js
import { Router } from "express";
export const notesRouter = Router();
notesRouter.get("/", listerNotes);
notesRouter.get("/:id", lireNote);
notesRouter.post("/", creerNote);

// src/server.js
app.use("/api/notes", notesRouter);   // GET /api/notes/3 -> lireNote

Ce qui change avec Express 5

  • Les erreurs des gestionnaires async sont transmises automatiquement au gestionnaire d’erreurs (leçon 4).
  • Les chemins sont plus stricts : un joker doit être nommé (/fichiers/*chemin), un segment optionnel s’écrit /livres{/:format}.
  • Sans express.json(), req.body vaut undefined (et non plus {}).
  • req.query est en lecture seule ; app.del() et res.sendfile() ont disparu.

À retenir

Une route = méthode + chemin + gestionnaire. Lisez params, query et body en les convertissant, répondez une seule fois avec le bon statut, et organisez les ressources avec Router.

Exercices

Les solutions et les tests restent sur le serveur. Dans l'espace étudiant, ton code est exécuté et corrigé, et le tuteur donne des indices avant la solution.

  1. CodeDifficulté 2JavaScript dans le navigateur2 indices

    Associer un chemin à un motif de route

    Pour comprendre le routage, écrivez matchRoute(pattern, path) : pattern est un chemin comme /notes/:id/commentaires/:cid. Renvoyez un objet des paramètres ({ id: "3", cid: "7" }) si path correspond, sinon null. Les segments sans : doivent être identiques ; le nombre de segments doit être le même ; les valeurs sont décodées avec decodeURIComponent. Ignorez la chaîne de requête éventuelle (?...).

    function matchRoute(pattern, path) {
      // À compléter
    }
  2. CodeDifficulté 1JavaScript dans le navigateur2 indices

    Gestionnaire de route GET /notes/:id

    Écrivez le gestionnaire getNote(req, res) utilisé ainsi : app.get("/notes/:id", getNote). Il cherche dans le tableau notes la note dont l’id (nombre) correspond à req.params.id (chaîne) :

    • trouvée : res.json(note) ;
    • id non entier : res.status(400).json({ error: "Identifiant invalide" }) ;
    • absente : res.status(404).json({ error: "Note introuvable" }).
    const notes = [
      { id: 1, titre: "Courses" },
      { id: 2, titre: "Réunion" },
    ];
    
    function getNote(req, res) {
      // À compléter
    }
  3. QCMDifficulté 11 indice

    Le bon code de statut

    Une requête POST /api/notes crée une note avec succès. Quel statut renvoyer ?

    • 200 OK
    • 201 Created
    • 204 No Content
    • 302 Found

Quiz de fin de leçon

  1. Où se trouve 42 dans GET /notes/42?tri=date avec la route /notes/:id ?

    • req.query.id
    • req.params.id
    • req.body.id
  2. Que vaut req.body dans Express 5 si aucun analyseur de corps n’est installé ?

    • {}
    • undefined
    • Une chaîne vide
  3. Comment écrire un joker de chemin en Express 5 ?

    • /fichiers/*
    • /fichiers/*chemin
    • /fichiers/(.*)

La suite du cours

  1. Les middlewares : la chaîne de traitement d'Express18 min
  2. Valider les données entrantes18 min
  3. Gérer les erreurs avec Express 515 min
  4. Structurer une API REST CRUD complète20 min

API avec Express · Intermédiaire · 3 h 26