🗄️ Mini-Projet — API Articles avec Persistance JSON

API REST avec persistance sur disque via la classe JsonDB — les données survivent aux redémarrages du serveur.

Aperçu

Ce mini-projet démontre la persistance des données sans base de données externe. La classe JsonDB lit et écrit dans db.json à chaque opération CRUD. Au démarrage, si la base est vide, 3 articles de seed sont insérés automatiquement.

JSON
Persistance fichier
3009
Port
0
Dépendances externes

Classe JsonDB — Explication

La classe JsonDB encapsule toutes les opérations fichier. Elle est instanciée une seule fois au démarrage et partagée par toutes les routes.

  • constructor(filename) — charge le fichier en mémoire dans this.data
  • _load() — lit + parse le JSON, retourne {"{ articles: [] }"} en cas d'erreur
  • _save() — sérialise this.data et l'écrit sur le disque
  • findAll() — retourne le tableau articles
  • findById(id) — cherche avec .find() et parseInt(id)
  • insert(article) — auto-increment ID + createdAt + push + save
  • update(id, data) — merge spread + save
  • delete(id) — filter + save, retourne bool
class JsonDB {
  constructor(filename) {
    this.filepath = path.join(__dirname, filename);
    this.data = this._load();
  }
  _load() {
    try { return JSON.parse(fs.readFileSync(this.filepath, 'utf-8')); }
    catch { return { articles: [] }; }
  }
  _save() { fs.writeFileSync(this.filepath, JSON.stringify(this.data, null, 2)); }
  findAll()   { return this.data.articles; }
  findById(id){ return this.data.articles.find(a => a.id === parseInt(id)); }
  insert(article) {
    const ids = this.data.articles.map(a => a.id);
    article.id = ids.length ? Math.max(...ids) + 1 : 1;
    article.createdAt = new Date().toISOString();
    this.data.articles.push(article);
    this._save();
    return article;
  }
  // update() et delete() similaires...
}

server.js — Routes Express

const db = new JsonDB('db.json');

// Seed automatique si vide
if (db.findAll().length === 0) {
  ['Node.js et les streams', 'Express middleware', 'JWT auth'].forEach((titre, i) => {
    db.insert({ titre, auteur: 'Formateur', contenu: 'Contenu ' + (i+1), tags: ['nodejs'] });
  });
}

app.get('/articles',     (req, res) => res.json({ success: true, data: db.findAll() }));
app.get('/articles/:id', (req, res) => {
  const a = db.findById(req.params.id);
  if (!a) return res.status(404).json({ success: false, error: 'Article introuvable' });
  res.json({ success: true, data: a });
});
app.post('/articles', (req, res) => {
  const { titre, auteur } = req.body;
  if (!titre || !auteur) return res.status(400).json({ success: false, error: 'titre et auteur requis' });
  res.status(201).json({ success: true, data: db.insert(req.body) });
});
app.put('/articles/:id', (req, res) => {
  const a = db.update(req.params.id, req.body);
  if (!a) return res.status(404).json({ success: false, error: 'Article introuvable' });
  res.json({ success: true, data: a });
});
app.delete('/articles/:id', (req, res) => {
  if (!db.delete(req.params.id)) return res.status(404).json({ success: false, error: 'Article introuvable' });
  res.status(204).send();
});

Endpoints

Méthode URL Body Description
GET/articlesLister tous les articles (depuis db.json)
GET/articles/:idRécupérer un article par ID
POST/articles{ titre, auteur, contenu }Créer (persiste immédiatement)
PUT/articles/:id{ ... }Mise à jour complète
DELETE/articles/:idSupprimer (204 No Content)

Exemples curl

# Démarrer
npm install && node server.js

# Lister les articles (seed automatique)
curl http://localhost:3009/articles

# Créer un article
curl -X POST http://localhost:3009/articles \
  -H "Content-Type: application/json" \
  -d '{"titre":"Mon article","auteur":"Alice","contenu":"Contenu ici"}'

# Modifier
curl -X PUT http://localhost:3009/articles/1 \
  -H "Content-Type: application/json" \
  -d '{"titre":"Titre modifié","auteur":"Alice","contenu":"Nouveau contenu"}'

# Supprimer
curl -X DELETE http://localhost:3009/articles/2
# → 204 No Content (fichier db.json mis à jour)
← Cours N09 Exercices N09 →