Injection de dépendances FastAPI

FastAPI fournit un système d'injection de dépendances puissant et concis.

L'injection de dépendances est un patron de conception qui vous permet d'extraire la logique commune (comme les connexions aux bases de données, l'authentification, la validation des paramètres, etc.) dans des composants réutilisables, puis de les utiliser selon les besoins dans les routes.


Qu'est-ce que l'injection de dépendances

En bref,DépendanceIl s'agit essentiellement d'une fonction qui peut utiliser les mêmes paramètres que les fonctions d'opération de chemin (paramètres de requête, paramètres de chemin, corps de requête, etc.). FastAPI appellera automatiquement la fonction de dépendance avant d'exécuter la fonction de route, et transmettra sa valeur de retour à la fonction de route.

Exemple

from typing import Annotated
from fastapi import Depends, FastAPI

app = FastAPI()


# 1. Définir la fonction de dépendance
def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
    return {"q": q, "skip": skip, "limit": limit}


# 2. Utiliser les dépendances dans les routes
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
    # commons reçoit la valeur de retour de la fonction de dépendance
    return commons


@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
    # Plusieurs routes peuvent réutiliser la même dépendance
    return commons

Explication du code :

PartieDescription
common_parametersFonctions de dépendance, gérant les paramètres de requête communs
Depends(common_parameters)Déclarer les paramètrescommonsLa valeur provient de la fonction de dépendance
commons: dictReçoit le dictionnaire renvoyé par la fonction de dépendance

Les fonctions de dépendance et les fonctions d'opération de chemin utilisent le même style de déclaration de paramètres, et FastAPI résoudra automatiquement les paramètres de la fonction de dépendance. Cela signifie que les fonctions de dépendance peuvent également utiliser des paramètres de requête, des paramètres de chemin, un corps de requête, etc.


Flux d'exécution des dépendances

Lorsqu'une requête arrive, l'ordre de traitement de FastAPI :

  1. Identifier les fonctions de route et leurs dépendances
  2. Exécuter les fonctions de dépendance (dans l'ordre des dépendances)
  3. Transmettre la valeur de retour de la fonction de dépendance à la fonction de route.
  4. Exécuter la fonction de route

Classe en tant que dépendance

Outre les fonctions, vous pouvez également utiliser des classes comme dépendances :

Exemple

from typing import Annotated
from fastapi import Depends, FastAPI

app = FastAPI()


# Déclaration des dépendances avec des classes
class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


# Utiliser une classe comme dépendance
@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
    return {"q": commons.q, "skip": commons.skip, "limit": commons.limit}

QuandDepends()Lorsqu'aucun paramètre n'est passé, FastAPI utilise automatiquement l'annotation de type du paramètre (CommonQueryParams) comme dépendance.


sous-dépendance

Les dépendances peuvent avoir leurs propres dépendances, formant une chaîne de dépendances :

Exemple

from typing import Annotated
from fastapi import Depends, FastAPI

app = FastAPI()


# Fonctions de dépendance
def query_extractor(q: str | None = None):
    return q


# Sous-dépendance : dépend de query_extractor.
def query_checker(q: str = Depends(query_extractor)):
    if q == "admin":
        # Les sous-dépendances peuvent être validées
        return q + " (checked)"
    return q


# Les routes utilisent des sous-dépendances
@app.get("/items/")
async def read_items(q: str = Depends(query_checker)):
    return {"q": q}

Flux d'exécution :query_extractor -> query_checker-> fonction de route


Utilisation des dépendances dans les décorateurs

Parfois, vous avez seulement besoin des effets de bord de la dépendance (comme les vérifications des permissions), pas de sa valeur de retour. Dans le décorateurdependenciesDéclaré dans les paramètres :

Exemple

from fastapi import Depends, FastAPI, Header, HTTPException

app = FastAPI()


# Dépendance : valider la clé API
async def verify_api_key(x_api_key: str = Header()):
    if x_api_key != "secret-key":
        raise HTTPException(status_code=400, detail="X-API-Key invalid")


# Utilisation d'une dépendance dans le décorateur, aucune valeur de retour requise
@app.get("/items/", dependencies=[Depends(verify_api_key)])
async def read_items():
    return [{"item": "Foo"}]


# Appliquer la dépendance à l'ensemble du groupe de routes
@app.get("/users/", dependencies=[Depends(verify_api_key)])
async def read_users():
    return [{"user": "Bar"}]

Dépendances globales

Vous pouvezFastAPIDéclarez des dépendances globales sur l'instance, effectives pour toutes les routes :

Exemple

from fastapi import Depends, FastAPI, Header, HTTPException

async def verify_token(x_token: str = Header()):
    if x_token != "fake-super-secret-token":
        raise HTTPException(status_code=400, detail="En-tête X-Token invalide")


# Dépendance globale : toutes les routes doivent passer la validation du token
app = FastAPI(dependencies=[Depends(verify_token)])


@app.get("/items/")
async def read_items():
    return [{"item": "Foo"}]


@app.get("/users/")
async def read_users():
    return [{"user": "Bar"}]

Dépendances utilisant yield

Lorsqu'une dépendance doit effectuer des opérations de nettoyage (comme fermer des connexions à la base de données), utilisezyield:

Exemple

from typing import Annotated
from fastapi import Depends, FastAPI

app = FastAPI()


# Dépendances qui utilisent yield : créez une connexion avant la requête, et fermez-la après la requête.
def get_db():
    db = "database_connection"  # Simuler la création d'une connexion à la base de données
    try:
        yield db  # Fournir une connexion à la base de données pendant le traitement de la requête
    finally:
        print("Close database connection")  # Nettoyer les ressources une fois la requête terminée


@app.get("/items/")
async def read_items(db: str = Depends(get_db)):
    return {"db": db}

Flux d'exécution :

  1. Lorsque la requête arrive, exécuteryieldLe code précédent, qui crée une connexion à la base de données
  2. yieldTransmettez la connexion à la fonction de route
  3. Une fois la fonction de route terminée, exécuterfinallyCode de nettoyage dans

yieldLes dépendances sont idéales pour gérer les ressources qui nécessitent un nettoyage, comme les connexions à la base de données et les descripteurs de fichiers. Le code de nettoyage s'exécutera que la fonction de route lève une exception ou non.


Résumé

  • L'injection de dépendances extrait la logique commune dans des fonctions ou des classes réutilisables.
  • UtilisationDepends()Déclarez les dépendances dans les paramètres de la fonction de route
  • Les dépendances peuvent être imbriquées, formant des chaînes de dépendances
  • du décorateurdependenciesParamètres utilisés pour les dépendances qui n'ont pas besoin de valeurs de retour
  • UtilisationyieldLes dépendances prennent en charge le nettoyage des ressources
  • Les dépendances globales s'appliquent à toutes les routes
autres extensions