Terminez d'abord "Leçon 2 : Mise en place d'un projet Node.js et Express" pour débloquer cette leçon.Aller à la leçon précédente

Introduction

À mesure que votre API se développe au-delà de quelques endpoints, tout regrouper dans un seul fichier devient vite ingérable. Express fournit un outil intégré appelé Router pour répartir les routes dans des modules séparés par ressource. Associez cela à une couche de contrôleurs et vous obtenez une structure qui évolue proprement — les nouveaux membres de l'équipe trouvent ce dont ils ont besoin, et l'ajout d'une nouvelle ressource ne touche pas au code existant.

Cette leçon parcourt une disposition de projet concrète : les routes définissent les patterns d'URL et les verbes HTTP, les contrôleurs contiennent la logique métier, et app.js les assemble. Cette séparation est l'habitude la plus importante à construire dès le départ.

schéma d'architecture en couches montrant la Requête qui circule vers app.js, puis la couche Router, puis la couche Controller, puis une couche Data (espace réservé)

Structure du Projet

Voici l'arborescence de répertoires vers laquelle nous allons construire :

text
project/
├── app.js
├── routes/
│ ├── users.js
│ └── products.js
└── controllers/
├── usersController.js
└── productsController.js

Le pattern est simple : un fichier de routes par ressource, un fichier de contrôleur par ressource. Les routes restent fines — elles se contentent de déclarer quelle fonction de contrôleur gère chaque endpoint. Les contrôleurs restent concentrés — ils ne contiennent que la logique de requête/réponse pour leur ressource.

Express Router

Express Router crée une mini-application qui gère les routes de manière indépendante, que l'on monte ensuite sur un chemin dans app.js.

Commencez par le fichier de routes des utilisateurs :

javascript
// routes/users.js
const express = require('express');
const router = express.Router();
const usersController = require('../controllers/usersController');
router.get('/', usersController.getAllUsers);
router.get('/:id', usersController.getUserById);
router.post('/', usersController.createUser);
router.put('/:id', usersController.updateUser);
router.delete('/:id', usersController.deleteUser);
module.exports = router;

Notez que les routes utilisent des chemins relatifs comme / et /:id, et non /users ou /users/:id. Le préfixe est ajouté lors du montage du routeur dans app.js, ce qui évite toute répétition.

Montage du routeur dans app.js :

javascript
// app.js
const express = require('express');
const app = express();
app.use(express.json());
const usersRouter = require('./routes/users');
const productsRouter = require('./routes/products');
app.use('/users', usersRouter);
app.use('/products', productsRouter);
app.listen(3000, () => console.log('Server running on port 3000'));

Une requête GET vers /users/42 se résout maintenant en router.get('/:id', ...) avec req.params.id égal à '42'. Propre et prévisible.

Contrôleurs

Les contrôleurs sont de simples modules qui exportent des fonctions nommées. Chaque fonction est un gestionnaire de requête Express standard — elle reçoit req et res (et éventuellement next) et est responsable de l'envoi de la réponse.

javascript
// controllers/usersController.js
// Simulated in-memory data — you will replace this with a database call later
const users = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
];
exports.getAllUsers = (req, res) => {
res.json(users);
};
exports.getUserById = (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.json(user);
};
exports.createUser = (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ message: 'name and email are required' });
}
const newUser = { id: users.length + 1, name, email };
users.push(newUser);
res.status(201).json(newUser);
};
exports.updateUser = (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
const { name, email } = req.body;
if (name) user.name = name;
if (email) user.email = email;
res.json(user);
};
exports.deleteUser = (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ message: 'User not found' });
}
users.splice(index, 1);
res.status(204).send();
};

Plusieurs choses méritent d'être soulignées ici. Le contrôleur valide les entrées et renvoie tôt avec un code de statut approprié en cas d'erreur — cela maintient la lisibilité du chemin nominal. La vérification 404 est explicite : ne partez pas du principe qu'un enregistrement existe. Et 204 No Content sans corps est la réponse conventionnelle pour une suppression réussie.

diagramme montrant une seule requête HTTP entrante qui est mise en correspondance par le Router avec la bonne fonction du Controller, puis qui bifurque vers une réponse de succès ou une réponse d'erreur

Erreurs Courantes

Oublier d'analyser le corps JSON des requêtes est le problème le plus fréquent pour un débutant. Sans app.use(express.json()) dans app.js, req.body sera undefined et createUser ou updateUser recevront silencieusement rien.

Un autre piège consiste à comparer directement req.params.id (une chaîne de caractères) à un identifiant numérique avec l'égalité stricte. La vérification users.find(u => u.id === req.params.id) échouera toujours car '42' !== 42. Utilisez parseInt ou Number() pour convertir au préalable.

Enfin, ne pas faire return après l'envoi d'une réponse provoque l'erreur « Cannot set headers after they are sent ». Utilisez toujours return res.status(404).json(...) — le return empêche Express de passer à la ligne suivante et de tenter une seconde réponse.

Résumé

Express Router permet de regrouper les routes liées dans leurs propres modules et de les monter sous un préfixe dans app.js. Les contrôleurs extraient la logique des gestionnaires hors des fichiers de routes, ce qui rend chaque couche plus facile à lire, tester et étendre. Le pattern est : le fichier de route déclare l'URL et le verbe, la fonction du contrôleur gère la logique et envoie la réponse. En respectant un fichier par ressource, cette structure tiendra bon à mesure que le projet grandit.

Entraînement

Point de contrôle de la leçon

Révisez la leçon et recevez des conseils sur votre travail.

0/1
Répondu · 0/1