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.
// 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.
// 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.
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.
npm install cors morgan helmet
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).
// 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.
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;
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.
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;
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.
// 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.
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.
- Un middleware =
(req, res, next) => { ... }— appellenext()pour continuer la chaîne. express.json()etexpress.urlencoded()parsent le corps des requêtes →req.body.corsautorise les requêtes cross-origin,morganjournalise,helmetsé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.