Garden of KnowledgeApplied Sciences › Computer Science › Software › Web
April 7, 2026

Node.js et Express

Node.js§

Node.js est un environnement d’exécution JavaScript côté serveur, construit sur le moteur V8 de Chrome. Il permet d’exécuter du JavaScript en dehors du navigateur.

Caractéristiques§

Architecture événementielle non-bloquante : Node.js utilise un modèle d’I/O asynchrone basé sur une boucle d’événements (event loop). Au lieu de créer un thread par connexion, Node.js gère toutes les connexions dans un seul thread, en déléguant les opérations I/O au système d’exploitation.

Requêtes entrantes


   Event Loop (single thread)

   ┌────┴────┐
   │         │
Callbacks  I/O Operations (async)
(sync)    ─────────────────────────
          File System, Network, DB
          (gérés par libuv en C++)

Adapté pour : APIs REST, applications temps réel (chat, streaming), microservices, outils CLI.

Moins adapté pour : calcul intensif CPU (bloque l’event loop), applications nécessitant du parallélisme natif.

npm — Node Package Manager§

# Initialiser un projet
npm init -y

# Installer une dépendance
npm install express
npm install -D nodemon   # dépendance de développement (-D = --save-dev)

# Désinstaller
npm uninstall express

# Lancer un script (défini dans package.json)
npm start
npm run dev

# Audit de sécurité
npm audit
npm audit fix

Modules CommonJS et ESM§

// CommonJS (historique, .js par défaut si "type": "commonjs")
const fs = require('fs');
const { join } = require('path');
module.exports = { maFonction };

// ESM — ES Modules (.mjs ou "type": "module" dans package.json)
import fs from 'fs';
import { join } from 'path';
export { maFonction };
export default class MaClasse {}

Modules natifs courants§

const fs = require('fs');           // Système de fichiers
const path = require('path');       // Manipulation de chemins
const http = require('http');       // Serveur HTTP natif
const https = require('https');     // Serveur HTTPS natif
const os = require('os');           // Informations système
const crypto = require('crypto');   // Cryptographie
const events = require('events');   // EventEmitter
const stream = require('stream');   // Streams
const url = require('url');         // Parsing d'URL
const querystring = require('querystring'); // Query strings

Système de fichiers asynchrone§

const fs = require('fs').promises;  // API promises (Node 10+)
const path = require('path');

// Lire un fichier
const contenu = await fs.readFile(path.join(__dirname, 'data.txt'), 'utf8');

// Écrire un fichier
await fs.writeFile('output.txt', 'Hello World', 'utf8');

// Lire un répertoire
const fichiers = await fs.readdir('./');

// Vérifier l'existence
try {
    await fs.access('fichier.txt');
    console.log('Existe');
} catch {
    console.log("N'existe pas");
}

// Copier, renommer, supprimer
await fs.copyFile('src.txt', 'dest.txt');
await fs.rename('ancien.txt', 'nouveau.txt');
await fs.unlink('fichier.txt');

Streams§

Les streams permettent de traiter des données en flux continu sans charger tout le fichier en mémoire.

const fs = require('fs');

// Lire un grand fichier par morceaux
const readable = fs.createReadStream('grand-fichier.csv', { encoding: 'utf8' });

readable.on('data', (chunk) => {
    console.log(`Reçu ${chunk.length} octets`);
});
readable.on('end', () => console.log('Lecture terminée'));
readable.on('error', (err) => console.error(err));

// Pipe : connecter readable → writable
const readStream = fs.createReadStream('input.txt');
const writeStream = fs.createWriteStream('output.txt');
readStream.pipe(writeStream);

// Transform stream (transformer à la volée)
const { Transform } = require('stream');
const majuscules = new Transform({
    transform(chunk, encoding, callback) {
        callback(null, chunk.toString().toUpperCase());
    }
});
fs.createReadStream('input.txt')
    .pipe(majuscules)
    .pipe(fs.createWriteStream('output.txt'));

EventEmitter§

const EventEmitter = require('events');

class Serveur extends EventEmitter {
    demarrer(port) {
        // ... démarrage
        this.emit('demarrage', port);
    }
    arreter() {
        this.emit('arret');
    }
}

const serveur = new Serveur();
serveur.on('demarrage', (port) => console.log(`Serveur démarré sur :${port}`));
serveur.on('arret', () => console.log('Serveur arrêté'));
serveur.demarrer(3000);

Express.js§

Express est le framework web minimal pour Node.js. Il fournit un système de routage, un middleware pipeline et des utilitaires HTTP.

Installation et serveur de base§

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

// Middleware globaux
app.use(express.json());                    // Parser les corps JSON
app.use(express.urlencoded({ extended: true })); // Parser les form data
app.use(express.static('public'));          // Servir des fichiers statiques

// Route simple
app.get('/', (req, res) => {
    res.json({ message: 'Bienvenue sur l\'API' });
});

// Démarrer le serveur
app.listen(PORT, () => {
    console.log(`Serveur sur http://localhost:${PORT}`);
});

Routage§

// Méthodes HTTP
app.get('/clients', listerClients);
app.post('/clients', creerClient);
app.get('/clients/:id', obtenirClient);
app.put('/clients/:id', remplacerClient);
app.patch('/clients/:id', modifierClient);
app.delete('/clients/:id', supprimerClient);

// Paramètres de route
app.get('/clients/:id/commandes/:commandeId', (req, res) => {
    const { id, commandeId } = req.params;
    res.json({ clientId: id, commandeId });
});

// Query parameters
app.get('/produits', (req, res) => {
    const { page = 1, limit = 20, categorie } = req.query;
    // GET /produits?page=2&limit=10&categorie=informatique
    res.json({ page, limit, categorie });
});

// Router modulaire
const router = express.Router();
router.get('/', listerClients);
router.post('/', creerClient);
router.get('/:id', obtenirClient);

app.use('/api/v1/clients', router);

Middleware§

Le middleware est une fonction (req, res, next) qui s’exécute dans le pipeline de traitement de la requête.

// Middleware global (s'applique à toutes les routes)
app.use((req, res, next) => {
    console.log(`${req.method} ${req.path} - ${new Date().toISOString()}`);
    next(); // Passer au middleware suivant
});

// Middleware sur une route spécifique
const verifierAuthentification = (req, res, next) => {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token) {
        return res.status(401).json({ erreur: 'Token manquant' });
    }
    try {
        req.utilisateur = jwt.verify(token, process.env.JWT_SECRET);
        next();
    } catch {
        res.status(401).json({ erreur: 'Token invalide' });
    }
};

app.get('/profil', verifierAuthentification, (req, res) => {
    res.json(req.utilisateur);
});

// Middleware de gestion des erreurs (4 paramètres)
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(err.status || 500).json({
        erreur: {
            message: err.message || 'Erreur interne du serveur',
            code: err.code || 'INTERNAL_ERROR'
        }
    });
});

Architecture MVC avec Express§

projet/
├── src/
│   ├── controllers/      # Logique de traitement des requêtes
│   │   └── clientController.js
│   ├── services/         # Logique métier
│   │   └── clientService.js
│   ├── models/           # Modèles de données (Mongoose, Sequelize...)
│   │   └── Client.js
│   ├── routes/           # Définition des routes
│   │   └── clientRoutes.js
│   ├── middlewares/      # Middlewares personnalisés
│   │   └── auth.js
│   └── app.js            # Configuration Express
├── .env                  # Variables d'environnement
└── server.js             # Point d'entrée
// controllers/clientController.js
const clientService = require('../services/clientService');

exports.lister = async (req, res, next) => {
    try {
        const { page = 1, limit = 20 } = req.query;
        const clients = await clientService.lister({ page, limit });
        res.json({ data: clients });
    } catch (err) {
        next(err);  // Passer l'erreur au middleware d'erreur
    }
};

exports.creer = async (req, res, next) => {
    try {
        const client = await clientService.creer(req.body);
        res.status(201).json({ data: client });
    } catch (err) {
        next(err);
    }
};

// routes/clientRoutes.js
const router = require('express').Router();
const { lister, creer, obtenir, modifier, supprimer } = require('../controllers/clientController');
const { verifierToken } = require('../middlewares/auth');

router.get('/', lister);
router.post('/', verifierToken, creer);
router.get('/:id', obtenir);
router.patch('/:id', verifierToken, modifier);
router.delete('/:id', verifierToken, supprimer);

module.exports = router;

Validation avec express-validator§

const { body, validationResult } = require('express-validator');

const reglesCréationClient = [
    body('nom')
        .notEmpty().withMessage('Le nom est requis')
        .isLength({ min: 2, max: 100 }).withMessage('2 à 100 caractères'),
    body('email')
        .isEmail().withMessage('Email invalide')
        .normalizeEmail(),
    body('age')
        .optional()
        .isInt({ min: 0, max: 150 }).withMessage('Âge entre 0 et 150')
];

const valider = (req, res, next) => {
    const erreurs = validationResult(req);
    if (!erreurs.isEmpty()) {
        return res.status(422).json({ erreurs: erreurs.array() });
    }
    next();
};

router.post('/', reglesCréationClient, valider, creerClient);

Variables d’environnement avec dotenv§

# .env (ne jamais committer)
PORT=3000
DATABASE_URL=postgresql://user:pass@localhost:5432/madb
JWT_SECRET=super_secret_key_changez_moi
NODE_ENV=development
require('dotenv').config();  // À appeler le plus tôt possible

const port = process.env.PORT || 3000;
const dbUrl = process.env.DATABASE_URL;

CORS§

const cors = require('cors');

// Autoriser toutes les origines (développement seulement)
app.use(cors());

// Configuration précise (production)
app.use(cors({
    origin: ['https://monsite.com', 'https://app.monsite.com'],
    methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
    allowedHeaders: ['Content-Type', 'Authorization'],
    credentials: true  // Autoriser les cookies
}));

Authentification JWT§

const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');

// Connexion
app.post('/auth/login', async (req, res) => {
    const { email, motDePasse } = req.body;
    const utilisateur = await trouverParEmail(email);

    if (!utilisateur || !await bcrypt.compare(motDePasse, utilisateur.motDePasse)) {
        return res.status(401).json({ erreur: 'Identifiants invalides' });
    }

    const token = jwt.sign(
        { id: utilisateur.id, email: utilisateur.email, role: utilisateur.role },
        process.env.JWT_SECRET,
        { expiresIn: '24h' }
    );

    res.json({ token });
});

// Inscription
app.post('/auth/inscription', async (req, res) => {
    const { email, motDePasse } = req.body;
    const hash = await bcrypt.hash(motDePasse, 12);  // 12 rounds
    const utilisateur = await creerUtilisateur({ email, motDePasse: hash });
    res.status(201).json({ id: utilisateur.id });
});

Connexion à une base de données (PostgreSQL avec pg)§

const { Pool } = require('pg');

const pool = new Pool({
    connectionString: process.env.DATABASE_URL,
    max: 20,              // Taille maximale du pool
    idleTimeoutMillis: 30000,
    connectionTimeoutMillis: 2000
});

// Requête simple
const { rows } = await pool.query(
    'SELECT * FROM clients WHERE id = $1',
    [id]
);

// Transaction
const client = await pool.connect();
try {
    await client.query('BEGIN');
    await client.query('UPDATE comptes SET solde = solde - $1 WHERE id = $2', [montant, idSource]);
    await client.query('UPDATE comptes SET solde = solde + $1 WHERE id = $2', [montant, idDest]);
    await client.query('COMMIT');
} catch (err) {
    await client.query('ROLLBACK');
    throw err;
} finally {
    client.release();
}

Middlewares tiers populaires§

PackageUsage
corsGestion du Cross-Origin Resource Sharing
helmetEn-têtes de sécurité HTTP
express-rate-limitLimitation du nombre de requêtes
morganLogging des requêtes HTTP
compressionCompression gzip des réponses
multerUpload de fichiers multipart
express-validatorValidation et sanitisation
dotenvVariables d’environnement
jsonwebtokenCréation et vérification JWT
bcryptHachage de mots de passe
pgClient PostgreSQL
mongooseODM MongoDB
sequelizeORM SQL
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const morgan = require('morgan');

// Sécurité
app.use(helmet());

// Rate limiting
const limiter = rateLimit({
    windowMs: 15 * 60 * 1000,  // 15 minutes
    max: 100,                    // 100 requêtes par fenêtre
    message: 'Trop de requêtes, réessayez dans 15 minutes'
});
app.use('/api/', limiter);

// Logging
app.use(morgan('combined'));   // Format Apache
app.use(morgan('dev'));        // Format compact coloré
—The Gardener