Leçon 6 / 8
Leçon 06 · Node.js

Routes et middlewares

Qu'est-ce qu'un middleware ?

Dans Express, tout passe par des middlewares. Un middleware est simplement une fonction qui reçoit la requête req, la réponse res, et une fonction next qui permet de passer au middleware suivant.

JavaScript
// Signature d'un middleware Express
const monMiddleware = (req, res, next) => {
  // 1. Faire quelque chose avec req ou res
  console.log('Requête reçue :', req.method, req.url);

  // 2. Passer au middleware suivant (ou répondre)
  next();
};

// Enregistrer le middleware dans l'application
app.use(monMiddleware);

Express traite les middlewares en pile : ils s'exécutent dans l'ordre où tu les déclares. Chaque middleware peut lire ou modifier la requête, envoyer une réponse, ou appeler next() pour continuer la chaîne. Si personne ne répond, la requête reste en attente.

JavaScript
// Pile de middlewares — exécutés dans l'ordre
app.use(middlewareA);  // 1er exécuté
app.use(middlewareB);  // 2ème
app.use(middlewareC);  // 3ème — peut envoyer la réponse finale

Middlewares intégrés Express

Express fournit plusieurs middlewares prêts à l'emploi. Les deux plus courants gèrent le corps (body) des requêtes entrantes.

JavaScript
const express = require('express');
const app = express();

// Parse les corps JSON : { "nom": "Alice" }
app.use(express.json());

// Parse les corps de formulaires HTML (application/x-www-form-urlencoded)
app.use(express.urlencoded({ extended: true }));

// Après ces middlewares, req.body est disponible dans toutes les routes
app.post('/utilisateurs', (req, res) => {
  console.log(req.body); // { nom: 'Alice', email: 'alice@ex.com' }
  res.json({ ok: true });
});

Middlewares tiers

L'écosystème npm regorge de middlewares Express. Voici les incontournables que tu rencontreras dans presque tous les projets Node.js.

bash
npm install cors morgan helmet
JavaScript
const cors    = require('cors');
const morgan  = require('morgan');
const helmet  = require('helmet');

// Ajoute des headers HTTP de sécurité (XSS, clickjacking…)
app.use(helmet());

// Autorise les requêtes cross-origin (depuis un navigateur sur un autre domaine)
app.use(cors());

// Journalise chaque requête dans le terminal (format 'dev' = colorisé)
// Exemple de sortie : GET /utilisateurs 200 4.321 ms
app.use(morgan('dev'));
💡

cors est indispensable dès que ton API est consommée depuis un navigateur sur un domaine différent (ex : frontend React sur localhost:3000 qui appelle l'API sur localhost:4000). Sans lui, le navigateur bloque la requête.

Middleware d'application, de routeur et de gestion d'erreurs

Express distingue trois portées pour les middlewares :

  • Middleware d'application — déclaré avec app.use(), s'applique à toutes les routes.
  • Middleware de routeur — déclaré avec router.use(), limité aux routes de ce routeur.
  • Middleware de gestion d'erreurs — signature spéciale à 4 paramètres (err, req, res, next).
JavaScript
// Middleware d'application — toutes les routes
app.use(morgan('dev'));

// Middleware de routeur — uniquement les routes /api/*
const apiRouter = express.Router();
apiRouter.use(verifierToken); // s'applique seulement ici
app.use('/api', apiRouter);

// Middleware de gestion d'erreurs — 4 paramètres obligatoires
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ erreur: err.message });
});

express.Router() — découper les routes par ressource

Quand ton application grandit, tout mettre dans app.js devient ingérable. express.Router() te permet de créer des mini-applications modulaires, une par ressource.

JavaScript — routes/utilisateurs.js
const express = require('express');
const router  = express.Router();

// GET /utilisateurs
router.get('/', (req, res) => {
  res.json([{ id: 1, nom: 'Alice' }]);
});

// GET /utilisateurs/:id
router.get('/:id', (req, res) => {
  res.json({ id: req.params.id, nom: 'Alice' });
});

// POST /utilisateurs
router.post('/', (req, res) => {
  const { nom, email } = req.body;
  res.status(201).json({ id: 2, nom, email });
});

module.exports = router;
JavaScript — app.js
const utilisateursRouter = require('./routes/utilisateurs');
const articlesRouter     = require('./routes/articles');

// Préfixes de routes — les chemins du routeur s'y ajoutent
app.use('/utilisateurs', utilisateursRouter);
app.use('/articles', articlesRouter);
// Résultat : GET /utilisateurs/, GET /utilisateurs/:id, POST /utilisateurs/
//            GET /articles/, GET /articles/:id, etc.

Middleware d'authentification simple

Un pattern courant : protéger certaines routes en vérifiant un header Authorization. Le middleware lit le token, valide, et appelle next() si tout va bien — ou renvoie une erreur 401 sinon.

JavaScript — middlewares/auth.js
const TOKEN_SECRET = 'mon-token-secret';

function verifierToken(req, res, next) {
  // Le header attendu : Authorization: Bearer <token>
  const authHeader = req.headers['authorization'];

  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ erreur: 'Token manquant' });
  }

  const token = authHeader.split(' ')[1];

  if (token !== TOKEN_SECRET) {
    return res.status(401).json({ erreur: 'Token invalide' });
  }

  // Token valide — on passe à la suite
  next();
}

module.exports = verifierToken;
JavaScript — utilisation
const verifierToken = require('./middlewares/auth');

// Protéger une route spécifique
app.get('/profil', verifierToken, (req, res) => {
  res.json({ message: 'Accès autorisé' });
});

// Protéger tout un routeur
apiRouter.use(verifierToken);
app.use('/api', apiRouter);
⚠️

Cet exemple utilise un token statique à titre pédagogique. En production, tu utiliseras des JWT (JSON Web Tokens) avec la librairie jsonwebtoken pour des tokens signés, expirables et infalsifiables.

Middleware de gestion d'erreurs

Le middleware de gestion d'erreurs a une signature à quatre paramètres : (err, req, res, next). Express le reconnaît automatiquement grâce à ce quatrième paramètre. Il doit être déclaré en dernier, après toutes les routes.

JavaScript
// Dans une route, propager une erreur avec next(err)
app.get('/donnees', async (req, res, next) => {
  try {
    const data = await recupererDonnees();
    res.json(data);
  } catch (err) {
    next(err); // Express route l'erreur vers le gestionnaire d'erreurs
  }
});

// Gestionnaire d'erreurs global — TOUJOURS en dernier
app.use((err, req, res, next) => {
  console.error('[Erreur]', err.message);

  const status = err.status || 500;
  res.status(status).json({
    erreur: err.message || 'Erreur interne du serveur'
  });
});

Ordre des middlewares — pourquoi l'ordre compte

Express exécute les middlewares dans l'ordre exact de leur déclaration. Une erreur d'ordre peut rendre un middleware inefficace ou bloquer toute l'application.

JavaScript — ordre recommandé
const app = express();

// 1. Sécurité et logging — en premier, avant tout
app.use(helmet());
app.use(morgan('dev'));

// 2. Parsing du corps — avant les routes qui lisent req.body
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 3. CORS — avant les routes
app.use(cors());

// 4. Routes de l'application
app.use('/utilisateurs', utilisateursRouter);
app.use('/articles', articlesRouter);

// 5. Route 404 — après toutes les routes
app.use((req, res) => {
  res.status(404).json({ erreur: 'Route introuvable' });
});

// 6. Gestionnaire d'erreurs — absolument en dernier
app.use((err, req, res, next) => {
  res.status(err.status || 500).json({ erreur: err.message });
});
💡

Si tu déclares express.json() après tes routes, req.body sera undefined dans toutes tes routes POST. C'est l'erreur la plus fréquente chez les débutants avec Express.

// À retenir
  • Un middleware = (req, res, next) => { ... } — appelle next() pour continuer la chaîne.
  • express.json() et express.urlencoded() parsent le corps des requêtes → req.body.
  • cors autorise les requêtes cross-origin, morgan journalise, helmet sécurise.
  • express.Router() découpe les routes par ressource dans des fichiers séparés.
  • Le gestionnaire d'erreurs a 4 paramètres (err, req, res, next) et doit être déclaré en dernier.
  • L'ordre des middlewares est crucial — express.json() avant les routes, erreurs après les routes.