サブ依存関係¶
**サブ依存関係**を持つ依存関係を作成できます。
必要に応じて、**深い**レベルまでネストできます。
**FastAPI**はそれらを解決します。
最初の依存関係「dependable」¶
最初の依存関係(「dependable」)を次のように作成できます。
from typing import Annotated
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: str | None = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[str | None, Cookie()] = None,
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(
query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
from typing import Annotated, Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[str, None], Cookie()] = None,
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(
query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
from typing import Union
from fastapi import Cookie, Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[str, None], Cookie()] = None,
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(
query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
ヒント
可能であれば、Annotated
バージョンを使用することをお勧めします。
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: str | None = None):
return q
def query_or_cookie_extractor(
q: str = Depends(query_extractor), last_query: str | None = Cookie(default=None)
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
return {"q_or_cookie": query_or_default}
ヒント
可能であれば、Annotated
バージョンを使用することをお勧めします。
from typing import Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: str = Depends(query_extractor),
last_query: Union[str, None] = Cookie(default=None),
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
return {"q_or_cookie": query_or_default}
これは、オプションのクエリパラメータq
をstr
として宣言し、それを返すだけです。
これは非常にシンプル(あまり役に立たない)ですが、サブ依存関係の動作に焦点を当てるのに役立ちます。
2番目の依存関係、「dependable」と「dependant」¶
次に、同時に独自の依存関係を宣言する別の依存関数(「dependable」)を作成できます(そのため、「dependant」でもあります)。
from typing import Annotated
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: str | None = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[str | None, Cookie()] = None,
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(
query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
from typing import Annotated, Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[str, None], Cookie()] = None,
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(
query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
from typing import Union
from fastapi import Cookie, Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[str, None], Cookie()] = None,
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(
query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
ヒント
可能であれば、Annotated
バージョンを使用することをお勧めします。
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: str | None = None):
return q
def query_or_cookie_extractor(
q: str = Depends(query_extractor), last_query: str | None = Cookie(default=None)
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
return {"q_or_cookie": query_or_default}
ヒント
可能であれば、Annotated
バージョンを使用することをお勧めします。
from typing import Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: str = Depends(query_extractor),
last_query: Union[str, None] = Cookie(default=None),
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
return {"q_or_cookie": query_or_default}
宣言されたパラメータに焦点を当てましょう。
- この関数はそれ自体が依存関係(「dependable」)であるにもかかわらず、別の依存関係も宣言しています(他のものにも「依存」しています)。
query_extractor
に依存し、その戻り値をパラメータq
に代入します。
- また、オプションの
last_query
クッキーをstr
として宣言します。- ユーザーがクエリ
q
を提供しなかった場合、前にクッキーに保存した最後に使用したクエリを使用します。
- ユーザーがクエリ
依存関係の使用¶
次に、次のように依存関係を使用できます。
from typing import Annotated
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: str | None = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[str | None, Cookie()] = None,
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(
query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
from typing import Annotated, Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[str, None], Cookie()] = None,
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(
query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
from typing import Union
from fastapi import Cookie, Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[str, None], Cookie()] = None,
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(
query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
ヒント
可能であれば、Annotated
バージョンを使用することをお勧めします。
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: str | None = None):
return q
def query_or_cookie_extractor(
q: str = Depends(query_extractor), last_query: str | None = Cookie(default=None)
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
return {"q_or_cookie": query_or_default}
ヒント
可能であれば、Annotated
バージョンを使用することをお勧めします。
from typing import Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: str = Depends(query_extractor),
last_query: Union[str, None] = Cookie(default=None),
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
return {"q_or_cookie": query_or_default}
情報
パスオペレーション関数では、query_or_cookie_extractor
という1つの依存関係しか宣言していないことに注意してください。
しかし、**FastAPI**は、query_or_cookie_extractor
を呼び出す際に、その結果をquery_or_cookie_extractor
に渡すために、最初にquery_extractor
を解決する必要があることを認識します。
graph TB
query_extractor(["query_extractor"])
query_or_cookie_extractor(["query_or_cookie_extractor"])
read_query["/items/"]
query_extractor --> query_or_cookie_extractor --> read_query
同じ依存関係の複数回使用¶
依存関係の1つが同じパスオペレーションに対して複数回宣言されている場合(たとえば、複数の依存関係に共通のサブ依存関係がある場合)、**FastAPI**はそのサブ依存関係をリクエストごとに1回だけ呼び出すことを認識します。
そして、そのリクエストで必要なすべての「依存関係」に渡すために、返された値を"キャッシュ"に保存し、リクエストごとに依存関係を複数回呼び出す代わりに、そのリクエストのすべての「依存関係」に渡します。
「キャッシュ」された値を使用する代わりに、同じリクエストのすべてのステップで(おそらく複数回)依存関係を呼び出す必要があることがわかっている高度なシナリオでは、Depends
を使用する際にパラメータuse_cache=False
を設定できます。
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
return {"fresh_value": fresh_value}
ヒント
可能であれば、Annotated
バージョンを使用することをお勧めします。
async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
return {"fresh_value": fresh_value}
まとめ¶
ここで使用されているすべての専門用語とは別に、**依存関係注入**システムは非常にシンプルです。
パスオペレーション関数と同じように見える関数です。
しかし、それでも非常に強力であり、任意の深さでネストされた依存関係「グラフ」(ツリー)を宣言できます。
ヒント
これらの簡単な例では、それほど有用には見えないかもしれません。
しかし、セキュリティに関する章で、それがいかに有用であるかがお分かりいただけるでしょう。
そして、それがどれだけのコードを削減してくれるかも分かるでしょう。