依存性注入¶
FastAPI には、非常に強力でありながら直感的な 依存性注入 システムがあります。
これは、非常に使いやすく、どの開発者でも他のコンポーネントを FastAPI と簡単に統合できるように設計されています。
「依存性注入」とは何か¶
プログラミングにおける 「依存性注入」 とは、コード(この場合は パス操作関数)が、機能するために必要なもの(「依存関係」)を宣言する方法があることを意味します。
そして、そのシステム(この場合は FastAPI)が、それらの必要な依存関係をコードに提供するために必要なことすべて(依存関係を「注入」すること)を行います。
これは、次のような場合に非常に便利です。
- 共有ロジックがある場合(同じコードロジックが何度も繰り返される場合)。
- データベース接続を共有する場合。
- セキュリティ、認証、ロール要件などを強制する場合。
- その他多くのこと...
これらすべてを、コードの繰り返しを最小限に抑えながら実現します。
最初のステップ¶
非常に簡単な例を見てみましょう。今のところ、あまり役に立たないほど単純です。
しかし、この方法で 依存性注入 システムがどのように機能するかに焦点を当てることができます。
依存関係、または「依存性のあるもの」を作成する¶
まず、依存関係に焦点を当てましょう。
これは、パス操作関数 が受け取ることができるのと同じすべてのパラメーターを受け取ることができる単なる関数です。
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
🤓 その他のバージョンとバリアント
from typing import Annotated, Union
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
from typing import Union
from fastapi import Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
ヒント
可能であれば`Annotated`バージョンを使用することをお勧めします。
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
ヒント
可能であれば`Annotated`バージョンを使用することをお勧めします。
from typing import Union
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
それだけです。
2行.
そして、それはすべての パス操作関数 が持つものと同じ形と構造を持っています。
「デコレータ」(@app.get("/some-path")なし)がない パス操作関数 と考えることができます。
そして、好きなものを返すことができます。
この場合、この依存関係は次を期待します。
str型のオプションのクエリパラメーターq。int型のオプションのクエリパラメーターskipで、デフォルトは0です。int型のオプションのクエリパラメーターlimitで、デフォルトは100です。
そして、それらの値を含む dict を返すだけです。
情報
FastAPI はバージョン 0.95.0 で Annotated のサポートを追加し(そして推奨し始めました)。
古いバージョンを使用している場合、Annotated を使用しようとするとエラーが発生します。
Annotated を使用する前に、FastAPI のバージョンを 0.95.1 以上にアップグレードしてください。
Depends をインポートする¶
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
🤓 その他のバージョンとバリアント
from typing import Annotated, Union
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
from typing import Union
from fastapi import Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
ヒント
可能であれば`Annotated`バージョンを使用することをお勧めします。
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
ヒント
可能であれば`Annotated`バージョンを使用することをお勧めします。
from typing import Union
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
「依存性のあるもの」で依存関係を宣言する¶
パス操作関数 パラメーターで Body、Query などを使用するのと同じ方法で、新しいパラメーターで Depends を使用します。
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
🤓 その他のバージョンとバリアント
from typing import Annotated, Union
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
from typing import Union
from fastapi import Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
ヒント
可能であれば`Annotated`バージョンを使用することをお勧めします。
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
ヒント
可能であれば`Annotated`バージョンを使用することをお勧めします。
from typing import Union
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
関数パラメーターで Body、Query などを使用するのと同じ方法で Depends を使用しますが、Depends は少し異なって機能します。
Depends には単一のパラメーターのみを渡します。
このパラメーターは関数のようなものでなければなりません。
直接 呼び出すことはしません(最後に括弧を追加しません)、単に Depends() へのパラメーターとして渡します。
そして、その関数は パス操作関数 と同じ方法でパラメーターを受け取ります。
ヒント
関数以外の他の「もの」が依存関係として使用できるかについては、次の章で説明します。
新しいリクエストが到着すると、FastAPI は次を行います。
- 依存関係(「依存性のあるもの」)関数を正しいパラメーターで呼び出します。
- 関数から結果を取得します。
- その結果を パス操作関数 のパラメーターに割り当てます。
graph TB
common_parameters(["common_parameters"])
read_items["/items/"]
read_users["/users/"]
common_parameters --> read_items
common_parameters --> read_users
このようにして、共有コードを一度記述するだけで、FastAPI が パス操作 のためにそれを呼び出すのを処理します。
確認
特別なクラスを作成して、それを FastAPI に「登録」したり、それに類することをしたりする必要はないことに注意してください。
単に Depends に渡すだけで、FastAPI が残りを処理する方法を知っています。
Annotated 依存関係を共有する¶
上記の例では、わずかな コードの重複 があることがわかります。
common_parameters() 依存関係を使用する必要がある場合、型アノテーションと Depends() を含むパラメーター全体を記述する必要があります。
commons: Annotated[dict, Depends(common_parameters)]
しかし、Annotated を使用しているため、その Annotated 値を変数に格納して、複数の場所で使用できます。
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
CommonsDep = Annotated[dict, Depends(common_parameters)]
@app.get("/items/")
async def read_items(commons: CommonsDep):
return commons
@app.get("/users/")
async def read_users(commons: CommonsDep):
return commons
🤓 その他のバージョンとバリアント
from typing import Annotated, Union
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
CommonsDep = Annotated[dict, Depends(common_parameters)]
@app.get("/items/")
async def read_items(commons: CommonsDep):
return commons
@app.get("/users/")
async def read_users(commons: CommonsDep):
return commons
from typing import Union
from fastapi import Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
CommonsDep = Annotated[dict, Depends(common_parameters)]
@app.get("/items/")
async def read_items(commons: CommonsDep):
return commons
@app.get("/users/")
async def read_users(commons: CommonsDep):
return commons
ヒント
これは標準的なPythonであり、「型エイリアス」と呼ばれ、実際には FastAPI に固有のものではありません。
しかし、FastAPI は Annotated を含むPython標準に基づいているため、このトリックをコードで使用できます。 😎
依存関係は期待どおりに機能し続け、最も良い点 は 型情報が保持される ことです。つまり、エディタは 自動補完、インラインエラー などを引き続き提供できます。mypy などの他のツールも同様です。
これは、大規模なコードベース で 同じ依存関係 を 多くの パス操作 で繰り返し使用する場合に特に役立ちます。
async を使うか使わないか¶
依存関係も FastAPI によって呼び出されるため(パス操作関数 と同じ)、関数を定義する際には同じルールが適用されます。
async def または通常の def を使用できます。
そして、通常の def パス操作関数 内で async def 依存関係を宣言したり、async def パス操作関数 内で def 依存関係を宣言したりできます。
それは関係ありません。FastAPI は何をすべきかを知っています。
Note
わからない場合は、ドキュメントの Async: "急いでいる方へ?" の async と await のセクションを確認してください。
OpenAPI と統合¶
依存関係(およびサブ依存関係)のすべてのリクエスト宣言、検証、要件は、同じOpenAPIスキーマに統合されます。
したがって、インタラクティブなドキュメントには、これらの依存関係からの情報もすべて含まれます。

簡単な使い方¶
見ての通り、パス操作関数 は パス と 操作 が一致したときに使用されるように宣言され、その後 FastAPI はリクエストからデータを抽出して、正しいパラメータで関数を呼び出すことを処理します。
実際、すべての(またはほとんどの)Webフレームワークは同じ方法で動作します。
これらの関数を直接呼び出すことはありません。それらはフレームワーク(この場合は FastAPI)によって呼び出されます。
依存性注入システムを使用すると、FastAPI に、パス操作関数 が、パス操作関数 の前に実行されるべき他のものにも「依存」していることを伝えることができます。そして FastAPI は、それを実行し、結果を「注入」することを処理します。
この「依存性注入」という同じ考え方の他の一般的な用語は次のとおりです。
- リソース
- プロバイダー
- サービス
- インジェクタブル
- コンポーネント
FastAPI プラグイン¶
統合と「プラグイン」は 依存性注入 システムを使用して構築できます。しかし実際には、「プラグイン」を作成する必要はありません。依存関係を使用することで、パス操作関数 で利用可能な無限の統合とインタラクションを宣言できるからです。
そして、依存関係は非常にシンプルで直感的な方法で作成できるため、必要なPythonパッケージをインポートするだけで、文字通り数行のコードでAPI関数と統合できます。
これについては、リレーショナルデータベースとNoSQLデータベース、セキュリティなどに関する次の章で例を示します。
FastAPI の互換性¶
依存性注入システムのシンプルさにより、FastAPI は以下と互換性があります。
- すべてのリレーショナルデータベース
- NoSQLデータベース
- 外部パッケージ
- 外部API
- 認証および認可システム
- API利用状況監視システム
- 応答データ注入システム
- など
シンプルでパワフル¶
階層的な依存性注入システムは、定義と使用が非常にシンプルですが、それでも非常に強力です。
依存関係を定義し、それがさらに依存関係を定義することができます。
最終的に、依存関係の階層ツリーが構築され、依存性注入 システムがこれらすべての依存関係(およびそのサブ依存関係)を解決し、各ステップで結果を提供(注入)するのを処理します。
例えば、4つのAPIエンドポイント(パス操作)があるとします。
/items/public//items/private//users/{user_id}/activate/items/pro/
その後、依存関係とサブ依存関係だけで、それぞれに異なる権限要件を追加できます。
graph TB
current_user(["current_user"])
active_user(["active_user"])
admin_user(["admin_user"])
paying_user(["paying_user"])
public["/items/public/"]
private["/items/private/"]
activate_user["/users/{user_id}/activate"]
pro_items["/items/pro/"]
current_user --> active_user
active_user --> admin_user
active_user --> paying_user
current_user --> public
active_user --> private
admin_user --> activate_user
paying_user --> pro_items
OpenAPI と統合¶
これらの依存関係はすべて、要件を宣言する際に、パス操作 にパラメータ、検証などを追加します。
FastAPI は、これらすべてを OpenAPI スキーマに追加し、対話型ドキュメントシステムに表示されるようにします。