4.1 · Construire une API REST complète (CRUD)

Niveau 4 · API, authentification & temps réel

4.1Construire une API REST complète (CRUD)

Objectif : Construire une API REST complète et bien structurée (CRUD, ressources, méthodes HTTP sémantiques, codes de statut, MVC) — un livrable central du back-end Node.
Temps estimé : 12 min · lecture autonome · Si vous n'avez que 5 min : lisez « L'essentiel en 30s » + le schéma.

L'essentiel en 30 secondes

  • REST = ressources + méthodes HTTP : l'URL désigne la ressource au pluriel (/users), la méthode porte l'action (GET lire, POST créer, PUT modifier, DELETE supprimer).
  • Structurer en couches (MVC) : routes (URL) → contrôleurs (logique) → modèles (données) ; express.Router() regroupe les routes par ressource.
  • Réflexe de Salim : renvoyer du JSON avec le bon code (201 après création, 404 si absent, 400 si invalide) et versionner (/api/v1/).

Mini-cas filé — Salim construit l'API produits à Alger

Salim, développeur junior dans une startup à Alger, doit exposer le catalogue produits au front : lister, afficher un produit, en créer, modifier, supprimer. Il conçoit d'abord ses endpoints REST (GET /api/v1/produits, GET /api/v1/produits/:id, POST, PUT, DELETE), sépare routes, contrôleurs et données, et regroupe les routes dans un express.Router() monté sur l'app. Quand le front appelle son API, chaque réponse arrive en JSON avec le bon code de statut. Premier jalon du fil rouge : une API prévisible que le front devine sans documentation.

Ce même cas revient dans le cours, le schéma, le script et le défi 48h — et continue en 4.2, 4.3 et 4.4.

1. Les principes REST

REST est un style d'architecture d'API : on expose des ressources (utilisateurs, produits) identifiées par des URL claires au pluriel (/users, /produits), et on agit dessus avec les méthodes HTTP selon leur sémantique : GET /users (lister), GET /users/:id (lire un), POST /users (créer), PUT/PATCH /users/:id (modifier), DELETE /users/:id (supprimer). Comme Salim, on ne met jamais de verbe dans l'URL : pas /getUsers, mais GET /users.

L'API renvoie des données en JSON avec les bons codes de statut : 200 succès, 201 créé (après POST), 204 sans contenu (après DELETE), 400 requête invalide, 404 non trouvé, 500 erreur serveur. Ces conventions cohérentes rendent l'API prévisible : le front devine les endpoints au lieu de les mémoriser un par un.

2. Structurer en couches (MVC)

Une API qui grossit sans structure devient un plat de spaghetti. Le pattern classique est le MVC : les modèles (structure et accès aux données), les contrôleurs (logique de traitement de chaque requête), les routes (définition des URL et méthodes, qui délèguent aux contrôleurs). Dossiers typiques : routes/, controllers/, models/, plus middlewares/, services/, config/.

On utilise le Router d'Express (express.Router()) pour regrouper les routes par ressource dans des fichiers séparés (un routeur produits, un routeur commandes), montés sur l'app. Cette séparation rend le code compréhensible, maintenable, testable et évolutif — et permet de travailler à plusieurs sans se marcher dessus.

3. Les bonnes pratiques d'une API bien conçue

Ce qui sépare une API professionnelle d'une API qui « marche » : des URL cohérentes au pluriel, les bonnes méthodes pour les bonnes actions, les bons codes de statut (jamais 200 pour une erreur), une gestion d'erreurs propre (voir 4.4), la pagination des listes, le versionnage (/api/v1/...) pour faire évoluer l'API sans casser les clients, et des réponses JSON structurées. Salim applique cette check-list à chaque endpoint avant de dire « c'est fini ».

Erreur d'interprétation fréquente : « Mon API marche, donc elle est bien conçue : le front reçoit les données, c'est l'essentiel ». Non. Une API peut renvoyer les bonnes données tout en étant incohérente (verbes dans les URL, tout en POST, 200 pour les erreurs, logique entassée dans les routes) — et cette dette se paie dès que le front grandit ou qu'un deuxième client arrive. Bien conçu = prévisible, maintenable, testable — pas seulement fonctionnel en démo.
Le trajet d'une requête dans l'API Routes → contrôleurs → modèles → réponse Routes URL + méthode(express.Router)Contrôleurs Logiquede traitementModèles Données (mémoire,Mongoose, Prisma)Réponse JSON + boncode de statut
Routes → contrôleurs → modèles → réponse
Version texte du schéma (SEO / lecteurs d'écran / traduction) : 1) Salim définit ses endpoints REST : l'URL désigne la ressource au pluriel, la méthode HTTP porte l'action. 2) Il sépare routes (URL), contrôleurs (logique) et modèles (données), avec un routeur Express par ressource. 3) Chaque réponse part en JSON avec le bon code : 201 après création, 404 si absent, 400 si invalide. Leçon : prévisible pour le front, maintenable pour l'équipe.

🔎 Exemple concret — 🔎 Exemple concret — Le CRUD REST d'une ressource

La table de correspondance que Salim affiche au-dessus de son écran :

GET    /api/v1/produits      → lister (200)
GET    /api/v1/produits/:id  → lire un (200, 404 si absent)
POST   /api/v1/produits      → créer (201, 400 si invalide)
PUT    /api/v1/produits/:id  → modifier (200, 404 si absent)
DELETE /api/v1/produits/:id  → supprimer (204)

Lecture : cinq lignes, cinq couples méthode + URL, cinq codes attendus.

Leçon : l'action est portée par la méthode HTTP, jamais par l'URL.

Vocabulaire de la section

API REST
Style d'architecture d'API web : exposer des ressources (URL claires) manipulées par les méthodes HTTP selon leur sémantique, réponses en JSON avec les bons codes de statut.

Exemple simple : L'API produits de Salim : GET pour lire, POST pour créer, JSON en réponse.

Ce que ce n'est pas : un simple script qui renvoie du HTML mélangé à la logique.

Réflexe : pour chaque endpoint, nommer ressource, méthode et code attendu.

Ressource
Entité exposée par l'API (produits, utilisateurs, commandes), identifiée par une URL claire au pluriel.

Exemple simple : La ressource produits de Salim vit sous /api/v1/produits.

Ce que ce n'est pas : une action verbale comme /creerProduit.

Réflexe : URL = nom au pluriel, sans verbe.

MVC
Séparation modèles (données), contrôleurs (logique), routes (URL) pour un code maintenable et évolutif.

Exemple simple : Salim place ses URL dans routes/, sa logique dans controllers/.

Ce que ce n'est pas : tout le code entassé dans un seul fichier app.js.

Réflexe : une modification touche une couche, pas les trois.

express.Router()
Outil Express regroupant les routes d'une ressource dans un fichier séparé, monté ensuite sur l'application.

Exemple simple : Le routeur produits de Salim est monté avec app.use('/api/v1/produits', routeur).

Ce que ce n'est pas : la déclaration de toutes les routes en vrac dans le fichier principal.

Réflexe : un fichier de routes par ressource.

Code de statut
Nombre HTTP communiquant le résultat : 200 succès, 201 créé, 204 sans contenu, 400 invalide, 404 absent, 500 erreur serveur.

Exemple simple : Salim renvoie 201 après un POST réussi, 404 pour un produit inconnu.

Ce que ce n'est pas : un 200 systématique même en cas d'erreur.

Réflexe : le client doit comprendre le résultat sans lire le corps.

En pratique — En pratique — Construire une API REST structurée

  1. Concevez les endpoints d'une ressource selon REST : GET /items (lister), GET /items/:id (lire), POST /items (créer), PUT /items/:id (modifier), DELETE /items/:id (supprimer).
  2. Structurez le projet en couches : routes/ (URL), controllers/ (logique), models/ (données) — comme Salim pour son catalogue.
  3. Utilisez express.Router() pour regrouper les routes d'une ressource dans un fichier, monté sur l'app (app.use('/api/v1/items', itemsRouter)).
  4. Renvoyez du JSON avec les bons codes de statut (201 après création, 404 si non trouvé, 400 si données invalides) et prévoyez pagination et versionnage.
Vous construisez une API REST complète et bien structurée (CRUD, ressources, méthodes HTTP sémantiques, codes de statut, MVC) — un livrable central du back-end Node.

Script prêt à dire — présenter son API au front (30 s)

« C'est Salim : l'API produits suit les conventions REST — GET pour lire, POST pour créer, PUT pour modifier, DELETE pour supprimer, sous /api/v1/produits, réponses en JSON avec les bons codes : 201 après création, 404 si absent, 400 si invalide. La structure est en couches routes, contrôleurs, modèles, donc on pourra ajouter des ressources sans tout casser. »

À dire en revue de code ; montrez la table des cinq endpoints.

Modèle copier-coller — routeur CRUD Express (code testé)

const express = require('express');
const routeur = express.Router();

let produits = [];
let prochainId = 1;

// GET /api/v1/produits → lister (200)
routeur.get('/', (req, res) => {
  res.json(produits);
});

// GET /api/v1/produits/:id → lire un (200 / 404)
routeur.get('/:id', (req, res) => {
  const produit = produits.find((p) => p.id === Number(req.params.id));
  if (!produit) return res.status(404).json({ erreur: 'Produit introuvable' });
  res.json(produit);
});

// POST /api/v1/produits → créer (201 / 400)
routeur.post('/', (req, res) => {
  if (!req.body.nom) return res.status(400).json({ erreur: 'Le champ nom est requis' });
  const produit = { id: prochainId++, nom: req.body.nom };
  produits.push(produit);
  res.status(201).json(produit);
});

// PUT /api/v1/produits/:id → modifier (200 / 404)
routeur.put('/:id', (req, res) => {
  const produit = produits.find((p) => p.id === Number(req.params.id));
  if (!produit) return res.status(404).json({ erreur: 'Produit introuvable' });
  if (req.body.nom) produit.nom = req.body.nom;
  res.json(produit);
});

// DELETE /api/v1/produits/:id → supprimer (204 / 404)
routeur.delete('/:id', (req, res) => {
  const index = produits.findIndex((p) => p.id === Number(req.params.id));
  if (index === -1) return res.status(404).json({ erreur: 'Produit introuvable' });
  produits.splice(index, 1);
  res.status(204).end();
});

module.exports = routeur;
// Montage (nécessite express.json()) :
// const express = require('express');
// const app = express();
// app.use(express.json());
// app.use('/api/v1/produits', routeur);

Prototype jetable

Une séparation légère suffit (routes + logique), mais gardez les conventions REST : elles ne coûtent rien et évitent de réécrire.

API réelle en équipe

Comme Salim : couches complètes (routes/, controllers/, models/, services/), un routeur par ressource, revue de code sur les statuts.

API consommée par un mobile

Soignez pagination et réponses JSON stables : le mobile met en cache et souffre de chaque rupture de contrat.

API qui doit évoluer

Versionnez dès le départ (/api/v1/) : la v2 viendra, et vos clients v1 ne casseront pas.

Prudence : Une API expose votre système au monde : validez toujours les entrées (voir 4.4) et ne renvoyez jamais de détails techniques sensibles dans les erreurs. Testez chaque endpoint y compris les cas d'échec (404, 400) avant d'annoncer « c'est fini ». Contenu pédagogique, exemples avec données fictives.

✓ Bonnes pratiques

  • URL = ressource au pluriel, action = méthode HTTP.
  • Structurer en couches dès que l'API est réelle.
  • Renvoyer le bon code de statut à chaque fois.

✗ Pièges fréquents

  • Mettre un verbe dans l'URL (/getProduits).
  • Renvoyer 200 pour tout, même les erreurs.
  • Entasser toute la logique dans les fichiers de routes.

Points clés à retenir

  • API REST : exposer des RESSOURCES (URL claires au pluriel) manipulées par les MÉTHODES HTTP selon leur sémantique, en JSON avec les bons CODES DE STATUT.
  • CRUD REST : GET /produits (lister), GET /produits/:id (lire), POST (créer, 201), PUT (modifier), DELETE (supprimer, 204).
  • STRUCTURER en couches (MVC) : models, controllers, routes + services/middlewares ; express.Router() regroupe les routes par ressource.
  • Bonnes pratiques : URL cohérentes, bons codes, gestion d'erreurs, pagination, versionnage (/api/v1/). Prévisible et professionnelle.

Défi 48h — appliquez demain

Construisez le routeur CRUD complet d'1 ressource réelle (les 5 endpoints, bons codes) et testez chaque route y compris le 404 et le 400.

Checklist sortie de section
  • Je peux citer les 5 endpoints CRUD avec leurs codes.
  • Je sais séparer routes, contrôleurs et modèles.
  • J'ai testé 1 routeur complet, échecs inclus.
Auto-évaluation 1-5 : mes URL portent-elles des ressources sans verbe ?mes codes de statut sont-ils justes sur chaque route ?

Questions fréquentes

Qu'est-ce qui distingue une API REST « bien conçue » d'une API qui « marche » simplement ?

Des conventions et une structure : URL cohérentes sur les ressources (pas de verbe), bonnes méthodes HTTP selon leur sémantique, bons codes de statut (201, 404, 400 — pas 200 pour tout), couches MVC au lieu du spaghetti, gestion d'erreurs propre (4.4), validation des entrées, réponses JSON structurées, pagination et versionnage (/api/v1/). Une API bien conçue est prévisible (on devine ses endpoints), maintenable et agréable à consommer — cruciale car elle est faite pour être utilisée par d'autres.

Faut-il vraiment structurer en MVC dès le début, même pour une petite API ?

Adaptez au projet, mais séparez tôt : les projets grandissent presque toujours et refactoriser un spaghetti coûte cher. Petit prototype : séparation légère (routes vs logique, avec express.Router()). API réelle : couches complètes dès le début (routes/, controllers/, models/, services/) — compréhensible, maintenable, testable et collaborative. Ni sur-ingénierie pour un exercice, ni fourre-tout « parce que c'est petit ».

Vérifiez votre compréhension

Dans une API REST, qui porte l'action (créer, supprimer) ?

Ressources supplémentaires (optionnel, pour aller plus loin)

Examen du niveau 4Questions inédites et durcies pour valider vos acquis