FastAPIのDependsについて知る【備忘録】

お疲れ様です。

FastAPIで使用するDependsという機能について調べたまとめです。 公式ドキュメントやAI等を使って勉強はしましたが、すべて理解できた気がしないので一旦は理解できた範囲でメモを残しておこうと思います…。

fastapi.tiangolo.com

Dependsとは

FastAPIのエンドポイントで依存関係(Dependency Injection) を定義するための仕組みのこと。

具体的には下記のような処理で使用できます。 ユーザ認証用の処理でよく使用されているイメージですね。

  • DBセッション取得
  • 認証・認可
  • Logger取得
  • 設定値取得
  • 共通バリデーション
  • 共通クエリパラメータ処理

Dependency Injectionとは

依存性注入(DI: Dependency Injection)は、「必要なオブジェクトを自分で作らず、外部から渡してもらう設計」のこと。
関数なら引数でオブジェクト間の依存関係を切り離した状態で渡すという設計上の考え方というイメージです。

使い方

下記のような形で書きます。(以前の記事で作成したコードを流用しています。)
例によってソースはGitHubにも残しておきました。

github.com

Depends内に記載した関数を先に実行して引数の値に注入します。 引数queryはクエリパラメータをBaseModelの形でデータが入り、引数loggerにはFastAPIのRequestから取得したAPIのURL(="/test")をロガー名で設定したロガーが作成されます。

from typing import Annotated

from fastapi import Depends, FastAPI

app = FastAPI()

class RequestModel(CamelModel):
    """リクエスト用のBaseModel"""
    user_id: int = 1234
    user_name: str = "test_user"
    

class ResponseModel(CamelModel):
    """レスポンス用のBaseModel"""
    user_id: int
    user_name: str
    message: str
    
    
def get_endpoint_logger(req: Request) -> logging.Logger:
    """APIエンドポイント用のロガーを取得する関数

    Args:
        req (Request): APIエンドポイントのRequestオブジェクト

    Returns:
        logging.Logger: APIエンドポイント用のロガーのインスタンス
    """
    endpoint_name = req.url.path
    return logging.getLogger(endpoint_name)


@app.get("/test")
def base_model_test(
    query: Annotated[RequestModel, Depends()],
    logger: Annotated[logging.Logger, Depends(get_endpoint_logger)]
) -> ResponseModel:
    """getメソッドでテスト"""
    # 受け取ったリクエストモデルを表示
    logger.info(f"変換なし: {query.model_dump()}")
    logger.info(f"変換あり: {query.model_dump(by_alias=True)}")
    
    # レスポンスモデルを返す
    response = ResponseModel(
        user_id=query.user_id,
        user_name=query.user_name,
        message="getメソッドでレスポンスモデルのテスト"
    )
    
    return response

Depends内の関数の引数について

Depends内の関数の引数はFastAPIが自動解決して入力してくれるようになっているようです。 値の取得は下記のものから行います。パラメータ系やRequestはよく使いそうです。

  • クエリパラメータ
  • パスパラメータ
  • HTTP Header
  • Cookie
  • Request
  • 階層化されたDepends

Annotatedを使う書き方について

最近のFastAPIではこの書き方が推奨されています。Ruffを使っていると警告が出ます。
型ヒントがきれいに書ける点、VSCodeを使う場合など補完がうまく機能してくれたりするので基本こちらの書き方で書くのが良さそうです。

動作確認

先ほどのコードを実行してみました。 SwaggerUIからクエリパラメータを設定して実行します。

SwaggerUI

実行するとこのような出力になりました。
上で説明した通りqueryにはクエリパラメータをBaseModelがloggerにはAPIのURLを名前に設定したロガーが取得できています。

result

参考サイト