Cours APIs REST Complet 🔌
Les 12 chapitres essentiels — HTTP, CRUD, authentification, pagination et documentation
7. Validation et erreurs
2. Le protocole HTTP
8. Authentification
3. Conception d'une API REST
9. Pagination, tri et filtrage
4. CRUD en pratique (Node.js)
10. Documentation (OpenAPI)
5. CRUD en pratique (Python)
11. Sécurité
6. Codes de statut HTTP
12. Bonnes pratiques
🏠 Hub Programmation
⚡ JavaScript
🟢 Node.js
🐍 Python
🎸 Django
🧪 Flask
Introduction : qu'est-ce qu'une API REST ?
# 1. Le client (app mobile) envoie une REQUÊTE
POST /api/orders
# 2. Le serveur traite la requête et renvoie une RÉPONSE
201 Created
API (Application Programming Interface) = un contrat entre deux logiciels. REST (Representational State Transfer) = un style d'architecture pour les APIs web, défini par Roy Fielding en 2000. Le client et le serveur communiquent via HTTP en échangeant du JSON. Chaque URL représente une ressource (utilisateur, produit, commande). Les actions sont définies par les méthodes HTTP (GET, POST, PUT, DELETE).
| Contrainte | Signification |
|---|---|
| Client-Serveur | Séparation des responsabilités (front ≠ back) |
| Sans état (Stateless) | Chaque requête contient toute l'info nécessaire (pas de session serveur) |
| Cache | Les réponses peuvent être mises en cache (headers Cache-Control) |
| Interface uniforme | URLs cohérentes, méthodes HTTP standard, JSON |
| Système en couches | Load balancer, cache, gateway — transparent pour le client |
| Code à la demande | (Optionnel) Le serveur peut envoyer du code exécutable |
Le protocole HTTP
GET /api/users/42 HTTP/1.1 ← Méthode + URL + Version
Host: api.example.com ← Headers
Authorization: Bearer eyJhbGc…
Accept: application/json
Content-Type: application/json
# RÉPONSE
HTTP/1.1 200 OK ← Status code + Message
Content-Type: application/json ← Headers
Cache-Control: max-age=3600
X-Total-Count: 150
| Méthode | Action | Idempotent | Body | Exemple |
|---|---|---|---|---|
| GET | Lire | ✅ Oui | Non | Récupérer un utilisateur |
| POST | Créer | ❌ Non | Oui | Créer un utilisateur |
| PUT | Remplacer (tout) | ✅ Oui | Oui | Remplacer toutes les infos |
| PATCH | Modifier (partiel) | ❌ Non | Oui | Modifier juste le nom |
| DELETE | Supprimer | ✅ Oui | Non | Supprimer un utilisateur |
Idempotent = même résultat si on répète la requête. GET /users/42 retourne toujours le même utilisateur. DELETE /users/42 supprime une fois — les appels suivants ne changent rien. POST /users crée un nouvel utilisateur à chaque appel — c'est pour ça qu'il n'est pas idempotent.
Conception d'une API REST
GET /api/users # Liste des utilisateurs
GET /api/users/42 # Un utilisateur
POST /api/users # Créer un utilisateur
PUT /api/users/42 # Remplacer l'utilisateur 42
PATCH /api/users/42 # Modifier partiellement
DELETE /api/users/42 # Supprimer l'utilisateur 42
# Ressources imbriquées
GET /api/users/42/posts # Posts de l'utilisateur 42
POST /api/users/42/posts # Créer un post pour l'utilisateur 42
GET /api/posts/7/comments # Commentaires du post 7
# Filtres et recherche (query parameters)
GET /api/users?role=admin&active=true
GET /api/posts?author=42&sort=-created_at
GET /api/products?q=laptop&min_price=500&max_price=2000
# Pagination
GET /api/posts?page=2&limit=20
❌ Mauvaises URLs : GET /getUsers, POST /createUser, DELETE /deleteUser/42. L'action est dans la méthode HTTP, pas dans l'URL. L'URL représente une ressource (nom, pluriel). Toujours en minuscules, kebab-case si nécessaire : /api/blog-posts.
| Règle | ✅ Correct | ❌ Incorrect |
|---|---|---|
| Noms, pas de verbes | /api/users | /api/getUsers |
| Pluriel | /api/products | /api/product |
| Minuscules + kebab-case | /api/blog-posts | /api/BlogPosts |
| Pas de trailing slash | /api/users | /api/users/ |
| Préfixe versionné | /api/v1/users | /users |
| Filtres en query params | ?role=admin | /api/users/admin |
CRUD en pratique (Node.js)
const express = require('express');
const app = express();
app.use(express.json()); // Parser le body JSON
let users = [
,
,
];
// GET /api/users — Liste
app.get('/api/users', (req, res) => );
// GET /api/users/:id — Détail
app.get('/api/users/:id', (req, res) => );
// POST /api/users — Créer
app.post('/api/users', (req, res) => );
// PATCH /api/users/:id — Modifier
app.patch('/api/users/:id', (req, res) => );
// DELETE /api/users/:id — Supprimer
app.delete('/api/users/:id', (req, res) => );
app.listen(3000, () => console.log('API sur http://localhost:3000'));
CRUD en pratique (Python)
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, EmailStr
app = FastAPI(title=« Mon API », version=« 1.0 »)
# Schéma de validation (Pydantic)
class UserCreate(BaseModel):
name: str
email: EmailStr
class User(UserCreate):
id: int
users_db: list[User] = [
User(id=1, name=« Alice », email=« alice@mail.com »),
User(id=2, name=« Bob », email=« bob@mail.com »),
]
@app.get(« /api/users », response_model=list[User])
def list_users():
return users_db
@app.get(« /api/users/ », response_model=User)
def get_user(user_id: int):
user = next((u for u in users_db if u.id == user_id), None)
if not user:
raise HTTPException(status_code=404, detail=« User not found »)
return user
@app.post(« /api/users », response_model=User, status_code=201)
def create_user(data: UserCreate):
user = User(id=len(users_db) + 1, **data.model_dump())
users_db.append(user)
return user
@app.delete(« /api/users/ », status_code=204)
def delete_user(user_id: int):
user = next((u for u in users_db if u.id == user_id), None)
if not user:
raise HTTPException(status_code=404, detail=« User not found »)
users_db.remove(user)
# Lancer : uvicorn main:app –reload
# Doc auto : http://localhost:8000/docs (Swagger UI)
FastAPI génère automatiquement la documentation Swagger à partir de vos types Pydantic et de vos routes. Accédez à /docs pour une interface interactive, et /redoc pour une doc plus lisible. La validation du body, des query params et des path params est automatique grâce au typage Python.
Codes de statut HTTP
| Code | Nom | Quand l'utiliser |
|---|---|---|
| 200 | OK | GET réussi, PATCH réussi |
| 201 | Created | POST réussi (ressource créée) |
| 204 | No Content | DELETE réussi (pas de body) |
| 301 | Moved Permanently | URL changée définitivement |
| 304 | Not Modified | Le cache est encore valide |
| 400 | Bad Request | Données invalides (validation) |
| 401 | Unauthorized | Pas authentifié (token manquant/invalide) |
| 403 | Forbidden | Authentifié mais pas autorisé (pas les droits) |
| 404 | Not Found | Ressource inexistante |
| 409 | Conflict | Conflit (email déjà pris, doublon) |
| 422 | Unprocessable Entity | Syntaxe OK mais sémantique invalide |
| 429 | Too Many Requests | Rate limit dépassé |
| 500 | Internal Server Error | Bug serveur (ne jamais exposer le détail) |
| 503 | Service Unavailable | Serveur en maintenance |
401 vs 403 : 401 = « Qui es-tu ? » (pas de token, ou token expiré). 403 = « Je sais qui tu es, mais tu n'as pas le droit » (rôle insuffisant). Un utilisateur normal qui tente d'accéder à /api/admin → 403, pas 401.
Validation et erreurs
// 404
// 500 — JAMAIS exposer le stack trace au client
Validez TOUJOURS l'input côté serveur, même si le client valide aussi. Bibliothèques recommandées : Zod (Node.js/TypeScript), Pydantic (Python/FastAPI), Joi (Node.js). Ne faites jamais confiance aux données du client — validez le type, la longueur, le format, et assainissez pour éviter les injections.
Authentification
POST /api/auth/login
// 2. Le serveur vérifie et renvoie un token JWT
200 OK
// 3. Le client envoie le token dans chaque requête
GET /api/users/me
Authorization: Bearer eyJhbGciOiJIUzI1NiIs…
// Structure d'un JWT (3 parties séparées par des .)
// HEADER.PAYLOAD.SIGNATURE
// Header :
// Payload :
// Signature : HMACSHA256(header + payload, SECRET_KEY)
| Méthode | Idéal pour | Stockage |
|---|---|---|
| JWT (Bearer Token) | APIs stateless, mobile, SPA | Client (localStorage/cookie) |
| Session + Cookie | Apps web server-side, MPA | Serveur (Redis/DB) |
| API Key | Service-to-service, APIs publiques | Header X-API-Key |
| OAuth 2.0 | « Connexion avec Google/GitHub » | Provider externe |
Ne stockez JAMAIS un JWT dans localStorage pour une app web (vulnérable aux attaques XSS). Préférez un cookie httpOnly + secure + sameSite. Pour les apps mobiles, utilisez le secure storage natif (Keychain iOS, EncryptedSharedPreferences Android).
Pagination, tri et filtrage
GET /api/posts?page=2&limit=20
// Réponse
// 2. Pagination par CURSOR (performante, pour les gros datasets)
GET /api/posts?limit=20&after=eyJpZCI6NDJ9
// Réponse
GET /api/posts?sort=-created_at # Plus récents d'abord
GET /api/posts?sort=price,-rating # Prix croissant, note décroissante
// Filtrage
GET /api/products?category=electronics&in_stock=true
GET /api/products?min_price=100&max_price=500
// Recherche
GET /api/products?q=laptop
// Sélection de champs (sparse fieldsets)
GET /api/users?fields=id,name,email # Retourne seulement ces champs
// Include (relations)
GET /api/posts?include=author,comments # Embarquer les relations
Documentation (OpenAPI)
openapi: « 3.0.0 »
info:
title: Mon API
version: « 1.0 »
description: API de gestion des utilisateurs
paths:
/api/users:
get:
summary: Liste des utilisateurs
parameters:
– name: page
in: query
schema:
– name: limit
in: query
schema:
responses:
« 200 »:
description: Liste paginée
post:
summary: Créer un utilisateur
requestBody:
required: true
content:
application/json:
schema:
$ref: « #/components/schemas/UserCreate »
responses:
« 201 »:
description: Utilisateur créé
| Outil | Rôle |
|---|---|
| Swagger UI | Interface interactive pour tester l'API (/docs) |
| Redoc | Documentation lisible et élégante (/redoc) |
| Postman | Client HTTP pour tester manuellement |
| Insomnia | Alternative à Postman (plus léger) |
| Bruno | Client API open-source (fichiers Git-friendly) |
Sécurité
// 2. Rate limiting — limiter les requêtes par IP/utilisateur
// Express : npm install express-rate-limit
const rateLimit = require('express-rate-limit');
app.use(rateLimit());
// 3. CORS — contrôler les origines autorisées
// Express : npm install cors
const cors = require('cors');
app.use(cors());
// 4. Helmet — headers de sécurité HTTP
// Express : npm install helmet
const helmet = require('helmet');
app.use(helmet());
// 5. Validation input (Zod)
// Ne jamais insérer de l'input utilisateur brut en SQL/NoSQL
// 6. Ne jamais exposer les erreurs internes
// ❌ res.status(500).json()
// ✅ res.status(500).json()
| Menace | Protection |
|---|---|
| Injection SQL/NoSQL | ORM (Prisma, Sequelize, SQLAlchemy) + validation input |
| XSS | Échapper les outputs, Content-Security-Policy |
| Brute force | Rate limiting, captcha, lockout après N échecs |
| CSRF | Cookie SameSite, CSRF token pour les formulaires |
| Man-in-the-middle | HTTPS obligatoire, HSTS |
| Données sensibles exposées | Ne jamais retourner le mot de passe, même hashé |
| Accès non autorisé | Vérifier les permissions sur chaque endpoint |
Bonnes pratiques
| Aspect | REST | GraphQL | gRPC |
|---|---|---|---|
| Format | JSON | JSON (query flexible) | Protocol Buffers (binaire) |
| Transport | HTTP | HTTP (POST unique) | HTTP/2 |
| Sur-fetching | Possible (retourne tout) | Non (le client choisit) | Non (schema strict) |
| N+1 requêtes | Possible | Résolu (1 requête) | N/A |
| Performance | Bonne | Bonne | Excellente (binaire) |
| Courbe | Simple | Moyenne | Complexe |
| Idéal pour | CRUD, APIs publiques | Apps complexes, mobile | Microservices internes |
✅ À FAIRE
• Noms de ressources au pluriel
• Codes de statut HTTP corrects
• Validation de tout input
• Pagination sur les listes
• Versionner l'API (/api/v1/)
• Format d'erreur cohérent
• HTTPS obligatoire
• Rate limiting
• Documenter avec OpenAPI
• CORS configuré correctement
❌ À ÉVITER
• Verbes dans les URLs (/getUsers)
• Retourner 200 pour les erreurs
• Exposer les stack traces au client
• Pas de pagination (listes infinies)
• Stocker JWT dans localStorage (web)
• Retourner les mots de passe
• SQL brut avec l'input utilisateur
• Ignorer CORS en prod
• API sans authentification ni rate limit
• Pas de documentation
🏠 Hub Programmation
🟢 Cours Node.js
🐍 Cours Python
🎸 Cours Django
🧪 Cours Flask
⚡ Cours JavaScript
🔷 Cours TypeScript
Cours APIs REST Complet — HTTP, CRUD, authentification, sécurité et documentation
Référence : OpenAPI Spec | MDN HTTP | FastAPI

