Browse Source
Co-authored-by: ryusuke.miyaji <[email protected]> Co-authored-by: ryuckel <[email protected]> Co-authored-by: tokusumi <[email protected]> Co-authored-by: T. Tokusumi <[email protected]> Co-authored-by: Sebastián Ramírez <[email protected]>pull/10972/head
committed by
GitHub
2 changed files with 400 additions and 0 deletions
@ -0,0 +1,191 @@ |
|||
# 依存関係としてのクラス |
|||
|
|||
**依存性注入** システムを深く掘り下げる前に、先ほどの例をアップグレードしてみましょう。 |
|||
|
|||
## 前の例の`dict` |
|||
|
|||
前の例では、依存関係("dependable")から`dict`を返していました: |
|||
|
|||
```Python hl_lines="9" |
|||
{!../../../docs_src/dependencies/tutorial001.py!} |
|||
``` |
|||
|
|||
しかし、*path operation関数*のパラメータ`commons`に`dict`が含まれています。 |
|||
|
|||
また、エディタは`dict`のキーと値の型を知ることができないため、多くのサポート(補完のような)を提供することができません。 |
|||
|
|||
もっとうまくやれるはずです...。 |
|||
|
|||
## 依存関係を作るもの |
|||
|
|||
これまでは、依存関係が関数として宣言されているのを見てきました。 |
|||
|
|||
しかし、依存関係を定義する方法はそれだけではありません(その方が一般的かもしれませんが)。 |
|||
|
|||
重要なのは、依存関係が「呼び出し可能」なものであることです。 |
|||
|
|||
Pythonにおける「**呼び出し可能**」とは、Pythonが関数のように「呼び出す」ことができるものを指します。 |
|||
|
|||
そのため、`something`オブジェクト(関数ではないかもしれませんが)を持っていて、それを次のように「呼び出す」(実行する)ことができるとします: |
|||
|
|||
```Python |
|||
something() |
|||
``` |
|||
|
|||
または |
|||
|
|||
```Python |
|||
something(some_argument, some_keyword_argument="foo") |
|||
``` |
|||
|
|||
これを「呼び出し可能」なものと呼びます。 |
|||
|
|||
## 依存関係としてのクラス |
|||
|
|||
Pythonのクラスのインスタンスを作成する際に、同じ構文を使用していることに気づくかもしれません。 |
|||
|
|||
例えば: |
|||
|
|||
```Python |
|||
class Cat: |
|||
def __init__(self, name: str): |
|||
self.name = name |
|||
|
|||
|
|||
fluffy = Cat(name="Mr Fluffy") |
|||
``` |
|||
|
|||
この場合、`fluffy`は`Cat`クラスのインスタンスです。 |
|||
|
|||
そして`fluffy`を作成するために、`Cat`を「呼び出している」ことになります。 |
|||
|
|||
そのため、Pythonのクラスもまた「呼び出し可能」です。 |
|||
|
|||
そして、**FastAPI** では、Pythonのクラスを依存関係として使用することができます。 |
|||
|
|||
FastAPIが実際にチェックしているのは、それが「呼び出し可能」(関数、クラス、その他なんでも)であり、パラメータが定義されているかどうかということです。 |
|||
|
|||
**FastAPI** の依存関係として「呼び出し可能なもの」を渡すと、その「呼び出し可能なもの」のパラメータを解析し、サブ依存関係も含めて、*path operation関数*のパラメータと同じように処理します。 |
|||
|
|||
それは、パラメータが全くない呼び出し可能なものにも適用されます。パラメータのない*path operation関数*と同じように。 |
|||
|
|||
そこで、上で紹介した依存関係の`common_parameters`を`CommonQueryParams`クラスに変更します: |
|||
|
|||
```Python hl_lines="11 12 13 14 15" |
|||
{!../../../docs_src/dependencies/tutorial002.py!} |
|||
``` |
|||
|
|||
クラスのインスタンスを作成するために使用される`__init__`メソッドに注目してください: |
|||
|
|||
```Python hl_lines="12" |
|||
{!../../../docs_src/dependencies/tutorial002.py!} |
|||
``` |
|||
|
|||
...以前の`common_parameters`と同じパラメータを持っています: |
|||
|
|||
```Python hl_lines="8" |
|||
{!../../../docs_src/dependencies/tutorial001.py!} |
|||
``` |
|||
|
|||
これらのパラメータは **FastAPI** が依存関係を「解決」するために使用するものです。 |
|||
|
|||
どちらの場合も以下を持っています: |
|||
|
|||
* オプショナルの`q`クエリパラメータ。 |
|||
* `skip`クエリパラメータ、デフォルトは`0`。 |
|||
* `limit`クエリパラメータ、デフォルトは`100`。 |
|||
|
|||
どちらの場合も、データは変換され、検証され、OpenAPIスキーマなどで文書化されます。 |
|||
|
|||
## 使用 |
|||
|
|||
これで、このクラスを使用して依存関係を宣言することができます。 |
|||
|
|||
```Python hl_lines="19" |
|||
{!../../../docs_src/dependencies/tutorial002.py!} |
|||
``` |
|||
|
|||
**FastAPI** は`CommonQueryParams`クラスを呼び出します。これにより、そのクラスの「インスタンス」が作成され、インスタンスはパラメータ`commons`として関数に渡されます。 |
|||
|
|||
## 型注釈と`Depends` |
|||
|
|||
上のコードでは`CommonQueryParams`を2回書いていることに注目してください: |
|||
|
|||
```Python |
|||
commons: CommonQueryParams = Depends(CommonQueryParams) |
|||
``` |
|||
|
|||
以下にある最後の`CommonQueryParams`: |
|||
|
|||
```Python |
|||
... = Depends(CommonQueryParams) |
|||
``` |
|||
|
|||
...は、**FastAPI** が依存関係を知るために実際に使用するものです。 |
|||
|
|||
そこからFastAPIが宣言されたパラメータを抽出し、それが実際にFastAPIが呼び出すものです。 |
|||
|
|||
--- |
|||
|
|||
この場合、以下にある最初の`CommonQueryParams`: |
|||
|
|||
```Python |
|||
commons: CommonQueryParams ... |
|||
``` |
|||
|
|||
...は **FastAPI** に対して特別な意味をもちません。FastAPIはデータ変換や検証などには使用しません(それらのためには`= Depends(CommonQueryParams)`を使用しています)。 |
|||
|
|||
実際には以下のように書けばいいだけです: |
|||
|
|||
```Python |
|||
commons = Depends(CommonQueryParams) |
|||
``` |
|||
|
|||
以下にあるように: |
|||
|
|||
```Python hl_lines="19" |
|||
{!../../../docs_src/dependencies/tutorial003.py!} |
|||
``` |
|||
|
|||
しかし、型を宣言することは推奨されています。そうすれば、エディタは`commons`のパラメータとして何が渡されるかを知ることができ、コードの補完や型チェックなどを行うのに役立ちます: |
|||
|
|||
<img src="https://fastapi.tiangolo.com/img/tutorial/dependencies/image02.png"> |
|||
|
|||
## ショートカット |
|||
|
|||
しかし、ここでは`CommonQueryParams`を2回書くというコードの繰り返しが発生していることがわかります: |
|||
|
|||
```Python |
|||
commons: CommonQueryParams = Depends(CommonQueryParams) |
|||
``` |
|||
|
|||
依存関係が、クラス自体のインスタンスを作成するために**FastAPI**が「呼び出す」*特定の*クラスである場合、**FastAPI** はこれらのケースのショートカットを提供しています。 |
|||
|
|||
それらの具体的なケースについては以下のようにします: |
|||
|
|||
以下のように書く代わりに: |
|||
|
|||
```Python |
|||
commons: CommonQueryParams = Depends(CommonQueryParams) |
|||
``` |
|||
|
|||
...以下のように書きます: |
|||
|
|||
```Python |
|||
commons: CommonQueryParams = Depends() |
|||
``` |
|||
|
|||
パラメータの型として依存関係を宣言し、`Depends()`の中でパラメータを指定せず、`Depends()`をその関数のパラメータの「デフォルト」値(`=`のあとの値)として使用することで、`Depends(CommonQueryParams)`の中でクラス全体を*もう一度*書かなくてもよくなります。 |
|||
|
|||
同じ例では以下のようになります: |
|||
|
|||
```Python hl_lines="19" |
|||
{!../../../docs_src/dependencies/tutorial004.py!} |
|||
``` |
|||
|
|||
...そして **FastAPI** は何をすべきか知っています。 |
|||
|
|||
!!! tip "豆知識" |
|||
役に立つというよりも、混乱するようであれば無視してください。それをする*必要*はありません。 |
|||
|
|||
それは単なるショートカットです。なぜなら **FastAPI** はコードの繰り返しを最小限に抑えることに気を使っているからです。 |
@ -0,0 +1,209 @@ |
|||
# 依存関係 - 最初のステップ |
|||
|
|||
** FastAPI** は非常に強力でありながら直感的な **<abbr title="コンポーネント、リソース、プロバイダ、サービス、インジェクタブルとしても知られている">依存性注入</abbr>** システムを持っています。 |
|||
|
|||
それは非常にシンプルに使用できるように設計されており、開発者が他のコンポーネント **FastAPI** と統合するのが非常に簡単になるように設計されています。 |
|||
|
|||
## 「依存性注入」とは |
|||
|
|||
**「依存性注入」** とは、プログラミングにおいて、コード(この場合は、*path operation関数*)が動作したり使用したりするために必要なもの(「依存関係」)を宣言する方法があることを意味します: |
|||
|
|||
そして、そのシステム(この場合は、**FastAPI**)は、必要な依存関係をコードに提供するために必要なことは何でも行います(依存関係を「注入」します)。 |
|||
|
|||
これは以下のようなことが必要な時にとても便利です: |
|||
|
|||
* ロジックを共有している。(同じコードロジックを何度も繰り返している)。 |
|||
* データベース接続を共有する。 |
|||
* セキュリティ、認証、ロール要件などを強制する。 |
|||
* そのほかにも多くのこと... |
|||
|
|||
これらすべてを、コードの繰り返しを最小限に抑えながら行います。 |
|||
|
|||
## 最初のステップ |
|||
|
|||
非常にシンプルな例を見てみましょう。あまりにもシンプルなので、今のところはあまり参考にならないでしょう。 |
|||
|
|||
しかし、この方法では **依存性注入** システムがどのように機能するかに焦点を当てることができます。 |
|||
|
|||
### 依存関係の作成 |
|||
|
|||
まずは依存関係に注目してみましょう。 |
|||
|
|||
以下のように、*path operation関数*と同じパラメータを全て取ることができる関数にすぎません: |
|||
|
|||
```Python hl_lines="8 9" |
|||
{!../../../docs_src/dependencies/tutorial001.py!} |
|||
``` |
|||
|
|||
これだけです。 |
|||
|
|||
**2行**。 |
|||
|
|||
そして、それはすべての*path operation関数*が持っているのと同じ形と構造を持っています。 |
|||
|
|||
「デコレータ」を含まない(`@app.get("/some-path")`を含まない)*path operation関数*と考えることもできます。 |
|||
|
|||
そして何でも返すことができます。 |
|||
|
|||
この場合、この依存関係は以下を期待しています: |
|||
|
|||
* オプショナルのクエリパラメータ`q`は`str`です。 |
|||
* オプショナルのクエリパラメータ`skip`は`int`で、デフォルトは`0`です。 |
|||
* オプショナルのクエリパラメータ`limit`は`int`で、デフォルトは`100`です。 |
|||
|
|||
そして、これらの値を含む`dict`を返します。 |
|||
|
|||
### `Depends`のインポート |
|||
|
|||
```Python hl_lines="3" |
|||
{!../../../docs_src/dependencies/tutorial001.py!} |
|||
``` |
|||
|
|||
### "dependant"での依存関係の宣言 |
|||
|
|||
*path operation関数*のパラメータに`Body`や`Query`などを使用するのと同じように、新しいパラメータに`Depends`を使用することができます: |
|||
|
|||
```Python hl_lines="13 18" |
|||
{!../../../docs_src/dependencies/tutorial001.py!} |
|||
``` |
|||
|
|||
関数のパラメータに`Depends`を使用するのは`Body`や`Query`などと同じですが、`Depends`の動作は少し異なります。 |
|||
|
|||
`Depends`は1つのパラメータしか与えられません。 |
|||
|
|||
このパラメータは関数のようなものである必要があります。 |
|||
|
|||
そして、その関数は、*path operation関数*が行うのと同じ方法でパラメータを取ります。 |
|||
|
|||
!!! tip "豆知識" |
|||
次の章では、関数以外の「もの」が依存関係として使用できるものを見ていきます。 |
|||
|
|||
新しいリクエストが到着するたびに、**FastAPI** が以下のような処理を行います: |
|||
|
|||
* 依存関係("dependable")関数を正しいパラメータで呼び出します。 |
|||
* 関数の結果を取得します。 |
|||
* *path operation関数*のパラメータにその結果を代入してください。 |
|||
|
|||
```mermaid |
|||
graph TB |
|||
|
|||
common_parameters(["common_parameters"]) |
|||
read_items["/items/"] |
|||
read_users["/users/"] |
|||
|
|||
common_parameters --> read_items |
|||
common_parameters --> read_users |
|||
``` |
|||
|
|||
この方法では、共有されるコードを一度書き、**FastAPI** が*path operations*のための呼び出しを行います。 |
|||
|
|||
!!! check "確認" |
|||
特別なクラスを作成してどこかで **FastAPI** に渡して「登録」する必要はないことに注意してください。 |
|||
|
|||
`Depends`を渡すだけで、**FastAPI** が残りの処理をしてくれます。 |
|||
|
|||
## `async`にするかどうか |
|||
|
|||
依存関係は **FastAPI**(*path operation関数*と同じ)からも呼び出されるため、関数を定義する際にも同じルールが適用されます。 |
|||
|
|||
`async def`や通常の`def`を使用することができます。 |
|||
|
|||
また、通常の`def`*path operation関数*の中に`async def`を入れて依存関係を宣言したり、`async def`*path operation関数*の中に`def`を入れて依存関係を宣言したりすることなどができます。 |
|||
|
|||
それは重要ではありません。**FastAPI** は何をすべきかを知っています。 |
|||
|
|||
!!! note "備考" |
|||
わからない場合は、ドキュメントの[Async: *"In a hurry?"*](../../async.md){.internal-link target=_blank}の中の`async`と`await`についてのセクションを確認してください。 |
|||
|
|||
## OpenAPIとの統合 |
|||
|
|||
依存関係(およびサブ依存関係)のすべてのリクエスト宣言、検証、および要件は、同じOpenAPIスキーマに統合されます。 |
|||
|
|||
つまり、対話型ドキュメントにはこれらの依存関係から得られる全ての情報も含まれているということです: |
|||
|
|||
<img src="https://fastapi.tiangolo.com/img/tutorial/dependencies/image01.png"> |
|||
|
|||
## 簡単な使い方 |
|||
|
|||
見てみると、*path*と*operation*が一致した時に*path operation関数*が宣言されていて、**FastAPI** が正しいパラメータで関数を呼び出してリクエストからデータを抽出する処理をしています。 |
|||
|
|||
実は、すべての(あるいはほとんどの)Webフレームワークは、このように動作します。 |
|||
|
|||
これらの関数を直接呼び出すことはありません。これらの関数はフレームワーク(この場合は、**FastAPI**)によって呼び出されます。 |
|||
|
|||
依存性注入システムでは、**FastAPI** に*path operation*もまた、*path operation関数*の前に実行されるべき他の何かに「依存」していることを伝えることができ、**FastAPI** がそれを実行し、結果を「注入」することを引き受けます。 |
|||
|
|||
他にも、「依存性注入」と同じような考えの一般的な用語があります: |
|||
|
|||
* リソース |
|||
* プロバイダ |
|||
* サービス |
|||
* インジェクタブル |
|||
* コンポーネント |
|||
|
|||
## **FastAPI** プラグイン |
|||
|
|||
統合や「プラグイン」は **依存性注入** システムを使って構築することができます。しかし、実際には、**「プラグイン」を作成する必要はありません**。依存関係を使用することで、無限の数の統合やインタラクションを宣言することができ、それが**path operation関数*で利用可能になるからです。 |
|||
|
|||
依存関係は非常にシンプルで直感的な方法で作成することができ、必要なPythonパッケージをインポートするだけで、*文字通り*数行のコードでAPI関数と統合することができます。 |
|||
|
|||
次の章では、リレーショナルデータベースやNoSQLデータベース、セキュリティなどについて、その例を見ていきます。 |
|||
|
|||
## **FastAPI** 互換性 |
|||
|
|||
依存性注入システムがシンプルなので、**FastAPI** は以下のようなものと互換性があります: |
|||
|
|||
* すべてのリレーショナルデータベース |
|||
* NoSQLデータベース |
|||
* 外部パッケージ |
|||
* 外部API |
|||
* 認証・認可システム |
|||
* API利用状況監視システム |
|||
* レスポンスデータ注入システム |
|||
* など。 |
|||
|
|||
## シンプルでパワフル |
|||
|
|||
階層依存性注入システムは、定義や使用方法が非常にシンプルであるにもかかわらず、非常に強力なものとなっています。 |
|||
|
|||
依存関係事態を定義する依存関係を定義することができます。 |
|||
|
|||
最終的には、依存関係の階層ツリーが構築され、**依存性注入**システムが、これらの依存関係(およびそのサブ依存関係)をすべて解決し、各ステップで結果を提供(注入)します。 |
|||
|
|||
例えば、4つのAPIエンドポイント(*path operations*)があるとします: |
|||
|
|||
* `/items/public/` |
|||
* `/items/private/` |
|||
* `/users/{user_id}/activate` |
|||
* `/items/pro/` |
|||
|
|||
そして、依存関係とサブ依存関係だけで、それぞれに異なるパーミッション要件を追加することができます: |
|||
|
|||
```mermaid |
|||
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 operations*にパラメータやバリデーションを追加します。 |
|||
|
|||
**FastAPI** はそれをすべてOpenAPIスキーマに追加して、対話型のドキュメントシステムに表示されるようにします。 |
Loading…
Reference in new issue