API REST en Node.js / Express connectée à MySQL, organisée en couches pour séparer les responsabilités. Un frontend React permet de gérer les utilisateurs via une interface CRUD.
Application React accessible sur http://localhost:5173, connectée à l'API Express sur http://localhost:4000.
Affichage de la liste (Read) et formulaire pour ajouter un utilisateur (Create).
Clic sur « Modifier » : le formulaire passe en mode édition avec les données pré-remplies (Update).
Clic sur « Supprimer » : une boîte de dialogue demande confirmation avant la suppression (Delete).
Les captures sont servies via jsDelivr CDN depuis le dépôt GitHub, afin qu'elles s'affichent même hors clone du projet ou avec filtrage réseau.
Construire une API CRUD sur la ressource users en appliquant une architecture claire :
- Routes → définissent les URLs et les verbes HTTP
- Controllers → gèrent la requête HTTP et la réponse
- Services → contiennent la logique métier et les requêtes SQL
- Config → centralise la connexion à la base de données
expressbonpratique/
├── app.js # Point d'entrée, configuration Express
├── client/ # Frontend React (Vite)
│ ├── src/
│ │ ├── api/users.js # Appels fetch vers l'API
│ │ ├── App.jsx # Interface CRUD
│ │ └── main.jsx
│ └── package.json
├── config/
│ └── db.js # Pool de connexion MySQL
├── routes/
│ └── user.routes.js # Définition des routes /users
├── controllers/
│ └── user.controller.js # Traitement des requêtes HTTP
├── services/
│ └── user.service.js # Logique métier + requêtes SQL
├── screens/
│ ├── image.png # Vue principale (liste + création)
│ ├── modification.png # Mode modification
│ └── confirmation-suppression.png # Confirmation avant delete
└── package.json
Chaque couche a un rôle précis :
| Couche | Rôle | Exemple |
|---|---|---|
routes |
Associe une URL + méthode HTTP à une fonction | GET /users → getUsers |
controllers |
Lit req, appelle le service, renvoie res |
res.json(users) |
services |
Parle à la base de données, retourne des données | SELECT * FROM users |
config |
Configuration réutilisable (connexion DB) | Pool MySQL |
Le controller ne contient pas de SQL. Le service ne connaît pas Express (
req/res).
app.use(express.json()); // Parse le body JSON des requêtes POST/PUT
app.use('/api', userRoutes); // Préfixe commun pour toutes les routes users
app.listen(4000); // Serveur sur le port 4000express.json()est indispensable pour lire{ "name": "...", "email": "..." }dans le body.app.use('/api', ...)regroupe les routes sous/api/users,/api/users/:id, etc.
const router = express.Router();
router.get('/users', userController.getUsers);
module.exports = router;Le router isole les routes d'une ressource. On l'importe dans app.js avec un préfixe (/api).
| Méthode | Route | Action | Code réponse |
|---|---|---|---|
GET |
/api/users |
Lister tous les users | 200 |
GET |
/api/users/:id |
Récupérer un user par ID | 200 / 404 |
POST |
/api/users |
Créer un user | 201 |
PUT |
/api/users/:id |
Modifier un user | 200 / 404 |
DELETE |
/api/users/:id |
Supprimer un user | 204 / 404 |
:idest un paramètre dynamique, accessible viareq.params.id.404est renvoyé quand l'utilisateur n'existe pas.204 No Contentest la réponse standard après une suppression réussie.
const db = mysql.createPool({ host, user, password, database });- Pool : réutilise les connexions au lieu d'en ouvrir une nouvelle à chaque requête (meilleures performances).
/promise: permet d'utiliserasync/awaitau lieu des callbacks.
const [rows] = await db.query('SELECT * FROM users WHERE id = ?', [id]);- Les
?sont des requêtes préparées : protection contre les injections SQL. db.query()retourne un tableau[rows, fields]→ on destructure avec[rows].
Toutes les fonctions qui touchent la base sont async. On attend le résultat avec await :
async function getUsers(req, res) {
const users = await userService.getAllUsers();
res.json(users);
}Sans async/await, Express ne capturerait pas les erreurs asynchrones correctement.
Créer la base et la table dans phpMyAdmin ou en SQL :
CREATE DATABASE projetexpress;
USE projetexpress;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL
);# Installer les dépendances
npm install
# Lancer en mode développement (rechargement auto avec nodemon)
npm run dev
# Lancer en mode production
npm startLe serveur démarre sur http://localhost:4000.
Utiliser
npm run devplutôt quenodemon app.jsdirectement : nodemon est installé localement dans le projet.
Dans un second terminal :
cd client
npm install
npm run devL'interface est accessible sur http://localhost:5173.
Le frontend consomme l'API Express via fetch et permet de :
| Action | Interface | Capture |
|---|---|---|
| Read — lister | Tableau « Liste des utilisateurs » | image.png |
| Create — créer | Formulaire « Ajouter un utilisateur » | image.png |
| Update — modifier | Formulaire « Modifier un utilisateur » | modification.png |
| Delete — supprimer | Dialogue de confirmation | confirmation-suppression.png |
# Lister tous les utilisateurs
curl http://localhost:4000/api/users
# Récupérer un utilisateur
curl http://localhost:4000/api/users/1
# Créer un utilisateur
curl -X POST http://localhost:4000/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Alice","email":"[email protected]"}'
# Modifier un utilisateur
curl -X PUT http://localhost:4000/api/users/1 \
-H "Content-Type: application/json" \
-d '{"name":"Alice Martin","email":"[email protected]"}'
# Supprimer un utilisateur
curl -X DELETE http://localhost:4000/api/users/1Importer les mêmes routes en sélectionnant la bonne méthode HTTP et en ajoutant un body JSON pour POST et PUT.
Client
│
▼
app.js → app.use('/api', userRoutes)
│
▼
user.routes.js → router.get('/users/:id', getUserById)
│
▼
user.controller → lit req.params.id, appelle le service
│
▼
user.service → SELECT * FROM users WHERE id = ?
│
▼
config/db.js → pool MySQL
│
▼
Réponse JSON ← res.json(user) ou res.status(404).json(...)
| Package | Rôle |
|---|---|
express |
Framework web, gestion des routes et requêtes HTTP |
mysql2 |
Driver MySQL avec support des promesses |
nodemon |
Redémarre le serveur automatiquement en dev |


