1. Installation et premier serveur Express

Express est le framework web Node.js le plus populaire. Il ajoute une couche d'abstraction au-dessus du module http natif, rendant le code beaucoup plus concis et lisible.

Installation

# Dans votre dossier de projet
npm init -y
npm install express

# Pour le développement (rechargement automatique)
npm install --save-dev nodemon

Premier serveur Express — 5 lignes

const express = require('express');
const app = express();

app.get('/', (req, res) => res.send('Hello Express !'));

app.listen(3000, () => console.log('Serveur Express sur http://localhost:3000'));

Comparaison : HTTP natif vs Express

FonctionnalitéHTTP natifExpress
Lire le body JSON req.on('data'...) + parse express.json()req.body
Paramètre d'URL RegExp + groups :idreq.params.id
Réponse JSON res.writeHead + JSON.stringify res.json(data)
Status code res.writeHead(404) res.status(404).json(...)
Routing if/else manuels app.get(path, handler)
💡 Express est le framework recommandé pour 95 % des APIs Node.js en production. Il est léger, extensible, et possède un écosystème de middlewares immense.

2. Méthodes HTTP — app.get / post / put / delete

Express expose une méthode pour chaque verbe HTTP. Le handler reçoit toujours (req, res) en paramètres.

Les 4 méthodes CRUD

const express = require('express');
const app = express();

app.use(express.json()); // Parser le body JSON

// GET  — Lire
app.get('/users', (req, res) => {
  res.json({ method: 'GET', action: 'Lister les utilisateurs' });
});

// POST — Créer
app.post('/users', (req, res) => {
  res.status(201).json({ method: 'POST', received: req.body });
});

// PUT  — Remplacer
app.put('/users/:id', (req, res) => {
  res.json({ method: 'PUT', id: req.params.id, received: req.body });
});

// DELETE — Supprimer
app.delete('/users/:id', (req, res) => {
  res.json({ method: 'DELETE', id: req.params.id });
});

app.listen(3000);

app.all() et app.use()

// app.all() — Toutes les méthodes pour un chemin
app.all('/ping', (req, res) => {
  res.json({ method: req.method, message: 'pong' });
});

// app.use() — Middleware pour tous les chemins
// (détaillé dans N06 — Middleware)
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`); // Logger
  next(); // Passer au handler suivant
});

Handlers multiples sur la même route

// Plusieurs callbacks sur une route (chaîne de handlers)
function logger(req, res, next) {
  console.log('Logger middleware');
  next(); // Obligatoire pour passer au suivant
}

function checkAuth(req, res, next) {
  if (!req.headers.authorization) {
    return res.status(401).json({ error: 'Non autorisé' });
  }
  next();
}

// Les handlers sont exécutés dans l'ordre
app.get('/protected', logger, checkAuth, (req, res) => {
  res.json({ message: 'Route protégée !' });
});
💡 Les verbes Express correspondent directement aux méthodes HTTP : app.get → GET, app.post → POST, app.put → PUT, app.delete → DELETE, app.patch → PATCH.

3. req — Paramètres de la requête

L'objet req d'Express enrichit celui du module http natif avec des propriétés pratiques pour accéder aux données de la requête.

req.params — Paramètres de route dynamiques

// :id est un paramètre de route — capturé dans req.params.id
app.get('/users/:id', (req, res) => {
  const { id } = req.params;
  res.json({ userId: id, type: typeof id }); // id est toujours une string !
});

// Plusieurs paramètres
app.get('/users/:userId/posts/:postId', (req, res) => {
  const { userId, postId } = req.params;
  res.json({ userId, postId });
});

// :id? — paramètre optionnel
app.get('/products/:category?', (req, res) => {
  const cat = req.params.category ?? 'all';
  res.json({ category: cat });
});

req.query — Query string

// URL : GET /search?q=node&page=2&limit=10
app.get('/search', (req, res) => {
  const { q = '', page = '1', limit = '10' } = req.query;

  // req.query retourne toujours des strings !
  const pageNum  = parseInt(page,  10);
  const limitNum = parseInt(limit, 10);

  res.json({
    query:   q,
    page:    pageNum,
    limit:   limitNum,
    offset:  (pageNum - 1) * limitNum,
  });
});

req.body — Corps de la requête

// Nécessite le middleware express.json() !
app.use(express.json());

app.post('/users', (req, res) => {
  // req.body est l'objet JavaScript parsé
  const { name, email, age } = req.body;

  if (!name || !email) {
    return res.status(400).json({ error: 'name et email requis' });
  }

  // Validation de type
  if (age !== undefined && typeof age !== 'number') {
    return res.status(400).json({ error: 'age doit être un nombre' });
  }

  res.status(201).json({ created: { name, email, age } });
});

Autres propriétés utiles

app.get('/info', (req, res) => {
  res.json({
    method:     req.method,          // "GET"
    path:       req.path,            // "/info" (sans query string)
    url:        req.url,             // "/info?foo=bar" (avec query)
    hostname:   req.hostname,        // "localhost"
    ip:         req.ip,              // IP du client
    protocol:   req.protocol,        // "http" ou "https"
    secure:     req.secure,          // true si HTTPS
    userAgent:  req.headers['user-agent'],
    token:      req.headers.authorization,
  });
});
⚠️ req.params, req.query retournent toujours des strings. Convertissez avec parseInt(), parseFloat() ou Number() si nécessaire.

4. res — Construire la réponse

L'objet res d'Express simplifie énormément l'envoi de réponses par rapport au module http natif.

Méthodes de réponse Express

MéthodeUsageContent-Type auto
res.json(data)Objet/tableau JSONapplication/json
res.send(string)Texte ou HTMLtext/html ou text/plain
res.status(N).json()JSON + status codeapplication/json
res.redirect(url)Redirection 302
res.sendFile(path)Fichier statiqueDétecté auto
res.end()Corps vide (204)

Exemples de réponses

const path = require('path');

// JSON avec status 201 (Created)
app.post('/articles', (req, res) => {
  const article = { id: 1, ...req.body };
  res.status(201).json({ success: true, data: article });
});

// Erreur 404
app.get('/users/:id', (req, res) => {
  const user = users.find(u => u.id === parseInt(req.params.id));
  if (!user) {
    return res.status(404).json({ error: 'Utilisateur non trouvé' });
  }
  res.json({ data: user });
});

// Redirection
app.get('/old-path', (req, res) => {
  res.redirect(301, '/new-path'); // 301 = permanent
});

// Envoyer un fichier
app.get('/download', (req, res) => {
  res.sendFile(path.join(__dirname, 'public', 'rapport.pdf'));
});

// Réponse vide (204 No Content — souvent pour DELETE)
app.delete('/sessions', (req, res) => {
  res.status(204).end(); // Pas de body
});

Chaînage avec .status()

// Pattern recommandé : status().json() chaîné
res.status(200).json({ success: true, data: items });    // OK
res.status(201).json({ success: true, data: newItem });  // Created
res.status(400).json({ success: false, error: 'Bad Request' });
res.status(401).json({ success: false, error: 'Unauthorized' });
res.status(404).json({ success: false, error: 'Not Found' });
res.status(500).json({ success: false, error: 'Internal Error' });
💡 res.json() sans .status() envoie automatiquement un 200. Soyez explicite avec les codes non-200 pour respecter les conventions REST.

5. Structure d'une application Express

L'ordre des déclarations dans une application Express est crucial. Les middlewares et routes sont traités séquentiellement, de haut en bas.

Application complète bien organisée

const express = require('express');
const app = express();

// ─────────────────────────────────────────────────────
// 1. MIDDLEWARES GLOBAUX — avant toutes les routes
// ─────────────────────────────────────────────────────
app.use(express.json());                      // Parser JSON body
app.use(express.urlencoded({ extended: true })); // Parser form data

// Logger de requêtes (middleware custom simple)
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
});

// ─────────────────────────────────────────────────────
// 2. ROUTES — dans l'ordre du plus spécifique au plus général
// ─────────────────────────────────────────────────────
let users = [
  { id: 1, name: 'Alice', email: 'alice@example.com' },
  { id: 2, name: 'Bob',   email: 'bob@example.com'   },
];
let nextId = 3;

app.get('/users', (req, res) => {
  res.json({ success: true, count: users.length, data: users });
});

app.get('/users/:id', (req, res) => {
  const user = users.find(u => u.id === parseInt(req.params.id));
  if (!user) return res.status(404).json({ error: 'Non trouvé' });
  res.json({ success: true, data: user });
});

app.post('/users', (req, res) => {
  const { name, email } = req.body;
  if (!name || !email) return res.status(400).json({ error: 'name et email requis' });
  const user = { id: nextId++, name, email };
  users.push(user);
  res.status(201).json({ success: true, data: user });
});

app.put('/users/:id', (req, res) => {
  const idx = users.findIndex(u => u.id === parseInt(req.params.id));
  if (idx === -1) return res.status(404).json({ error: 'Non trouvé' });
  users[idx] = { ...users[idx], ...req.body, id: users[idx].id };
  res.json({ success: true, data: users[idx] });
});

app.delete('/users/:id', (req, res) => {
  const idx = users.findIndex(u => u.id === parseInt(req.params.id));
  if (idx === -1) return res.status(404).json({ error: 'Non trouvé' });
  users.splice(idx, 1);
  res.json({ success: true, message: 'Supprimé' });
});

// ─────────────────────────────────────────────────────
// 3. 404 — DOIT être après toutes les routes
// ─────────────────────────────────────────────────────
app.use('*', (req, res) => {
  res.status(404).json({ error: 'Route introuvable', path: req.path });
});

// ─────────────────────────────────────────────────────
// 4. ERROR HANDLER — DOIT être en dernier (4 paramètres)
// ─────────────────────────────────────────────────────
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ error: 'Erreur interne', message: err.message });
});

app.listen(3000, () => console.log('API Users sur http://localhost:3000'));

Ordre des éléments — résumé

#ÉlémentRaison de l'ordre
1Middlewares globaux (express.json(), logger...)Doivent traiter la req avant les routes
2Routes spécifiques (/users/:id avant /users)Express choisit la première route qui correspond
3Handler 404 (app.use('*', ...))Capte tout ce qui n'a pas matché
4Error handler ((err, req, res, next))Reçoit les erreurs propagées avec next(err)
⚠️ Si express.json() est placé après vos routes, req.body sera undefined dans ces routes. Toujours déclarer les middlewares avant les routes qui en dépendent.
← Accueil Exercices →