Skip to content

ミドルウェア

Note

ミドルウェアの仕組みは Starlette のもの。 FastAPI クラスStarlette クラス を継承していて、 @app.middleware("http")add_middleware も Starlette 側で定義されたものを受け継いでるだけ。下のコードにもある @app.middleware("http") は、内部で Starlette の BaseHTTPMiddleware を使って、関数を包んでるだけ。
add_middleware で追加する定番のミドルウェアも Starlette の再エクスポート。例えば FastAPI の CORSMiddlewareStarlette の CORSMiddleware と全く同じもの。

ミドルウェアは、リクエストがエンドポイントに届く前と、レスポンスがクライアントに返る前に処理を挟み込める仕組み。
認証チェックや CORS、 CSRF 対策 のように、複数のエンドポイントに共通でかけたい処理を書くのに向いてる。

cf. https://fastapi.tiangolo.com/tutorial/middleware/


どういう流れで動くのか

ミドルウェアは「リクエストを受け取る → 次の処理に渡す → レスポンスを受け取る」という順番で動く。
call_next を呼ぶと、その先のミドルウェアやエンドポイントに処理が渡って、戻ってきたレスポンスを受け取れる。

下の例は、リクエストの処理にかかった時間を測ってレスポンスヘッダーに入れるミドルウェア(FastAPI チュートリアルと同じもの)。

main.py
import time
from fastapi import FastAPI, Request

app = FastAPI()


@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start = time.perf_counter()
    response = await call_next(request)  # 先の処理にリクエストを渡す
    elapsed = time.perf_counter() - start
    response.headers["X-Process-Time"] = str(elapsed)  # 返ってきたレスポンスに手を加える
    return response

@app.middleware("http") を付けると、全リクエストがこの関数を通る。引数の request が届いたリクエストで、 call_next が「この先の処理を実行して」という関数。

ポイントは call_next を境に処理が「行き」と「帰り」に分かれること。

  • 行き( call_next の前 ): まだエンドポイントには渡してない段階。ここでは開始時刻を記録してる。
  • await call_next(request) : ここで初めてエンドポイントに処理が渡る。 await で処理が終わるのを待って、結果のレスポンスを受け取る。
  • 帰り( call_next の後 ): 返ってきたレスポンスに手を加えられる。ここではかかった時間を計算して、 X-Process-Time ヘッダーに入れてる。

認証チェックみたいに「エンドポイントに入る前に弾きたい」処理は行きに、レスポンスの加工は帰りに書く、というイメージ。

複数のミドルウェアを登録すると、玉ねぎのように外側から内側へ入って、内側から外側へ戻ってくる。


FastAPI の内部の仕組み

ミドルウェアが内部でどう動いてるかは、 Marcelo Trylesinski さんの PyCon Italia 2024 のトークで説明されてる。

トークでは、リクエストは Server から Application へ進んで、レスポンスは Application から Server へ戻ってくるって説明されてる。
下記のコードを例にすると、下の図のような流れでミドルウェアが効いてくるみたい。

Marcelo Trylesinski さんのトークで紹介されてるコード
from fastapi import FastAPI
from src.middleware import CustomMiddleware, AnotherCustomMiddleware

app = FastAPI()
app.add_middleware(CustomMiddleware)
app.add_middleware(AnotherCustomMiddleware)

ミドルウェアスタック(Marcelo Trylesinski さんのトークより)