Protocole HTTP
Le protocole HTTP (HyperText Transfer Protocol) est le fondement de toute communication sur le web. Comprendre son fonctionnement est essentiel pour concevoir et déboguer des API.
Communication : Requête / Réponse
Toute interaction HTTP suit un schéma simple :
- Un client envoie une requête à un serveur
- Le serveur effectue un traitement
- Le serveur renvoie une réponse au client
Composition d'une requête
Une requête HTTP contient :
| Élément | Description | Exemple |
|---|---|---|
| Méthode | L'action à effectuer | GET, POST, PUT, DELETE |
| URL (endpoint) | L'adresse de la ressource | /api/books/42 |
| Headers | Métadonnées de la requête | Content-Type: application/json |
| Body | Contenu de la requête (optionnel) | {"title": "Mon livre"} |
| Params | Partie dynamique de l'URL | /books/:id → /books/42 |
| Query | Filtres et options | ?page=2&limit=10 |
| Cookies | Données stockées côté client | session_id=abc123 |
Composition d'une réponse
Une réponse HTTP contient :
| Élément | Description | Exemple |
|---|---|---|
| Statut | Code indiquant le résultat | 200 OK, 404 Not Found |
| Headers | Métadonnées de la réponse | Cache-Control: max-age=3600 |
| Body | Contenu de la réponse | {"id": 42, "title": "Mon livre"} |
Méthodes HTTP
Les méthodes HTTP sont des verbes d'action qui indiquent au serveur quelle opération effectuer sur la ressource.
| Méthode | Action | Body ? | Idempotent ? |
|---|---|---|---|
| GET | Récupérer une ressource | Non | Oui |
| POST | Créer une ressource | Oui | Non |
| PUT | Remplacer intégralement une ressource | Oui | Oui |
| PATCH | Modifier partiellement une ressource | Oui | Non |
| DELETE | Supprimer une ressource | Non | Oui |
Idempotence
Une opération est idempotente si l'exécuter plusieurs fois produit le même résultat que l'exécuter une seule fois. GET /books/1 renvoie toujours le même livre. DELETE /books/1 supprime le livre une fois ; les appels suivants ne changent rien (la ressource est déjà supprimée).
POST n'est pas idempotent : chaque appel peut créer une nouvelle ressource.
Exemple avec Flask
from flask import Flask, Blueprint, request, jsonify
books_bp = Blueprint('books', __name__, url_prefix='/api/books')
@books_bp.route('', methods=['GET'])
def get_books():
"""GET /api/books - Récupérer tous les livres"""
return jsonify(books), 200
@books_bp.route('/<int:book_id>', methods=['GET'])
def get_book(book_id: int):
"""GET /api/books/:id - Récupérer un livre"""
book = find_book(book_id)
if not book:
return jsonify({"error": "Livre non trouvé"}), 404
return jsonify(book), 200
@books_bp.route('', methods=['POST'])
def create_book():
"""POST /api/books - Créer un livre"""
data = request.get_json()
new_book = create_new_book(data)
return jsonify(new_book), 201
@books_bp.route('/<int:book_id>', methods=['PUT'])
def update_book(book_id: int):
"""PUT /api/books/:id - Remplacer un livre"""
data = request.get_json()
updated = replace_book(book_id, data)
return jsonify(updated), 200
@books_bp.route('/<int:book_id>', methods=['DELETE'])
def delete_book(book_id: int):
"""DELETE /api/books/:id - Supprimer un livre"""
remove_book(book_id)
return '', 204
Quelle méthode HTTP est idempotente ?
Body de requête
Le body est le contenu envoyé avec une requête. Il n'est jamais présent dans les requêtes GET et DELETE.
Types de body courants
| Content-Type | Usage |
|---|---|
application/json | Le plus courant pour les API REST |
application/x-www-form-urlencoded | Formulaires HTML classiques |
multipart/form-data | Upload de fichiers |
text/plain | Texte brut |
Le type du body est indiqué par le header Content-Type.
from pydantic import BaseModel
class CreateBookDTO(BaseModel):
title: str
author: str
year: int
@books_bp.route('', methods=['POST'])
def create_book():
data = request.get_json()
# Validation avec Pydantic
dto = CreateBookDTO(**data)
# dto.title, dto.author, dto.year sont typés et validés
new_book = book_service.create(dto)
return jsonify(new_book), 201
Params (paramètres de route)
Les params sont des segments dynamiques de l'URL, utilisés pour identifier une ressource précise.
GET /api/books/1520
^^^^
param "id" = 1520
Avec Flask, les params sont définis dans la route avec la syntaxe <type:nom> :
@books_bp.route('/<int:book_id>', methods=['GET'])
def get_book(book_id: int):
# book_id vaut 1520 pour GET /api/books/1520
book = book_service.get_by_id(book_id)
if not book:
return jsonify({"error": "Livre non trouvé"}), 404
return jsonify(book), 200
Query (paramètres de requête)
Les query parameters permettent de filtrer, trier ou paginer une collection. Ils sont optionnels et ne servent qu'à réduire le champ des résultats.
GET /api/books?authorID=5&sortBy=publishedAt&sortDirection=ASC&offset=20&limit=10
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
query string
Les query parameters sont :
- Précédés de
? - Composés de couples clé=valeur
- Séparés par
&
@books_bp.route('', methods=['GET'])
def get_books():
# Récupération des query params avec des valeurs par défaut
author_id = request.args.get('authorID', type=int)
sort_by = request.args.get('sortBy', default='id', type=str)
sort_dir = request.args.get('sortDirection', default='ASC', type=str)
offset = request.args.get('offset', default=0, type=int)
limit = request.args.get('limit', default=20, type=int)
books = book_service.find_all(
author_id=author_id,
sort_by=sort_by,
sort_direction=sort_dir,
offset=offset,
limit=limit
)
return jsonify(books), 200
Query en frontend
La query string est également très utilisée côté frontend pour partager des liens de recherche ou ne pas perdre l'état lors d'un rafraîchissement de page. Par exemple, une URL comme /search?q=flask&page=2 permet de retrouver exactement la même recherche.
Dans l'URL GET /api/users/42?role=admin, quels sont respectivement le param et la query ?
HTTP Headers
Les headers sont des métadonnées envoyées avec les requêtes et les réponses. Ils transmettent des informations contextuelles sur la communication.
Headers de requête courants
| Header | Rôle | Exemple |
|---|---|---|
Content-Type | Type du body envoyé | application/json |
Authorization | Authentification | Bearer eyJhbGciOi... |
Accept | Type de réponse attendu | application/json |
User-Agent | Identification du client | Mozilla/5.0... |
Headers de réponse courants
| Header | Rôle | Exemple |
|---|---|---|
Content-Type | Type du body renvoyé | application/json |
Cache-Control | Politique de cache | max-age=3600 |
Set-Cookie | Définir un cookie | session=abc123; HttpOnly |
Access-Control-Allow-Origin | CORS | https://monsite.com |
from flask import make_response
@books_bp.route('/<int:book_id>', methods=['GET'])
def get_book(book_id: int):
book = book_service.get_by_id(book_id)
if not book:
return jsonify({"error": "Livre non trouvé"}), 404
response = make_response(jsonify(book), 200)
response.headers['Cache-Control'] = 'max-age=300'
return response
À retenir
Points clés
- HTTP fonctionne en requête/réponse entre un client et un serveur
- Les méthodes HTTP (GET, POST, PUT, PATCH, DELETE) définissent l'action à effectuer
- Le body contient les données envoyées (jamais avec GET ou DELETE)
- Les params identifient une ressource précise dans l'URL (
/books/42) - La query string filtre, trie ou pagine une collection (
?page=2&limit=10) - Les headers transmettent des métadonnées (authentification, type de contenu, cache)