Ta première API tourne, tu sais créer un endpoint basique. Mais une API en production, c’est bien plus que return {"hello": "world"}. Il faut des routes dynamiques, des paramètres typés, des filtres, de la pagination — et surtout une validation robuste des données entrantes.
C’est là que FastAPI brille vraiment. Grâce à Pydantic et aux type hints Python, tu décris la forme de tes données et FastAPI s’occupe du reste : validation, conversion, messages d’erreur, documentation. Zéro boilerplate.
Path parameters : des routes dynamiques
Au lieu de créer un endpoint par ressource, tu captures des valeurs directement dans l’URL. Le secret : le type hint. Sans lui, tout est string. Avec lui, FastAPI valide et convertit automatiquement.
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id}
# GET /users/42 → {"user_id": 42} ✅ converti en int
# GET /users/alice → 422 Unprocessable ❌ rejeté automatiquement
Tu peux imbriquer plusieurs paramètres dans une même route :
@app.get("/users/{user_id}/posts/{post_id}")
def get_user_post(user_id: int, post_id: int):
return {"user_id": user_id, "post_id": post_id}
# GET /users/1/posts/42 → {"user_id": 1, "post_id": 42}
FastAPI mappe chaque segment au bon argument de fonction, valide les types et renvoie une 422 claire si ça ne colle pas.
💡 L’ordre des routes compte. Si tu as /users/me et /users/{user_id}, déclare la route fixe avant la dynamique. Sinon FastAPI essaiera de parser "me" comme un int et renverra une 422.
Query parameters : filtrer et paginer
Tout paramètre de fonction qui n’apparaît pas dans le path est automatiquement traité comme query parameter. Pas besoin de décorateur spécial.
@app.get("/users/{user_id}/posts")
def get_user_posts(
user_id: int, # path param (obligatoire)
published: bool = True, # query param (optionnel)
limit: int = 10 # query param (optionnel)
):
return {"user_id": user_id, "published": published, "limit": limit}
# GET /users/1/posts?published=false&limit=5
# → {"user_id": 1, "published": false, "limit": 5}
FastAPI convertit "false" en False (bool), "5" en 5 (int). Pour un paramètre nullable, utilise Optional[int] = None — FastAPI comprend que None signifie “pas fourni”.
🔥 Pattern pagination standard : skip: int = 0, limit: int = 10. Utilise-le systématiquement sur tes endpoints de liste. Tes consommateurs d’API te remercieront.
Pydantic : la validation automatique
C’est le game-changer de FastAPI. Sans Pydantic, tu valides chaque champ à la main — if "name" not in data, if not isinstance(...), etc. Avec Pydantic, tu définis un modèle et FastAPI fait le reste.
from pydantic import BaseModel, Field, field_validator
from typing import Optional
class UserCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
email: str = Field(..., description="Email de l'utilisateur")
age: Optional[int] = Field(None, ge=0, le=150)
@field_validator("name")
@classmethod
def name_not_blank(cls, v):
if not v.strip():
raise ValueError("Le nom ne peut pas être vide")
return v.strip()
@app.post("/users", status_code=201)
def create_user(user: UserCreate):
return {"message": "Créé", "user": user}
Envoie un JSON valide → 201. Oublie email → 422 avec un message clair indiquant quel champ manque. Envoie age: "pas un nombre" → 422 avec “Input should be a valid integer”. Tout est automatique, plus jamais de validation manuelle.
Les modèles se composent
Les modèles Pydantic s’imbriquent naturellement. Un UserCreate peut contenir un sous-modèle Address, et FastAPI valide récursivement toute l’arborescence :
from enum import Enum
class Tier(str, Enum):
free = "free"
pro = "pro"
class Address(BaseModel):
city: str
country: str = "Suisse"
class UserCreate(BaseModel):
name: str
subscription: Tier = Tier.free
tags: list[str] = []
address: Optional[Address] = None
🎯 Sépare toujours les modèles d’entrée et de sortie. Un UserCreate (sans id) pour le POST, un UserResponse (avec id) pour le GET. Ça évite de leaker des champs internes (hash de mot de passe, etc.).
Cas pratique : API de produits complète
Voici un exemple qui combine tout — path params, query params, Pydantic, et headers. FastAPI lit les headers HTTP avec Header(), exactement comme les autres paramètres :
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from typing import Optional
app = FastAPI(title="API Produits")
products_db: list[dict] = []
next_id = 1
class ProductCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=200)
price: float = Field(..., gt=0, description="Prix en CHF")
category: str
in_stock: bool = True
@app.get("/products")
def list_products(
category: Optional[str] = None,
min_price: Optional[float] = None,
skip: int = 0,
limit: int = 10
):
results = products_db
if category:
results = [p for p in results if p["category"] == category]
if min_price is not None:
results = [p for p in results if p["price"] >= min_price]
return results[skip:skip + limit]
@app.post("/products", status_code=201)
def create_product(
product: ProductCreate,
x_api_key: str = Header(...) # header obligatoire
):
if x_api_key != "secret-key":
raise HTTPException(401, "Clé API invalide")
global next_id
new = {"id": next_id, **product.model_dump()}
products_db.append(new)
next_id += 1
return new
⚠️ L’auth par header ici est pédagogique. En production, utilise OAuth2 ou JWT — FastAPI a un module security dédié qu’on verra dans un chapitre ultérieur.
Lance l’API et va sur http://127.0.0.1:8000/docs — Swagger affiche les endpoints, les modèles avec leurs contraintes, et tu peux tester directement depuis le navigateur. Zéro configuration.
Les pièges courants
Valeur par défaut = optionnel. Si tu mets limit: int = 10, le paramètre est optionnel. Si tu veux le rendre obligatoire, pas de défaut : limit: int. Ça paraît évident, mais c’est la source de 50% des bugs “pourquoi mon filtre ne marche pas”.
422 ≠ 400. FastAPI renvoie 422 (Unprocessable Entity) pour les erreurs de validation, pas 400 (Bad Request). C’est conforme à la spec HTTP, mais certains clients legacy s’attendent à du 400 — documente-le.
model_dump() pas dict(). En Pydantic v2, la méthode .dict() est dépréciée. Utilise .model_dump() pour convertir un modèle en dictionnaire. Même chose : .json() → .model_dump_json().
Ne mets pas de logique métier dans les validators. Les field_validator servent à valider le format des données (email valide, âge positif). La logique métier (l’utilisateur existe-t-il déjà ?) appartient à la couche service, pas au modèle.
Oublie pas response_model. En ajoutant response_model=UserResponse à ton décorateur, FastAPI filtre automatiquement les champs renvoyés au client. Sans ça, tu risques de renvoyer des données internes (timestamps, hashs) que le consommateur ne devrait pas voir.
Enum pour les valeurs fixes. Si un champ n’accepte que quelques valeurs ("free", "pro", "enterprise"), utilise un Enum dans ton modèle Pydantic plutôt qu’un simple str. FastAPI affichera les valeurs autorisées dans la doc Swagger, et les erreurs seront bien plus explicites qu’un simple “invalid value”.
Ce qu’on retient
🎯 FastAPI transforme les type hints Python en validation automatique — c’est sa killer feature.
Les essentiels :
- Path params —
{user_id: int}dans l’URL, validé et converti automatiquement - Query params — tout argument non-path, avec valeur par défaut = optionnel
- Pydantic BaseModel — définis la forme des données, FastAPI valide tout seul
- Field + validators — contraintes fines (
min_length,gt,ge) et règles custom - Headers — lus avec
Header(), utiles pour l’auth et les métadonnées - La doc Swagger sur
/docsreflète automatiquement tous tes modèles et contraintes
Prochain chapitre : on construit un CRUD complet — créer, lire, mettre à jour, supprimer des ressources avec une vraie logique métier. 🚀
Contenu réservé aux abonnés
Ce chapitre fait partie de la formation complète. Abonne-toi pour débloquer tous les contenus.
Débloquer pour 29 CHF/moisLe chapitre 1 de chaque formation est gratuit.
Série pas encore débloquée
Termine la série prérequise d'abord pour accéder à ce contenu.
Aller à la série prérequiseSérie : Apprendre FastAPI
2 / 6Sur cette page
Articles liés
FastAPI : ta première API en Python
Comprends les APIs, le protocole HTTP, l'architecture REST, puis installe FastAPI et crée ton premier endpoint. Le socle pour tout ce qui suit.
Tests et documentation automatique
Sécurise ton API avec JWT et OAuth2, écris des tests automatisés avec pytest, et génère la documentation OpenAPI/Swagger automatiquement.
Déployer FastAPI en production
Conteneurise ton API avec Docker, configure Nginx et Uvicorn, mets en place un CI/CD complet et applique les bonnes pratiques de production.