Un laboratoire REST API local bien conçu permet d'explorer des idées en toute sécurité, d'inspecter le comportement de près et d'itérer rapidement. Vous pouvez tester des requêtes, valider des hypothèses et répéter des étapes opérationnelles sans risquer de perturber les systèmes de production. Ce guide fournit une configuration pratique de bout en bout utilisant Node.js et Express, avec une API petite mais réaliste, des étapes de vérification observables et des instructions claires pour la gestion des échecs et la récupération.
L'objectif est de créer un projet pilote étroit et mesurable qui s'exécute entièrement sur votre poste de travail, se lie uniquement à l'interface de boucle locale et expose quelques points de terminaison faciles à sonder avec curl. Vous vérifierez le succès avec des contrôles concrets, gérerez les échecs courants et terminerez avec une liste de contrôle reproductible que vous pourrez exécuter chaque fois que vous vous asseyez pour expérimenter.
Inventaire des versions et de l'environnement
Établissez votre environnement d'exécution et votre topologie dès le départ afin de pouvoir reproduire les résultats et éviter la dérive. Gardez le premier projet pilote simple : hôte unique, boucle locale, ports non privilégiés, stockage en mémoire et journalisation des requêtes.
Topologie
- Poste de travail unique, sans appels réseau externes.
- L'API se lie à 127.0.0.1:3000.
- Routes de simulation (mock-stub) optionnelles au sein du même processus pour les dépendances externes.
- Données en mémoire pour éviter la complexité de la persistance lors du premier passage.
Prérequis et vérifications des versions
Utilisez des outils que vous avez probablement déjà. Ciblez un environnement d'exécution LTS maintenu et confirmez les versions.
| Composant | Version d'exemple | Comment vérifier | Notes |
|---|---|---|---|
| Node.js | 18.x LTS ou 20.x LTS | node -v | Utilisez LTS pour la stabilité |
| npm | 9.x+ (inclus avec Node) | npm -v | Assure un comportement moderne des paquets |
| curl | 7.68+ | curl --version | Pour tests HTTP rapides |
| Git (optionnel) | 2.30+ | git --version | Pour retour facile en arrière |
| MongoDB (optionnel) | 6.x | mongod --version | Uniquement si vous ajoutez la persistance plus tard |
Chemin de configuration sécurisé
Choisissez des valeurs par défaut qui sont sûres, locales et réversibles.
- Périmètre : Commencez avec un magasin en mémoire et quelques points de terminaison (santé, CRUD articles, une interaction externe simulée). Cela limite les pièces mobiles tout en fournissant une réelle valeur opérationnelle.
- Liaison : Écoutez sur 127.0.0.1 (boucle locale) et un port non privilégié (3000). Cela évite d'exposer le laboratoire à votre réseau local ou de nécessiter des droits d'administrateur.
- Environnement : Gardez la configuration dans un fichier
.envlocal qui n'est pas validé dans les dépôts partagés. Utilisez des clés simples et évidentes commePORTetBIND_ADDRESS. - Validation et journalisation : Validez les entrées pour faire apparaître les erreurs tôt et journalisez les requêtes en verbosité développement pour rendre le comportement observable.
- Réversibilité : Gardez tous les fichiers dans un répertoire dédié. Si quelque chose casse, vous pouvez supprimer le dossier et le recréer en quelques minutes.
Implémentation : Construire l'API du laboratoire local
Cette implémentation utilise Node.js avec Express, dotenv pour la configuration, morgan pour la journalisation de développement et joi pour la validation des entrées.
1) Créer le projet
# Créer et entrer dans un répertoire de travail propre
mkdir rest-api-lab && cd rest-api-lab
# Confirmer Node et npm
node -v
npm -v
# Initialiser le projet et installer les dépendances
npm init -y
npm install express dotenv morgan joi
2) Ajouter la configuration
Créez un fichier .env à la racine du projet :
# .env
PORT=3000
BIND_ADDRESS=127.0.0.1
NODE_ENV=development
3) Implémenter l'API
Créez server.js avec une API REST minimale mais réaliste.
// server.js
require('dotenv').config();
const express = require('express');
const morgan = require('morgan');
const Joi = require('joi');
const { randomUUID } = require('crypto');
const app = express();
app.use(express.json());
app.use(morgan('dev'));
// Configuration
const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;
const BIND_ADDRESS = process.env.BIND_ADDRESS || '127.0.0.1';
// Magasin de données en mémoire
const items = [];
// Schéma de validation
const itemSchema = Joi.object({
name: Joi.string().min(1).max(100).required(),
price: Joi.number().min(0).precision(2).required()
});
// Point de terminaison santé
app.get('/health', (req, res) => {
res.status(200).json({
status: 'ok',
uptime_s: process.uptime(),
version: '1.0.0'
});
});
// Lister les articles
app.get('/items', (req, res) => {
res.json({ count: items.length, items });
});
// Créer un article
app.post('/items', (req, res, next) => {
const { error, value } = itemSchema.validate(req.body);
if (error) return res.status(400).json({ error: error.details[0].message });
const item = { id: randomUUID(), ...value, createdAt: new Date().toISOString() };
items.push(item);
res.status(201).json(item);
});
// Lire un article
app.get('/items/:id', (req, res) => {
const item = items.find(i => i.id === req.params.id);
if (!item) return res.status(404).json({ error: 'Not found' });
res.json(item);
});
// Mettre à jour un article (complet ou partiel)
app.put('/items/:id', (req, res) => {
const idx = items.findIndex(i => i.id === req.params.id);
if (idx === -1) return res.status(404).json({ error: 'Not found' });
// Valider si les champs existent
const schema = Joi.object({
name: Joi.string().min(1).max(100).optional(),
price: Joi.number().min(0).precision(2).optional()
}).min(1);
const { error, value } = schema.validate(req.body);
if (error) return res.status(400).json({ error: error.details[0].message });
items[idx] = { ...items[idx], ...value, updatedAt: new Date().toISOString() };
res.json(items[idx]);
});
// Supprimer un article
app.delete('/items/:id', (req, res) => {
const idx = items.findIndex(i => i.id === req.params.id);
if (idx === -1) return res.status(404).json({ error: 'Not found' });
const [removed] = items.splice(idx, 1);
res.status(200).json({ deleted: removed.id });
});
// Appel externe simulé (exemple construit)
app.post('/payments/charge', (req, res) => {
const schema = Joi.object({
amount: Joi.number().integer().min(1).required(),
currency: Joi.string().length(3).uppercase().required(),
source: Joi.string().required()
});
const { error, value } = schema.validate(req.body);
if (error) return res.status(400).json({ error: error.details[0].message });
// Simuler le succès sans appeler de services externes
res.status(200).json({
id: 'ch_' + randomUUID().replace(/-/g, '').slice(0, 24),
status: 'succeeded',
amount: value.amount,
currency: value.currency,
created: Math.floor(Date.now() / 1000)
});
});
// Gestionnaire non trouvé
app.use((req, res) => {
res.status(404).json({ error: 'Route not found' });
});
// Gestionnaire d'erreurs
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
});
app.listen(PORT, BIND_ADDRESS, () => {
console.log(`REST API lab listening on http://${BIND_ADDRESS}:${PORT}`);
});
4) Démarrer le serveur
node server.js
Sortie console attendue :
REST API lab listening on http://127.0.0.1:3000
Exemples pratiques : Requêtes et flux de travail
Utilisez curl pour exercer l'API. Ces exemples montrent à la fois la commande et un exemple de réponse afin que vous puissiez comparer vos résultats.
Vérification de santé
curl -i http://127.0.0.1:3000/health
Réponse attendue :
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"status":"ok","uptime_s":1.234,"version":"1.0.0"}
Créer un article
curl -i -X POST http://127.0.0.1:3000/items \
-H 'Content-Type: application/json' \
-d '{"name":"crayon","price":0.99}'
Réponse attendue :
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
{"id":"8b2...","name":"crayon","price":0.99,"createdAt":"2024-01-01T00:00:00.000Z"}
Lister les articles
curl -i http://127.0.0.1:3000/items
Réponse attendue :
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"count":1,"items":[{"id":"8b2...","name":"crayon","price":0.99,"createdAt":"2024-01-01T00:00:00.000Z"}]}
Lire un article
ITEM_ID=<coller-id-depuis-creation>
curl -i http://127.0.0.1:3000/items/$ITEM_ID
Attendu : 200 avec l'article JSON.
Mettre à jour un article
curl -i -X PUT http://127.0.0.1:3000/items/$ITEM_ID \
-H 'Content-Type: application/json' \
-d '{"price":1.25}'
Attendu : 200 avec les champs mis à jour et updatedAt.
Supprimer un article
curl -i -X DELETE http://127.0.0.1:3000/items/$ITEM_ID
Attendu : 200 avec {"deleted":"<id>"}.
Paiement simulé
curl -i -X POST http://127.0.0.1:3000/payments/charge \
-H 'Content-Type: application/json' \
-d '{"amount":500,"currency":"USD","source":"tok_visa"}'
Attendu : 200 avec un objet JSON contenant id, status, amount, currency, created.
Carte des points de terminaison
Une référence rapide à ce que vous avez mis en place :
| Méthode | Point de terminaison | Objectif | Code de succès |
|---|---|---|---|
| GET | /health | Santé du processus et version | 200 |
| GET | /items | Lister tous les articles | 200 |
| POST | /items | Créer un article | 201 |
| GET | /items/:id | Lire un article par id | 200 |
| PUT | /items/:id | Mettre à jour un article | 200 |
| DELETE | /items/:id | Supprimer un article | 200 |
| POST | /payments/charge | Appel de facturation externe simulé | 200 |
Vérification et diagnostics
La vérification porte sur des faits observables : processus en cours d'exécution, port ouvert, réponses attendues et journaux propres.
1) Processus et port
- Sur macOS/Linux :
ss -lntp | grep :3000 || lsof -iTCP:3000 -sTCP:LISTEN
- Sur Windows PowerShell :
netstat -ano | findstr :3000
Attendu : Un écouteur sur 127.0.0.1:3000 lié à votre processus Node.
2) Comportement des points de terminaison
- Chemin nominal :
/healthretourne 200 avec statut ok ;/itemsretourne 200 avec un compteur ;POST /itemsretourne 201 et un nouvel id. - Gestion d'erreurs :
POST /itemsavec nom ou prix manquant doit retourner 400 et un message d'erreur utile ;/items/:idavec un id inconnu retourne 404.
3) Journaux
Le journaliseur morgan dev doit imprimer une ligne par requête avec méthode, chemin, code de statut et temps de réponse. Des 500 inattendus ou des temps de réponse longs sont des signaux à investiguer.
4) Santé de la configuration
- Assurez-vous que
.envest chargé : définissez temporairementPORT=3001dans.env, redémarrez et vérifiez que les journaux du serveur affichent 3001. - Confirmez la liaison à la boucle locale : le serveur doit signaler
http://127.0.0.1:PORT, pas0.0.0.0.
Modes d'échec et récupération
Voici les problèmes courants et comment les résoudre.
| Symptôme | Cause probable | Correctif | Vérification |
|---|---|---|---|
| EADDRINUSE au démarrage | Port 3000 utilisé | Changer PORT dans .env ou arrêter l'autre processus | ss/lsof ou netstat montre seulement votre écouteur node |
| Impossible d'accéder à /health | Mauvais port ou hôte | Vérifier URL et PORT/BIND_ADDRESS ; redémarrer le serveur | curl retourne 200 avec statut ok |
| 400 sur POST /items | Entrée invalide | Envoyer nom et prix, JSON correct | 201 Created avec nouvel id |
| 404 sur /items/:id | Id inconnu | Utiliser l'id retourné par POST ou recréer | GET retourne 200 pour cet id |
| Erreurs 500 | Bug code ou validation | Vérifier journaux serveur ; ajouter console.error dans gestionnaire d'erreurs | Appels subséquents retournent 2xx/4xx attendus |
| Module non trouvé | Paquets manquants | npm install pour restaurer dépendances | Serveur démarre sans erreur |
| Fonctionnalités Node incorrectes | Dérive version Node | Utiliser LTS ; réinstaller ou changer version | node -v montre LTS cible |
Procédures de retour en arrière et de récupération
- Réinitialisation rapide : Arrêter le serveur (Ctrl+C), supprimer le répertoire
rest-api-labet recréer à partir des étapes de ce guide. - Restauration des dépendances : Supprimer
node_modulesetpackage-lock.json, puis exécuternpm install. - Restauration de la configuration : Revenir au
.envde base simple (PORT=3000,BIND_ADDRESS=127.0.0.1,NODE_ENV=development). - Restauration du code : Si vous avez utilisé Git,
git checkout -- .pour annuler les modifications locales depuis le dernier commit. - Contournement de conflit de port : Définir temporairement
PORT=0dansserver.jspour attribuer automatiquement un port libre, puis lire la console pour le port sélectionné et revenir plus tard au port fixe.
Liste de contrôle opérationnelle
Utilisez cette courte liste de contrôle pour exécuter votre laboratoire de manière cohérente.
| Étape | Action |
|---|---|
| 1 | Confirmer les versions Node et npm (node -v, npm -v) |
| 2 | Assurer un répertoire de travail propre et un .env simple |
| 3 | Installer les dépendances (npm install) |
| 4 | Démarrer le serveur (node server.js) |
| 5 | Vérifier la liaison de port (ss/lsof sur macOS/Linux, netstat sur Windows) |
| 6 | Exécuter les vérifications de base : /health, /items (vide), cycle créer-lire-mettre à jour-supprimer |
| 7 | Exercer le point de terminaison simulé /payments/charge |
| 8 | Inspecter les journaux pour codes de statut et temps |
| 9 | Capturer des notes sur le comportement et toute anomalie |
| 10 | Arrêter le serveur (Ctrl+C) et réinitialiser l'environnement si nécessaire |
Conclusion
Vous disposez maintenant d'un laboratoire REST API local sûr et observable qui s'exécute sur la boucle locale, utilise des ports non privilégiés et implémente un petit ensemble réaliste de points de terminaison. Les choix d'implémentation favorisent la simplicité, la réversibilité et des diagnostics clairs. Avec cette base, vous pouvez étendre prudemment : ajouter de la persistance en introduisant une base de données locale seulement lorsque nécessaire, en commençant par une seule collection ou table et des étapes de migration claires ; ajouter l'authentification en commençant par une simple vérification de jeton dans un middleware, puis étendre vers des contrôles plus robustes selon les besoins ; ajouter des intégrations externes en les gardant simulées localement jusqu'à ce que vous ayez des tests solides et des garde-fous, puis activer des appels contrôlés dans un environnement séparé et clairement identifié. Plus important encore, gardez chaque changement mesurable et facile à inspecter localement. Cette discipline réduit le retravail, améliore la confiance et aide les équipes à avancer plus vite avec moins de surprises.