Skip to content

📅 SAISON B Semaine 2 Épisode 3 - Les Middlewares avec Express

📚 Notions du jour

Aujourd’hui, j’ai dĂ©couvert un concept central dans Express : les middlewares. Un middleware, c’est comme un ouvrier sur une chaĂźne de montage : il reçoit une requĂȘte, fait un travail spĂ©cifique (comme valider des donnĂ©es, logger une information, ou modifier la requĂȘte/rĂ©ponse), puis passe le relais au middleware suivant. Express est d’ailleurs conçu comme un moteur de middlewares : tout y est middleware, des routes aux gestionnaires d’erreurs ! C'est ce qu'on appel un design pattern.
Nous utilisions déjà sans le savoir des middlewares lors de notre apprentissage d'Express.

Pourquoi c’est puissant ?

  • ModularitĂ© : Chaque middleware a une responsabilitĂ© unique.
  • RĂ©utilisabilitĂ© : Un middleware peut ĂȘtre utilisĂ© sur plusieurs routes.
  • FlexibilitĂ© : Vous pouvez ajouter, retirer ou rĂ©organiser des middlewares sans tout casser.

🔗 Comment Fonctionnent les Middlewares ?

Un middleware est une fonction qui prend 3 paramĂštres :

  1. req : L’objet requĂȘte (informations sur la requĂȘte HTTP).
  2. res : L’objet rĂ©ponse (pour envoyer une rĂ©ponse au client).
  3. next : Une fonction callback pour passer au middleware suivant.

Syntaxe de base :

function myMiddleware(req, res, next) {
  // Something to do with req and/or res here
  console.log("Middleware executed!");
  next(); // Go to the next middleware
}

📌 Deux Façons d’Utiliser les Middlewares

1ïžâƒŁ Middleware SpĂ©cifique Ă  une Route (app.get, app.post, etc.)

Le middleware ne s’exĂ©cute que si l’URL correspond Ă  la route.

Exemple :

app.get('/about', (req, res, next) => {
  console.log("Someone accessed the About page!");
  next();
}, (req, res) => {
  res.send("About Page");
});

Explications :

  • Le premier argument de app.get est un middleware qui logge l’accĂšs Ă  /about.
  • Le deuxiĂšme argument est la fonction qui envoie la rĂ©ponse.

2ïžâƒŁ Middleware Global (app.use)

Le middleware s’exĂ©cute pour toutes les requĂȘtes, peu importe l’URL.

Exemple :

// Middleware that logs all request
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
});

Cas d’usage :

  • Logging (journalisation des requĂȘtes).
  • Authentification (vĂ©rifier si l’utilisateur est connectĂ©).

⚙ L’Ordre des Middlewares : Une Question Cruciale

L’ordre dans lequel on chaĂźne les middlewares est essentiel ! Express exĂ©cute les middlewares dans l’ordre oĂč ils sont dĂ©clarĂ©s. Si un middleware n’appelle pas next(), la chaĂźne s’arrĂȘte.

Exemple :

// Middleware 1 : Logs the request
app.use((req, res, next) => {
  console.log("Middleware 1");
  next();
});

// Finale route
app.get('/', (req, res) => {
  res.send("Welcome!");
});

đŸ› ïž Exemples Concrets de Middlewares

1ïžâƒŁ Middleware de Logging

Objectif : Logger toutes les requĂȘtes (mĂ©thode, URL, heure).

app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
});

2ïžâƒŁ Middleware pour Servir des Fichiers Statiques

Objectif : Servir les fichiers CSS, JS et images depuis un dossier public/.

app.use(express.static('public'));

💡 Ce Que J’ai Appris Aujourd’hui

  1. Tout est middleware dans Express : Les routes, les gestionnaires d’erreurs, mĂȘme express.static.
  2. L’ordre des middlewares est crucial : Un middleware qui n’appelle pas next() bloque la chaüne.
  3. Les middlewares permettent de :
  4. Logger les requĂȘtes.
  5. Valider les données (authentification, validation de formulaires).
  6. Modifier les requĂȘtes/rĂ©ponses.
  7. Gérer les erreurs de maniÚre centralisée.
  8. app.use() vs app.get() :
  9. app.use() : Middleware global (toutes les requĂȘtes).
  10. app.get() : Middleware spécifique à une route/méthode.

⌚ Challenge du jour : Challenge Middlewares pour la GhibliothĂšque – Gestion des 404 et Journalisation des Visites

đŸŽ€ PrĂ©sentation du Challenge

Aujourd’hui, nous allons amĂ©liorer notre GhibliothĂšque en ajoutant deux middlewares essentiels :

  1. Une gestion personnalisĂ©e des erreurs 404 pour afficher une page "not found" stylisĂ©e quand une route n’existe pas.
  2. Un systÚme de journalisation (logging) pour tracer les visites (date, IP, chemin accédé).

L’objectif Ă©tait de comprendre le fonctionnement des middlewares dans Express et de les utiliser pour amĂ©liorer l’expĂ©rience utilisateur et le dĂ©bogage.


📋 Étapes Ă  RĂ©aliser

1ïžâƒŁ Gestion des 404 PersonnalisĂ©e

Objectif : Afficher une page 404 personnalisĂ©e quand une route n’est pas trouvĂ©e.

đŸ‘šâ€đŸ’» Solution proposĂ©e

J’ai d’abord eu du mal Ă  comprendre comment capturer les erreurs 404 sans consulter la documentation (comme demandĂ© dans l’énoncĂ©). AprĂšs quelques essais, j’ai trouvĂ© une solution qui fonctionne, mais je ne suis pas sĂ»r qu’elle soit optimale. Je me suis dit que je pouvais crĂ©er un Middleware qui renvoie une erreur 404 par dĂ©faut si aucune route n'est trouvĂ©e. PlacĂ© aprĂšs le Middleware qui qui gĂšre les routes app.use(router);, si aucune route n'est trouvĂ©e quand l'utilisateur essaie d'accĂ©der Ă  une url qui n'existe pas, cela renvoie un statut 404 et rend la page personalisĂ©e 404 existante.

Mon code :

index.js
import express from 'express';
import { router } from './src/routers/index.router.js';

const app = express();

// Configuring static files and the template engine
app.use(express.static('public'));
app.set('view engine', 'ejs');
app.set('views', './src/views');

// Using the main router
app.use(router);

// Middleware to handle 404 errors (must be after all routes)
app.use((req, res, next) => {
  // If no route is found, return a 404 error
  res.status(404).render('404', { message: "Page non trouvée" });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

Réflexions aprÚs avoir lu la documentation :

AprĂšs avoir vĂ©rifiĂ© la documentation, il s'avĂšre que cette solution Ă©tait la bonne 😅. Je cherchais Ă  forcĂ©ment capturer une erreur afin de la renvoyer. Alors que la documentation prĂ©cise que ce n'est pas nĂ©cessaire : how to handle 404 responses.
👉 In Express, 404 responses are not the result of an error, so the error-handler middleware will not capture them. This behavior is because a 404 response simply indicates the absence of additional work to do; in other words, Express has executed all middleware functions and routes, and found that none of them responded. All you need to do is add a middleware function at the very bottom of the stack (below all other functions) to handle a 404 response.


2ïžâƒŁ Journalisation des Visites

Objectif : Logger (journaliser) chaque requĂȘte avec :

  • La date de la requĂȘte.
  • L’adresse IP du visiteur.
  • Le chemin accĂ©dĂ© (ex: /movies/1).

đŸ‘šâ€đŸ’» Solution proposĂ©e

J’ai explorĂ© l’objet req pour trouver les informations nĂ©cessaires. Voici comment j’ai implĂ©mentĂ© le middleware de logging :

Mon code :

request-logging.middleware.js in /src/middlewares/
export function requestLogging(req, res, next) {
  const timestamp = new Date().toISOString();
  const ipAddress = req.ip;
  const url = req.url;
  console.log(`${timestamp} ${ipAddress} ${url}`);
  next();
}

Import du middleware de logging dans index.js :

index.js
import express from 'express';
import { router } from './src/routers/index.router.js';
import { requestLogging } from './src/middlewares/request-logging.middleware.js';

const app = express();

// Configuring static files and the template engine
app.use(express.static('public'));
app.set('view engine', 'ejs');
app.set('views', './src/views');

// Using the logging middleware (must be before all routes)
app.use(requestLogging);

// Using the main router
app.use(router);

// Middleware to handle 404 errors (must be after all routes)
app.use((req, res, next) => {
  // If no route is found, return a 404 error
  res.status(404).render('404', { message: "Page non trouvée" });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

3ïžâƒŁ Bonus : Formatage ÉlĂ©gant des Logs

Objectif : AmĂ©liorer le format des logs pour qu’ils soient plus lisibles et exploitables.

đŸ‘šâ€đŸ’» Solution proposĂ©e

J’ai ajustĂ© le format des logs pour qu’ils suivent le format demandĂ© : [date-iso ip] path.

Mon code mis à jour : (Insérer ici ton bloc de code pour le formatage élégant des logs. Par exemple :)

request-logging.middleware.js in /src/middlewares/
export function requestLogging(req, res, next) {
  const timestamp = new Date().toISOString();
  const ipAddress = req.ip;
  const url = req.url;
  console.log(`[${timestamp} ${ipAddress}] ${url}`);
  next();
}

💡 Ce Que J’ai Appris avec ce Challenge

  1. Les middlewares sont le cƓur d’Express : Ils permettent d’ajouter des fonctionnalitĂ©s (logging, authentification, etc.) de maniĂšre modulaire.
  2. L’ordre des middlewares est crucial :
  3. Le middleware de logging doit ĂȘtre placĂ© avant les routes pour capturer toutes les requĂȘtes.
  4. Le middleware 404 doit ĂȘtre placĂ© aprĂšs toutes les routes pour ĂȘtre exĂ©cutĂ© en dernier recours.
  5. L’objet req contient Ă©normĂ©ment informations utiles :
  6. req.ip : Adresse IP du visiteur.
  7. req.url : URL de la requĂȘte.
  8. req.method : Méthode HTTP (GET, POST, etc.).
  9. Le formatage des logs est important :
  10. Un format clair ([date ip] path) permet de filtrer et analyser les logs facilement.