Déléguer la logique aux services
Objectif : Déplacer l’accès aux données et les règles applicatives dans des services distincts des contrôleurs.
Quand une route contient à la fois la lecture de la requête, une règle métier et l’accès aux données, elle devient difficile à faire évoluer. Vous allez clarifier le rôle de chaque couche : la route associe un chemin à un contrôleur, le contrôleur prépare la réponse HTTP et le service porte le traitement lié aux commandes ou aux produits.
Vos routeurs sont déjà montés sur les préfixes /api/commandes et /api/produits, comme dans « Relier les routes aux contrôleurs ». Ici, vous remplacez les réponses provisoires des contrôleurs par des appels à des fonctions de service. Les fonctions de service restent synchrones dans cette étape ; les promesses et les opérations asynchrones seront abordées dans les leçons suivantes.
Répartir les responsabilités
Le contrôleur reçoit les objets de requête et de réponse Express. Il extrait les informations utiles, appelle le service approprié, puis choisit le statut HTTP et construit le JSON normalisé. Le service ne connaît ni req ni res : il se concentre sur l’opération demandée et peut ainsi être réutilisé sans dépendre du protocole HTTP.
Pour garder le périmètre de cette étape limité, les services ci-dessous exposent une liste vide. Ce résultat permet de vérifier le passage contrôleur-service sans introduire le jeu de données en mémoire, qui sera préparé dans une leçon ultérieure. Dans une version connectée à une source de données, c’est le contenu du service qui évoluera ; le contrôleur gardera la même responsabilité HTTP.
Créer les opérations des services
Remplacez le contenu provisoire de chaque service par une fonction correspondant à une opération métier. Le nom indique clairement ce que le service fournit. Ces fonctions ne créent pas encore de stockage : elles donnent aux contrôleurs un contrat stable, que vous pourrez ensuite relier aux données du projet.
function listerCommandes() {
return [];
}
module.exports = {
listerCommandes
};function listerProduits() {
return [];
}
module.exports = {
listerProduits
};Un service peut dépendre d’une source de données : une base de données, un dépôt ou, pendant les essais, un jeu de données en mémoire. Cette dépendance reste dans la couche service, plutôt que d’être importée ou manipulée directement par le contrôleur. Vous pourrez ainsi remplacer la manière de lire les commandes sans modifier la construction des réponses HTTP.
Faire déléguer les contrôleurs
Les contrôleurs importent le service de leur ressource et appellent son opération. Ils gardent la responsabilité du statut et de la forme de la réponse. Les fonctions ci-dessous sont volontairement simples ; elles ne contiennent pas encore de logique asynchrone.
const commandesService = require('../services/commandes');
function lister(req, res) {
const commandes = commandesService.listerCommandes();
res.status(200).json({
donnees: commandes,
erreur: null
});
}
module.exports = {
lister
};const produitsService = require('../services/produits');
function lister(req, res) {
const produits = produitsService.listerProduits();
res.status(200).json({
donnees: produits,
erreur: null
});
}
module.exports = {
lister
};Relier les fonctions aux routes
Les fichiers de routes associent maintenant la méthode et le chemin à la fonction exportée par le contrôleur. Gardez ces noms cohérents avec les contrôleurs présentés : chaque route de liste appelle lister. Les montages du serveur restent inchangés ; ces routeurs sont déjà accessibles sous leurs préfixes API.
const express = require('express');
const commandesControleur = require('../controleurs/commandes');
const router = express.Router();
router.get('/', commandesControleur.lister);
module.exports = router;const express = require('express');
const produitsControleur = require('../controleurs/produits');
const router = express.Router();
router.get('/', produitsControleur.lister);
module.exports = router;Après avoir enregistré ces fichiers et démarré le serveur avec la commande déjà configurée dans votre projet, envoyez une requête GET à /api/commandes ou /api/produits. Dans les deux cas, le service fournit une liste vide et le contrôleur renvoie le statut 200 avec le format JSON attendu. Cette vérification confirme le passage route → contrôleur → service → réponse.
À retenir
- La route associe un chemin à une fonction de contrôleur.
- Le contrôleur gère la requête et la réponse HTTP ; le service porte l’opération liée à la ressource.
- Le contrôleur transmet au service uniquement les données nécessaires, sans lui passer les objets Express.
- La dépendance aux données reste dans le service, ce qui permet de la faire évoluer séparément.
Dans la prochaine leçon, vous ferez évoluer un service pour qu’il retourne une promesse, première étape avant d’utiliser les opérations asynchrones dans les contrôleurs.