Node.js

Créer une API REST avec Express.js : Guide Pratique

Mark Toledo

Mark Toledo

8 janvier 2025

Créer une API REST avec Express.js : Guide Pratique

Express.js est le framework Node.js le plus populaire pour créer des API REST. Léger mais puissant, il offre tout ce qu'il faut pour construire des backends robustes. Ce guide vous accompagne dans la création d'une API complète.

Installation et configuration

Initialisation du projet

mkdir mon-api
cd mon-api
npm init -y
npm install express
npm install --save-dev nodemon

Configuration de base

// app.js
const express = require('express');
const app = express();

// Middleware pour parser le JSON
app.use(express.json());

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

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Serveur démarré sur http://localhost:${PORT}`);
});

Ajoutez le script dans package.json :

{
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js"
  }
}

Les routes RESTful

Structure CRUD complète

// data.js - Données simulées
let utilisateurs = [
  { id: 1, nom: 'Alice', email: 'alice@exemple.fr' },
  { id: 2, nom: 'Bob', email: 'bob@exemple.fr' }
];

module.exports = { utilisateurs };

// routes/users.js
const express = require('express');
const router = express.Router();
const { utilisateurs } = require('../data');

// GET /api/users - Liste tous les utilisateurs
router.get('/', (req, res) => {
  res.json(utilisateurs);
});

// GET /api/users/:id - Un utilisateur par ID
router.get('/:id', (req, res) => {
  const id = parseInt(req.params.id);
  const user = utilisateurs.find(u => u.id === id);

  if (!user) {
    return res.status(404).json({ error: 'Utilisateur non trouvé' });
  }

  res.json(user);
});

// POST /api/users - Créer un utilisateur
router.post('/', (req, res) => {
  const { nom, email } = req.body;

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

  const newUser = {
    id: utilisateurs.length + 1,
    nom,
    email
  };

  utilisateurs.push(newUser);
  res.status(201).json(newUser);
});

// PUT /api/users/:id - Modifier un utilisateur
router.put('/:id', (req, res) => {
  const id = parseInt(req.params.id);
  const index = utilisateurs.findIndex(u => u.id === id);

  if (index === -1) {
    return res.status(404).json({ error: 'Utilisateur non trouvé' });
  }

  const { nom, email } = req.body;
  utilisateurs[index] = { ...utilisateurs[index], nom, email };

  res.json(utilisateurs[index]);
});

// DELETE /api/users/:id - Supprimer un utilisateur
router.delete('/:id', (req, res) => {
  const id = parseInt(req.params.id);
  const index = utilisateurs.findIndex(u => u.id === id);

  if (index === -1) {
    return res.status(404).json({ error: 'Utilisateur non trouvé' });
  }

  utilisateurs.splice(index, 1);
  res.status(204).send();
});

module.exports = router;

Intégration dans l'application

// app.js
const express = require('express');
const usersRouter = require('./routes/users');

const app = express();
app.use(express.json());

// Monter les routes
app.use('/api/users', usersRouter);

// Route racine
app.get('/', (req, res) => {
  res.json({
    message: 'API REST avec Express',
    endpoints: ['/api/users']
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`API démarrée sur http://localhost:${PORT}`);
});

Les Middlewares

Middleware de logging

// middlewares/logger.js
const logger = (req, res, next) => {
  const timestamp = new Date().toISOString();
  console.log(`[${timestamp}] ${req.method} ${req.url}`);
  next();
};

module.exports = logger;

// Utilisation
app.use(logger);

Middleware d'authentification

// middlewares/auth.js
const authMiddleware = (req, res, next) => {
  const token = req.headers.authorization;

  if (!token) {
    return res.status(401).json({ error: 'Token manquant' });
  }

  // Vérification simplifiée (utilisez JWT en production)
  if (token !== 'Bearer mon-token-secret') {
    return res.status(403).json({ error: 'Token invalide' });
  }

  // Ajouter l'utilisateur à la requête
  req.user = { id: 1, role: 'admin' };
  next();
};

module.exports = authMiddleware;

// Utilisation sur des routes spécifiques
router.get('/profile', authMiddleware, (req, res) => {
  res.json({ user: req.user });
});

Middleware de gestion d'erreurs

// middlewares/errorHandler.js
const errorHandler = (err, req, res, next) => {
  console.error(err.stack);

  const statusCode = err.statusCode || 500;
  const message = err.message || 'Erreur interne du serveur';

  res.status(statusCode).json({
    error: message,
    ...(process.env.NODE_ENV === 'development' && { stack: err.stack })
  });
};

module.exports = errorHandler;

// Utilisation (doit être le dernier middleware)
app.use(errorHandler);

Validation des données

Validation manuelle

const validateUser = (req, res, next) => {
  const { nom, email } = req.body;
  const errors = [];

  if (!nom || nom.length < 2) {
    errors.push('Le nom doit contenir au moins 2 caractères');
  }

  if (!email || !email.includes('@')) {
    errors.push('Email invalide');
  }

  if (errors.length > 0) {
    return res.status(400).json({ errors });
  }

  next();
};

router.post('/', validateUser, (req, res) => {
  // Logique de création...
});

Avec express-validator

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

const userValidationRules = [
  body('nom')
    .trim()
    .isLength({ min: 2 })
    .withMessage('Le nom doit contenir au moins 2 caractères'),
  body('email')
    .isEmail()
    .normalizeEmail()
    .withMessage('Email invalide')
];

const validate = (req, res, next) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(400).json({ errors: errors.array() });
  }
  next();
};

router.post('/', userValidationRules, validate, (req, res) => {
  // Création de l'utilisateur...
});

CORS et sécurité

npm install cors helmet
const cors = require('cors');
const helmet = require('helmet');

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

// CORS - Autoriser les requêtes cross-origin
app.use(cors({
  origin: ['http://localhost:3000', 'https://monsite.fr'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

Structure de projet recommandée

mon-api/
├── app.js              # Point d'entrée
├── package.json
├── routes/
│   ├── index.js        # Agrégateur de routes
│   ├── users.js
│   └── products.js
├── middlewares/
│   ├── auth.js
│   ├── logger.js
│   └── errorHandler.js
├── controllers/        # Logique métier
│   └── userController.js
├── models/             # Modèles de données
│   └── User.js
├── validators/         # Règles de validation
│   └── userValidator.js
└── config/
    └── database.js

Bonnes pratiques

  1. Codes HTTP appropriés : 200 (OK), 201 (Created), 204 (No Content), 400 (Bad Request), 401 (Unauthorized), 404 (Not Found), 500 (Server Error)

  2. Versioning de l'API : /api/v1/users

  3. Pagination pour les listes :

router.get('/', (req, res) => {
  const page = parseInt(req.query.page) || 1;
  const limit = parseInt(req.query.limit) || 10;
  const startIndex = (page - 1) * limit;

  const results = utilisateurs.slice(startIndex, startIndex + limit);

  res.json({
    data: results,
    pagination: {
      page,
      limit,
      total: utilisateurs.length,
      pages: Math.ceil(utilisateurs.length / limit)
    }
  });
});
  1. Variables d'environnement :
npm install dotenv
require('dotenv').config();
const PORT = process.env.PORT || 3000;

Conclusion

Express.js offre une base solide pour créer des API REST professionnelles. Avec une bonne organisation, des middlewares bien pensés et une validation rigoureuse, vous pouvez construire des backends robustes et maintenables.

Dans les prochains articles, nous verrons comment connecter une base de données et implémenter l'authentification JWT.