1. Développement, langage

FastAPI et Python asynchrone : bonnes pratiques pour éviter de bloquer son API

FastAPI n’accélère pas automatiquement le code

FastAPI a popularisé l’usage de async def dans les APIs Python. Pourtant, écrire un endpoint asynchrone ne suffit pas à rendre une application scalable. Si l’endpoint appelle du code bloquant, la boucle d’événements reste bloquée et les requêtes concurrentes attendent.

La bonne question n’est donc pas “faut-il mettre async partout ?”, mais “quelles parties de ma requête attendent des entrées/sorties et disposent de bibliothèques réellement asynchrones ?”.

Pour remettre ce sujet dans le parcours Python du site, vous pouvez aussi relire le langage Python, apprendre à coder en Python et les conseils pour écrire un code Python propre et lisible.

Endpoint async : utile quand la chaîne est async

from fastapi import FastAPI
import httpx

app = FastAPI()

@app.get("/meteo")
async def meteo():
    async with httpx.AsyncClient(timeout=5) as client:
        r = await client.get("https://api.example.com/weather")
        r.raise_for_status()
        return r.json()

Ici, l’appel HTTP est compatible avec await. Pendant que l’API externe répond, le serveur peut traiter d’autres requêtes.

Le mauvais mélange : async def + requests

import requests

@app.get("/lent")
async def lent():
    r = requests.get("https://api.example.com")  # bloque la boucle
    return r.json()

Ce code est trompeur : l’endpoint est asynchrone en apparence, mais requests.get() bloque. Il vaut mieux utiliser httpx.AsyncClient ou déclarer l’endpoint en def si le code reste synchrone.

Base de données : attention au driver

Un ORM ou driver synchrone dans une route async peut annuler l’intérêt de l’asynchrone. Pour PostgreSQL, par exemple, regardez des solutions compatibles async comme asyncpg, SQLAlchemy async ou les couches prévues par votre stack. L’objectif n’est pas de suivre une mode, mais d’éviter les attentes bloquantes sur les requêtes SQL.

Dépendances et services externes

Dans une API réelle, les blocages viennent souvent de dépendances secondaires : SDK de paiement, stockage S3, génération PDF, envoi d’e-mail, lecture d’un gros fichier. Listez les opérations lentes et classez-les : peuvent-elles être attendues en async ? doivent-elles partir dans une queue ? faut-il les exécuter dans un threadpool ?

from starlette.concurrency import run_in_threadpool

@app.get("/rapport")
async def rapport():
    resultat = await run_in_threadpool(generer_pdf_synchrone)
    return {"status": "ok", "resultat": resultat}

Le threadpool n’est pas une solution universelle, mais il permet d’isoler ponctuellement une fonction bloquante quand vous n’avez pas de version async fiable.

Ne créez pas un client HTTP à chaque fonction utilitaire

Créer et fermer un client à chaque appel est simple, mais pas optimal. En production, vous pouvez gérer un client partagé via le cycle de vie de l’application.

from contextlib import asynccontextmanager
import httpx

@asynccontextmanager
async def lifespan(app):
    app.state.http = httpx.AsyncClient(timeout=5)
    yield
    await app.state.http.aclose()

app = FastAPI(lifespan=lifespan)

@app.get("/ping-externe")
async def ping_externe():
    r = await app.state.http.get("https://example.com")
    return {"status": r.status_code}

Checklist avant mise en production

  • Les routes async n’appellent pas de fonctions bloquantes connues.
  • Les clients HTTP ont des timeouts.
  • Les connexions sont réutilisées quand c’est pertinent.
  • Les traitements lourds partent en worker ou threadpool.
  • Les erreurs externes sont gérées sans exposer une stack trace à l’utilisateur.

Conclusion

FastAPI fonctionne très bien avec l’asynchrone, à condition de respecter la chaîne complète. Un endpoint async def doit s’appuyer sur des bibliothèques async, des timeouts et une stratégie claire pour les opérations bloquantes. Sinon, le code paraît moderne mais reste séquentiel sous charge.

Frédéric Gaurat - formateur et développeur
Résumé de la politique de confidentialité

Ce site utilise des cookies afin que nous puissions vous fournir la meilleure expérience utilisateur possible. Les informations sur les cookies sont stockées dans votre navigateur et remplissent des fonctions telles que vous reconnaître lorsque vous revenez sur notre site Web et aider notre équipe à comprendre les sections du site que vous trouvez les plus intéressantes et utiles.