Intermédiaire

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 :

  1. Un client envoie une requête à un serveur
  2. Le serveur effectue un traitement
  3. Le serveur renvoie une réponse au client
Chargement du diagramme…

Composition d'une requête

Une requête HTTP contient :

ÉlémentDescriptionExemple
MéthodeL'action à effectuerGET, POST, PUT, DELETE
URL (endpoint)L'adresse de la ressource/api/books/42
HeadersMétadonnées de la requêteContent-Type: application/json
BodyContenu de la requête (optionnel){"title": "Mon livre"}
ParamsPartie dynamique de l'URL/books/:id/books/42
QueryFiltres et options?page=2&limit=10
CookiesDonnées stockées côté clientsession_id=abc123

Composition d'une réponse

Une réponse HTTP contient :

ÉlémentDescriptionExemple
StatutCode indiquant le résultat200 OK, 404 Not Found
HeadersMétadonnées de la réponseCache-Control: max-age=3600
BodyContenu 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éthodeActionBody ?Idempotent ?
GETRécupérer une ressourceNonOui
POSTCréer une ressourceOuiNon
PUTRemplacer intégralement une ressourceOuiOui
PATCHModifier partiellement une ressourceOuiNon
DELETESupprimer une ressourceNonOui

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

python
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-TypeUsage
application/jsonLe plus courant pour les API REST
application/x-www-form-urlencodedFormulaires HTML classiques
multipart/form-dataUpload de fichiers
text/plainTexte brut

Le type du body est indiqué par le header Content-Type.

python
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> :

python
@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 &
python
@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

HeaderRôleExemple
Content-TypeType du body envoyéapplication/json
AuthorizationAuthentificationBearer eyJhbGciOi...
AcceptType de réponse attenduapplication/json
User-AgentIdentification du clientMozilla/5.0...

Headers de réponse courants

HeaderRôleExemple
Content-TypeType du body renvoyéapplication/json
Cache-ControlPolitique de cachemax-age=3600
Set-CookieDéfinir un cookiesession=abc123; HttpOnly
Access-Control-Allow-OriginCORShttps://monsite.com
python
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)