TP : Création d'une API REST avec Express.js

⏱️ Durée : 1h30

Objectifs pédagogiques :

  • Comprendre et implémenter des middlewares Express
  • Créer des routes RESTful pour une ressource
  • Gérer les différentes méthodes HTTP (GET, POST, PATCH, DELETE)
  • Structurer une API REST simple

Partie 1 : Initialisation du projet

1.1 Création du projet

# Créer le dossier du projet
mkdir tp-express-api
cd tp-express-api
npm init -y
npm install express
npm install -D nodemon

1.2 Structure du projet

tp-express-api/
├── package.json
├── server.js
└── data/
└── posts.json

1.3 Configuration package.json

Modifiez le fichier package.json pour ajouter les scripts :

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

1.4 Données initiales

Créez le fichier data/posts.json :

[
  {
    "id": 1,
    "title": "Introduction à Express.js",
    "content": "Express est un framework web minimaliste pour Node.js",
    "author": "Ahmed",
    "createdAt": "2024-01-15T10:00:00Z"
  },
  {
    "id": 2,
    "title": "Les API REST",
    "content": "REST est un style architectural pour les services web",
    "author": "Fatima",
    "createdAt": "2024-01-16T14:30:00Z"
  }
]

Partie 2 : Mise en place du serveur Express

2.1 Serveur de base

Créez le fichier server.js :

const express = require('express');
const fs = require('fs').promises;
const path = require('path');

const app = express();
const PORT = 3000;

// TODO: Ajouter le middleware pour parser le JSON

// TODO: Démarrer le serveur sur le port 3000

2.2 Middleware de logging

Ajoutez un middleware personnalisé pour logger les requêtes :

// TODO: Créer un middleware qui log la date, la méthode HTTP et l'URL
// Format attendu: [2024-01-15T10:00:00.000Z] GET /api/posts

2.3 Fonctions utilitaires

Ajoutez ces fonctions pour gérer les données :

// Chemin vers le fichier de données
const POSTS_FILE = path.join(__dirname, 'data', 'posts.json');
// TODO: Implémenter la fonction readPosts()
// Cette fonction doit lire le fichier posts.json et retourner un tableau d'objets
async function readPosts() {
    // TODO
}

// TODO: Implémenter la fonction writePosts(posts)
// Cette fonction doit écrire le tableau posts dans le fichier posts.json
async function writePosts(posts) {
    // TODO
}

// TODO: Implémenter la fonction getNextId()
// Cette fonction doit retourner le prochain ID disponible
async function getNextId() {
    // TODO
}

Partie 3 : Implémentation des routes CRUD

3.1 GET /api/posts - Récupérer tous les posts

// TODO: Créer la route GET /api/posts
// Cette route doit retourner tous les posts au format :
// {
//   success: true,
//   count: nombre_de_posts,
//   data: [array_des_posts]
// }

3.2 GET /api/posts/:id - Récupérer un post par ID

// TODO: Créer la route GET /api/posts/:id
// Cette route doit :
// - Récupérer l'ID depuis req.params.id
// - Chercher le post correspondant
// - Retourner 404 si non trouvé
// - Retourner le post si trouvé

3.3 POST /api/posts - Créer un nouveau post

D'abord, créez un middleware de validation :

// TODO: Créer le middleware validatePost
// Ce middleware doit vérifier que title, content et author sont présents
// Si non, retourner une erreur 400
const validatePost = (req, res, next) => {
    // TODO
};

Puis, créez la route POST :

// TODO: Créer la route POST /api/posts avec le middleware validatePost
// Cette route doit :
// - Créer un nouveau post avec un ID généré
// - Ajouter createdAt avec la date actuelle
// - Sauvegarder dans le fichier
// - Retourner le post créé avec status 201

3.4 PATCH /api/posts/:id - Mettre à jour un post

// TODO: Créer la route PATCH /api/posts/:id
// Cette route doit :
// - Permettre la mise à jour partielle
// - Ne pas permettre la modification de l'ID
// - Ajouter un champ updatedAt
// - Retourner 404 si le post n'existe pas

3.5 DELETE /api/posts/:id - Supprimer un post

// TODO: Créer la route DELETE /api/posts/:id
// Cette route doit :
// - Supprimer le post correspondant à l'ID
// - Retourner 404 si le post n'existe pas
// - Retourner un message de succès si supprimé

3.6 Middleware de gestion des routes non trouvées

// TODO: Ajouter un middleware pour gérer les routes non trouvées
// Ce middleware doit retourner une erreur 404
// IMPORTANT: Ce middleware doit être placé en dernier

Partie 4 : Tests et validation

4.1 Fichier de test HTTP

Créez un fichier test.http pour tester votre API avec l'extension REST Client :

### Variables
@baseUrl = http://localhost:3000/api/posts

### Récupérer tous les posts
GET {{baseUrl}}

### Récupérer un post spécifique
GET {{baseUrl}}/1

### Créer un nouveau post
POST {{baseUrl}}
Content-Type: application/json

{
    "title": "Mon nouveau post",
    "content": "Contenu intéressant sur Express.js",
    "author": "Youssef"
}

### Mettre à jour un post
PATCH {{baseUrl}}/1
Content-Type: application/json

{
    "title": "Titre modifié"
}

### Supprimer un post
DELETE {{baseUrl}}/2

### Tester une route inexistante
GET http://localhost:3000/route-inexistante

### Tester POST sans données (devrait retourner 400)
POST {{baseUrl}}
Content-Type: application/json

{}

### Tester GET avec ID inexistant (devrait retourner 404)
GET {{baseUrl}}/999

Exercices supplémentaires

Exercice 1 : Pagination

Ajoutez la pagination à la route GET /api/posts avec les paramètres limit et page.

Exemple : /api/posts?limit=10&page=2

Exercice 2 : Filtrage

Permettez le filtrage par auteur.

Exemple : /api/posts?author=Ahmed

Exercice 3 : Tri

Ajoutez le tri par date de création.

Exemple : /api/posts?sort=createdAt&order=desc

Exercice 4 : Middleware d'authentification

Créez un middleware simple qui vérifie la présence d'un header X-API-Key.