依存関係¶
🌐 Translation by AI and humans
This translation was made by AI guided by humans. 🤝
It could have mistakes of misunderstanding the original meaning, or looking unnatural, etc. 🤖
You can improve this translation by helping us guide the AI LLM better.
FastAPI は非常に強力でありながら直感的な Dependency Injection システムを持っています。
それは非常にシンプルに使用できるように設計されており、開発者が他のコンポーネント FastAPI と統合するのが非常に簡単になるように設計されています。
「Dependency Injection」とは¶
「Dependency Injection」 とは、プログラミングにおいて、コード(この場合は、path operation 関数)が動作したり使用したりするために必要なもの(「依存関係」)を宣言する方法があることを意味します:
そして、そのシステム(この場合は、FastAPI)は、必要な依存関係をコードに提供するために必要なことは何でも行います(依存関係を「注入」します)。
これは以下のようなことが必要な時にとても便利です:
- ロジックを共有している。(同じコードロジックを何度も繰り返している)。
- データベース接続を共有する。
- セキュリティ、認証、ロール要件などを強制する。
- そのほかにも多くのこと...
これらすべてを、コードの繰り返しを最小限に抑えながら行います。
最初のステップ¶
非常にシンプルな例を見てみましょう。あまりにもシンプルなので、今のところはあまり参考にならないでしょう。
しかし、この方法では Dependency Injection システムがどのように機能するかに焦点を当てることができます。
依存関係(「dependable」)の作成¶
まずは依存関係に注目してみましょう。
以下のように、path operation 関数と同じパラメータを全て取ることができる関数にすぎません:
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
🤓 Other versions and variants
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
Tip
Prefer to use the Annotated version if possible.
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
Tip
Prefer to use the Annotated version if possible.
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行。
そして、それはすべてのpath operation 関数が持っているのと同じ形と構造を持っています。
「デコレータ」を含まない(@app.get("/some-path")を含まない)path operation 関数と考えることもできます。
そして何でも返すことができます。
この場合、この依存関係は以下を期待しています:
- オプショナルのクエリパラメータ
qはstrです。 - オプショナルのクエリパラメータ
skipはintで、デフォルトは0です。 - オプショナルのクエリパラメータ
limitはintで、デフォルトは100です。
そして、これらの値を含むdictを返します。
情報
FastAPI はバージョン 0.95.0 で Annotated のサポートを追加し(そして推奨し始めました)。
古いバージョンを使用している場合、Annotated を使おうとするとエラーになります。
Annotated を使用する前に、少なくとも 0.95.1 まで FastAPI のバージョンをアップグレード してください。
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
🤓 Other versions and variants
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
Tip
Prefer to use the Annotated version if possible.
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
Tip
Prefer to use the Annotated version if possible.
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
「dependant」での依存関係の宣言¶
path operation 関数のパラメータに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
🤓 Other versions and variants
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
Tip
Prefer to use the Annotated version if possible.
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
Tip
Prefer to use the Annotated version if possible.
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
関数のパラメータにDependsを使用するのはBodyやQueryなどと同じですが、Dependsの動作は少し異なります。
Dependsは1つのパラメータしか与えられません。
このパラメータは関数のようなものである必要があります。
直接呼び出しません(末尾に括弧を付けません)。Depends() のパラメータとして渡すだけです。
そして、その関数は、path operation 関数が行うのと同じ方法でパラメータを取ります。
豆知識
次の章では、関数以外の「もの」が依存関係として使用できるものを見ていきます。
新しいリクエストが到着するたびに、FastAPI が以下のような処理を行います:
- 依存関係("dependable")関数を正しいパラメータで呼び出します。
- 関数の結果を取得します。
- path operation 関数のパラメータにその結果を代入してください。
graph TB
common_parameters(["common_parameters"])
read_items["/items/"]
read_users["/users/"]
common_parameters --> read_items
common_parameters --> read_users
この方法では、共有されるコードを一度書き、FastAPI がpath operationのための呼び出しを行います。
確認
特別なクラスを作成してどこかで 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
🤓 Other versions and variants
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
豆知識
これはただの標準 Python で、「type alias」と呼ばれ、FastAPI 固有のものではありません。
しかし FastAPI は Annotated を含む Python 標準に基づいているため、このテクニックをコードで使えます。 😎
依存関係は期待どおりに動作し続け、一番良い点 は 型情報が保持される ことです。つまり、エディタは 自動補完、インラインエラー などを提供し続けられます。mypy のような他のツールでも同様です。
これは 大規模なコードベース で、同じ依存関係 を 多くの path operation で何度も使う場合に特に役立ちます。
asyncにするかどうか¶
依存関係は FastAPI(path operation 関数と同じ)からも呼び出されるため、関数を定義する際にも同じルールが適用されます。
async defや通常のdefを使用することができます。
また、通常のdefpath operation 関数の中にasync defを入れて依存関係を宣言したり、async defpath operation 関数の中にdefを入れて依存関係を宣言したりすることなどができます。
それは重要ではありません。FastAPI は何をすべきかを知っています。
備考
わからない場合は、ドキュメントのAsync: "In a hurry?"の中のasyncとawaitについてのセクションを確認してください。
OpenAPIとの統合¶
依存関係(およびサブ依存関係)のすべてのリクエスト宣言、検証、および要件は、同じOpenAPIスキーマに統合されます。
つまり、対話型ドキュメントにはこれらの依存関係から得られる全ての情報も含まれているということです:

簡単な使い方¶
見てみると、pathとoperationが一致した時にpath operation 関数が宣言されていて、FastAPI が正しいパラメータで関数を呼び出してリクエストからデータを抽出する処理をしています。
実は、すべての(あるいはほとんどの)Webフレームワークは、このように動作します。
これらの関数を直接呼び出すことはありません。これらの関数はフレームワーク(この場合は、FastAPI)によって呼び出されます。
Dependency Injection システムでは、FastAPI にpath operation 関数もまた、path operation 関数の前に実行されるべき他の何かに「依存」していることを伝えることができ、FastAPI がそれを実行し、結果を「注入」することを引き受けます。
他にも、「dependency injection」と同じような考えの一般的な用語があります:
- resources
- providers
- services
- injectables
- components
FastAPI プラグイン¶
統合や「プラグイン」は Dependency Injection システムを使って構築することができます。しかし、実際には、「プラグイン」を作成する必要はありません。依存関係を使用することで、無限の数の統合やインタラクションを宣言することができ、それがpath operation 関数で利用可能になるからです。
依存関係は非常にシンプルで直感的な方法で作成することができ、必要なPythonパッケージをインポートするだけで、文字通り数行のコードでAPI関数と統合することができます。
次の章では、リレーショナルデータベースやNoSQLデータベース、セキュリティなどについて、その例を見ていきます。
FastAPI 互換性¶
dependency injection システムがシンプルなので、FastAPI は以下のようなものと互換性があります:
- すべてのリレーショナルデータベース
- NoSQLデータベース
- 外部パッケージ
- 外部API
- 認証・認可システム
- API利用状況監視システム
- レスポンスデータ注入システム
- など。
シンプルでパワフル¶
階層的な dependency injection システムは、定義や使用方法が非常にシンプルであるにもかかわらず、非常に強力なものとなっています。
依存関係が、さらに依存関係を定義することもできます。
最終的には、依存関係の階層ツリーが構築され、Dependency Injectionシステムが、これらの依存関係(およびそのサブ依存関係)をすべて解決し、各ステップで結果を提供(注入)します。
例えば、4つのAPIエンドポイント(path operation)があるとします:
/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 との統合¶
これら全ての依存関係は、要件を宣言すると同時に、path operationにパラメータやバリデーションを追加します。
FastAPI はそれをすべてOpenAPIスキーマに追加して、対話型のドキュメントシステムに表示されるようにします。