【FastAPI】API間で共通の変数を扱うapp.state【備忘録】

お疲れ様です。

FastAPIで作成したAPI間で共通で使える変数を定義する方法のメモです。
最近の実装で必要になり調べたところFastAPIの機能として元からあることを知りました。

fastapi.tiangolo.com

FastAPIでAPIを作成する際app = FastAPI()と最初に定義するかと思います。 このFastAPIのclassにstateがあり、app.state.[任意の名前] = (値)として変数を格納できます。

from fastapi import FastAPI

app = FastAPI()

app.state.message = "メッセージ"

デモ

デモコードを作成したのでこちらで実際に試してみます。 ソースコード全体はこちらにあります。main.pyを実行してWebの画面を表示し実際に操作して試すことができます。

github.com

下記のようなフォームからテキストを入力してBackendに送信します。 入力

「送信」ボタンを押すと下記のAPIが呼ばれapp.state.message = textの部分で格納されます。

app = FastAPI()

@app.post("/text")
def record_message(
    obj: Text
) -> str:
    """入力したテキストを記録
    """
    text = obj.text
    print(text)
    
    # stateに格納
    app.state.message = text
    
    return "OK"

同一のソース内の場合

上記で格納したテキストを表示します。

同一のコード内

下記のようにmessage = app.state.messageからstateに格納された値を取り出しています。 「APIからデータ取得」ボタンを押すとアラートで入力したメッセージが表示されます。

@app.get("/message")
def get_message() -> str:
    """記録したメッセージを取り出す
    """
    # stateから取り出し
    message = app.state.message
    
    return message

APIからのメッセージ

routerを使用して別のソースを利用する場合

routerを使用する際、ソースコードが別になるのでapp = FastAPI()のappをそのまま使用することができません。

この場合はAPI呼び出しの際に様々な情報を取得できるRequestクラスを使用することで、routerをincludeしているFastAPIのappの情報も取得することができます。

下記のようにRequestクラスのreqを使ってmessage = req.app.state.messageからstateに格納された値を取り出せます。

  • メインモジュール側(app、main.py)
from router import sub

app.include_router(sub.router)
  • ルーティングモジュール(router、router/sub.py)
router = APIRouter(prefix="/sub")

@router.get("/message")
def get_message(
    req: Request
) -> str:
    """記録したメッセージを取り出す
    """
    # stateから取り出し
    message = req.app.state.message
    
    return message