Python : FastAPI
FastAPI est un framework web Python pour la création d'API HTTP, fondé sur les annotations de types standard du langage. Les types déclarés dans la signature d'une fonction servent à la fois à valider les requêtes, à convertir les données, à sérialiser les réponses et à générer une documentation OpenAPI interactive.
Aperçu
FastAPI s'appuie sur deux bibliothèques : Starlette, qui fournit la couche web ASGI (routage, requêtes, WebSocket), et Pydantic, qui valide et sérialise les données à partir des annotations de types. Le projet a été créé par Sebastián Ramírez (tiangolo) et est distribué sous licence MIT ; son site est fastapi.tiangolo.com.
- Finalité : création d'API web avec Python
- Principe : une seule déclaration de types alimente la validation, la conversion, la sérialisation et la documentation (standards OpenAPI et JSON Schema)
- Gouvernance : projet porté par son créateur et mainteneur principal, avec de nombreux contributeurs externes
ASGI, fonctions synchrones et asynchrones
FastAPI est une application ASGI (Asynchronous Server Gateway Interface), servie par un serveur comme Uvicorn. Contrairement à WSGI (Flask, Django classique), où chaque requête occupe un thread ou un processus, ASGI repose sur une boucle d'événements : une requête qui attend une entrée/sortie (base de données, appel HTTP) libère la boucle pour traiter les autres.
Une route peut être déclarée avec async def ou def, avec des conséquences différentes :
async def: la fonction s'exécute directement dans la boucle d'événements. Elle doit utiliser des bibliothèques asynchrones (httpx.AsyncClient,asyncpg) ; un appel bloquant (requests.get,time.sleep) y bloque toutes les requêtes en cours.def: FastAPI exécute la fonction dans un pool de threads, ce qui permet d'utiliser des bibliothèques synchrones sans bloquer la boucle.
Le fonctionnement de la boucle d'événements est détaillé dans l'article Python : async/await.
FastAPI vs Flask
FastAPI intègre la validation et la sérialisation des données (Pydantic), la génération de la documentation OpenAPI et le support natif de l'asynchrone. Les paramètres de chemin, de requête et le corps sont extraits et validés automatiquement d'après les annotations ; une requête invalide reçoit une réponse 422 détaillant les champs en erreur.
Flask est un micro-framework WSGI minimaliste, qui laisse au développeur le choix des composants. La validation des données et la documentation OpenAPI passent par des extensions tierces (Marshmallow, flask-smorest...). Son écosystème d'extensions, plus ancien, couvre de nombreux besoins.
FastAPI convient aux API dont les contrats de données doivent être validés et documentés, et aux services à forte concurrence d'entrées/sorties ; Flask, aux applications où la liberté d'assemblage prime ou qui s'appuient sur son écosystème existant.
Utilisation
Installation, avec les dépendances standard (serveur Uvicorn, CLI fastapi) :
pip install "fastapi[standard]"
L'exemple suivant est une API minimale de gestion de tâches permettant de créer, lire, mettre à jour et supprimer des tâches (CRUD) :
- Créer une tâche avec un titre, une description et une échéance.
- Lire la liste des tâches, paginée, ou une tâche par son identifiant.
- Mettre à jour une tâche existante.
- Supprimer une tâche par son identifiant.
from datetime import date
from typing import Annotated
from fastapi import FastAPI, HTTPException, Query, status
from pydantic import BaseModel
app = FastAPI()
class TaskIn(BaseModel):
title: str
description: str
due_date: date
class Task(TaskIn):
id: int
tasks: dict[int, Task] = {} # stockage en mémoire, perdu au redémarrage
next_id = 1
@app.post("/tasks/", response_model=Task, status_code=status.HTTP_201_CREATED)
def create_task(task_in: TaskIn):
global next_id
task = Task(id=next_id, **task_in.model_dump())
tasks[task.id] = task
next_id += 1
return task
@app.get("/tasks/", response_model=list[Task])
def read_tasks(
skip: Annotated[int, Query(ge=0)] = 0,
limit: Annotated[int, Query(ge=1, le=100)] = 10,
):
return list(tasks.values())[skip : skip + limit]
@app.get("/tasks/{task_id}", response_model=Task)
def read_task(task_id: int):
if task_id not in tasks:
raise HTTPException(status_code=404, detail="Task not found")
return tasks[task_id]
@app.put("/tasks/{task_id}", response_model=Task)
def update_task(task_id: int, task_in: TaskIn):
if task_id not in tasks:
raise HTTPException(status_code=404, detail="Task not found")
tasks[task_id] = Task(id=task_id, **task_in.model_dump())
return tasks[task_id]
@app.delete("/tasks/{task_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_task(task_id: int):
if tasks.pop(task_id, None) is None:
raise HTTPException(status_code=404, detail="Task not found")
@app.get("/search_tasks", response_model=list[Task])
def search_tasks(
title: Annotated[str | None, Query(max_length=100)] = None,
due_date: date | None = None,
):
results = list(tasks.values())
if title:
results = [t for t in results if title.lower() in t.title.lower()]
if due_date:
results = [t for t in results if t.due_date == due_date]
return results
Plusieurs mécanismes de FastAPI apparaissent dans cet exemple :
- Séparation entrée/sortie :
TaskIndécrit ce que le client envoie,Taskce que l'API renvoie ; l'identifiant est attribué par le serveur et ne peut pas être imposé par le client. - Validation des paramètres :
task_id: intest extrait du chemin et converti ;/tasks/abcreçoit une réponse422sans que la fonction soit appelée.Query(ge=0)ajoute une contrainte, reportée dans la documentation. - Codes de statut :
HTTPExceptioninterrompt le traitement avec le code indiqué (404), etstatus_codefixe le code de succès (201à la création,204sans corps à la suppression). response_model: la réponse est validée et filtrée selon ce modèle ; un champ absent du modèle n'est jamais renvoyé, ce qui évite de divulguer des attributs internes.Annotated: forme recommandée pour associer métadonnées (Query,Path,Body) et type, sans détourner la valeur par défaut du paramètre.
Pour lancer l'application :
fastapi dev main.py # développement : rechargement automatique, écoute sur 127.0.0.1
fastapi run main.py # production : sans rechargement, écoute sur 0.0.0.0:8000
Les deux commandes démarrent Uvicorn ; fastapi run --workers 4 lance plusieurs processus pour exploiter plusieurs cœurs.
En plus de l'API, FastAPI génère automatiquement une documentation interactive (Swagger UI) accessible à l'adresse http://127.0.0.1:8000/docs, une variante ReDoc sur /redoc, et le schéma OpenAPI brut sur /openapi.json, exploitable par des générateurs de clients.

L'article FastAPI : CRUD et authentification prolonge cet exemple avec une base de données et une authentification par jeton, et l'article Pydantic détaille le mécanisme de validation.