Sync fastapi docs from 11614be9 on 2026-03-11
This commit is contained in:
@@ -0,0 +1,503 @@
|
||||
# LLM テストファイル { #llm-test-file }
|
||||
|
||||
このドキュメントは、ドキュメントを翻訳する <abbr title="Large Language Model - 大規模言語モデル">LLM</abbr> が、`scripts/translate.py` の `general_prompt` と、`docs/{language code}/llm-prompt.md` の言語固有プロンプトを理解しているかをテストします。言語固有プロンプトは `general_prompt` の末尾に追加されます。
|
||||
|
||||
ここに追加したテストは、すべての言語固有プロンプトの設計者が参照します。
|
||||
|
||||
使い方:
|
||||
|
||||
* 言語固有プロンプトを用意します - `docs/{language code}/llm-prompt.md`。
|
||||
* この文書を希望するターゲット言語に新規で翻訳します(例: `translate.py` の `translate-page` コマンド)。これにより `docs/{language code}/docs/_llm-test.md` に翻訳が作成されます。
|
||||
* 翻訳が問題ないか確認します。
|
||||
* 必要であれば、言語固有プロンプト、general プロンプト、または英語ドキュメントを改善します。
|
||||
* その後、翻訳に残っている問題を手動で修正し、良い翻訳にします。
|
||||
* 良い翻訳を用意した状態でもう一度翻訳します。理想的な結果は、LLM が翻訳に一切変更を加えないことです。つまり general プロンプトと言語固有プロンプトが最良であることを意味します(時々いくつかランダムに見える変更を行うことがあります。理由は <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM は決定論的アルゴリズムではない</a> ためです)。
|
||||
|
||||
テスト内容:
|
||||
|
||||
## コードスニペット { #code-snippets }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
これはコードスニペットです: `foo`。そしてこれもコードスニペットです: `bar`。さらにもう一つ: `baz quux`。
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
コードスニペットの内容はそのままにしておく必要があります。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### Content of code snippets」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## 引用 { #quotes }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
昨日、友人はこう書きました。「incorrectly を正しく綴れば、あなたはそれを間違って綴ったことになる」。それに対して私はこう答えました。「そのとおり。ただし『incorrectly』は誤りで、『"incorrectly"』ではありません」。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
LLM はおそらくここを誤って翻訳します。重要なのは、再翻訳時に修正済みの翻訳を維持できるかどうかだけです。
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
プロンプト設計者は、ストレートクォートをタイポグラフィックな引用符に変換するかどうかを選べます。そのままでも問題ありません。
|
||||
|
||||
例として `docs/de/llm-prompt.md` の「### Quotes」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## コードスニペット内の引用 { #quotes-in-code-snippets }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
`pip install "foo[bar]"`
|
||||
|
||||
コードスニペット中の文字列リテラルの例: `"this"`, `'that'`.
|
||||
|
||||
難しい文字列リテラルの例: `f"I like {'oranges' if orange else "apples"}"`
|
||||
|
||||
ハードコア: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"`
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
... ただし、コードスニペット内の引用符はそのままにしておく必要があります。
|
||||
|
||||
////
|
||||
|
||||
## コードブロック { #code-blocks }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
Bash のコード例です...
|
||||
|
||||
```bash
|
||||
# 宇宙にあいさつを表示
|
||||
echo "Hello universe"
|
||||
```
|
||||
|
||||
...そしてコンソールのコード例です...
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting server
|
||||
Searching for package file structure
|
||||
```
|
||||
|
||||
...さらに別のコンソールのコード例です...
|
||||
|
||||
```console
|
||||
// ディレクトリ "code" を作成
|
||||
$ mkdir code
|
||||
// そのディレクトリに移動
|
||||
$ cd code
|
||||
```
|
||||
|
||||
...そして Python のコード例です...
|
||||
|
||||
```Python
|
||||
wont_work() # これは動作しません 😱
|
||||
works(foo="bar") # これは動作します 🎉
|
||||
```
|
||||
|
||||
...以上です。
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
コードブロック内のコードは、コメントを除き、変更してはいけません。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### Content of code blocks」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## タブと色付きボックス { #tabs-and-colored-boxes }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
/// info | 情報
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// note | 備考
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// note | 技術詳細
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// check | 確認
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// tip | 豆知識
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// warning | 注意
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
/// danger | 警告
|
||||
いくつかのテキスト
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
タブおよび `Info`/`Note`/`Warning` などのブロックには、タイトルの翻訳を縦棒(`|`)の後ろに追加します。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### Special blocks」と「### Tab blocks」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## Web リンクと内部リンク { #web-and-internal-links }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
リンクのテキストは翻訳し、リンク先のアドレスは変更しないでください:
|
||||
|
||||
* [上の見出しへのリンク](#code-snippets)
|
||||
* [内部リンク](index.md#installation){.internal-link target=_blank}
|
||||
* <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">外部リンク</a>
|
||||
* <a href="https://fastapi.tiangolo.com/css/styles.css" class="external-link" target="_blank">スタイルへのリンク</a>
|
||||
* <a href="https://fastapi.tiangolo.com/js/logic.js" class="external-link" target="_blank">スクリプトへのリンク</a>
|
||||
* <a href="https://fastapi.tiangolo.com/img/foo.jpg" class="external-link" target="_blank">画像へのリンク</a>
|
||||
|
||||
リンクのテキストは翻訳し、リンク先のアドレスは翻訳版を指すようにしてください:
|
||||
|
||||
* <a href="https://fastapi.tiangolo.com/ja/" class="external-link" target="_blank">FastAPI リンク</a>
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
リンクのテキストは翻訳し、アドレスは変更しないでください。例外は、FastAPI ドキュメントのページへの絶対 URL です。その場合は翻訳版へのリンクにします。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### Links」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## HTML "abbr" 要素 { #html-abbr-elements }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
ここでは HTML の "abbr" 要素で包まれたものをいくつか示します(いくつかは架空です):
|
||||
|
||||
### abbr が完全な語句を示す { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done - 仕事を成し遂げること">GTD</abbr>
|
||||
* <abbr title="less than - より小さい"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token - XML ウェブトークン">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - 並列サーバーゲートウェイインターフェース">PSGI</abbr>
|
||||
|
||||
### abbr が完全な語句と説明を示す { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network - Mozilla 開発者ネットワーク: 開発者向けドキュメント、Firefox の開発元が執筆">MDN</abbr>
|
||||
* <abbr title="Input/Output - 入出力: ディスクの読み書き、ネットワーク通信。">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
"abbr" 要素の "title" 属性は特定の指示に従って翻訳します。
|
||||
|
||||
翻訳は、英語の語を説明するために独自の "abbr" 要素を追加してもよく、LLM はそれらを削除してはいけません。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### HTML abbr elements」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## HTML "dfn" 要素 { #html-dfn-elements }
|
||||
|
||||
* <dfn title="ある方法で接続・連携して動作するよう構成された複数のマシンの集合">クラスター</dfn>
|
||||
* <dfn title="入力層と出力層の間に多数の隠れ層を持つ人工ニューラルネットワークを用いる機械学習の手法で、その内部構造を包括的に形成する">ディープラーニング</dfn>
|
||||
|
||||
## 見出し { #headings }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
### Web アプリを開発する - チュートリアル { #develop-a-webapp-a-tutorial }
|
||||
|
||||
こんにちは。
|
||||
|
||||
### 型ヒントとアノテーション { #type-hints-and-annotations }
|
||||
|
||||
またこんにちは。
|
||||
|
||||
### スーパークラスとサブクラス { #super-and-subclasses }
|
||||
|
||||
またこんにちは。
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
見出しに関する唯一の厳格なルールは、リンクが壊れないように、LLM が中括弧内のハッシュ部分を変更しないことです。
|
||||
|
||||
`scripts/translate.py` の general プロンプト内「### Headings」の節を参照してください。
|
||||
|
||||
言語固有の指示については、例として `docs/de/llm-prompt.md` の「### Headings」の節を参照してください。
|
||||
|
||||
////
|
||||
|
||||
## ドキュメントで使う用語 { #terms-used-in-the-docs }
|
||||
|
||||
//// tab | テスト
|
||||
|
||||
* you
|
||||
* your
|
||||
|
||||
* e.g.
|
||||
* etc.
|
||||
|
||||
* `foo` を `int` として
|
||||
* `bar` を `str` として
|
||||
* `baz` を `list` として
|
||||
|
||||
* チュートリアル - ユーザーガイド
|
||||
* 上級ユーザーガイド
|
||||
* SQLModel ドキュメント
|
||||
* API ドキュメント
|
||||
* 自動生成ドキュメント
|
||||
|
||||
* データサイエンス
|
||||
* ディープラーニング
|
||||
* 機械学習
|
||||
* 依存性注入
|
||||
* HTTP Basic 認証
|
||||
* HTTP Digest
|
||||
* ISO 形式
|
||||
* JSON Schema 規格
|
||||
* JSON スキーマ
|
||||
* スキーマ定義
|
||||
* Password Flow
|
||||
* モバイル
|
||||
|
||||
* 非推奨
|
||||
* 設計された
|
||||
* 無効
|
||||
* オンザフライ
|
||||
* 標準
|
||||
* デフォルト
|
||||
* 大文字小文字を区別
|
||||
* 大文字小文字を区別しない
|
||||
|
||||
* アプリケーションを提供する
|
||||
* ページを配信する
|
||||
|
||||
* アプリ
|
||||
* アプリケーション
|
||||
|
||||
* リクエスト
|
||||
* レスポンス
|
||||
* エラーレスポンス
|
||||
|
||||
* path operation
|
||||
* path operation デコレータ
|
||||
* path operation 関数
|
||||
|
||||
* ボディ
|
||||
* リクエストボディ
|
||||
* レスポンスボディ
|
||||
* JSON ボディ
|
||||
* フォームボディ
|
||||
* ファイルボディ
|
||||
* 関数本体
|
||||
|
||||
* パラメータ
|
||||
* ボディパラメータ
|
||||
* パスパラメータ
|
||||
* クエリパラメータ
|
||||
* Cookie パラメータ
|
||||
* ヘッダーパラメータ
|
||||
* フォームパラメータ
|
||||
* 関数パラメータ
|
||||
|
||||
* イベント
|
||||
* 起動イベント
|
||||
* サーバーの起動
|
||||
* シャットダウンイベント
|
||||
* lifespan イベント
|
||||
|
||||
* ハンドラ
|
||||
* イベントハンドラ
|
||||
* 例外ハンドラ
|
||||
* 処理する
|
||||
|
||||
* モデル
|
||||
* Pydantic モデル
|
||||
* データモデル
|
||||
* データベースモデル
|
||||
* フォームモデル
|
||||
* モデルオブジェクト
|
||||
|
||||
* クラス
|
||||
* 基底クラス
|
||||
* 親クラス
|
||||
* サブクラス
|
||||
* 子クラス
|
||||
* 兄弟クラス
|
||||
* クラスメソッド
|
||||
|
||||
* ヘッダー
|
||||
* ヘッダー(複数)
|
||||
* 認可ヘッダー
|
||||
* `Authorization` ヘッダー
|
||||
* Forwarded ヘッダー
|
||||
|
||||
* 依存性注入システム
|
||||
* 依存関係
|
||||
* dependable
|
||||
* dependant
|
||||
|
||||
* I/O バウンド
|
||||
* CPU バウンド
|
||||
* 同時実行性
|
||||
* 並列性
|
||||
* マルチプロセッシング
|
||||
|
||||
* env var
|
||||
* 環境変数
|
||||
* `PATH`
|
||||
* `PATH` 環境変数
|
||||
|
||||
* 認証
|
||||
* 認証プロバイダ
|
||||
* 認可
|
||||
* 認可フォーム
|
||||
* 認可プロバイダ
|
||||
* ユーザーが認証する
|
||||
* システムがユーザーを認証する
|
||||
|
||||
* CLI
|
||||
* コマンドラインインターフェース
|
||||
|
||||
* サーバー
|
||||
* クライアント
|
||||
|
||||
* クラウドプロバイダ
|
||||
* クラウドサービス
|
||||
|
||||
* 開発
|
||||
* 開発段階
|
||||
|
||||
* dict
|
||||
* 辞書
|
||||
* 列挙型
|
||||
* Enum
|
||||
* 列挙メンバー
|
||||
|
||||
* エンコーダー
|
||||
* デコーダー
|
||||
* エンコードする
|
||||
* デコードする
|
||||
|
||||
* 例外
|
||||
* 送出する
|
||||
|
||||
* 式
|
||||
* 文
|
||||
|
||||
* フロントエンド
|
||||
* バックエンド
|
||||
|
||||
* GitHub ディスカッション
|
||||
* GitHub Issue
|
||||
|
||||
* パフォーマンス
|
||||
* パフォーマンス最適化
|
||||
|
||||
* 戻り値の型
|
||||
* 戻り値
|
||||
|
||||
* セキュリティ
|
||||
* セキュリティスキーム
|
||||
|
||||
* タスク
|
||||
* バックグラウンドタスク
|
||||
* タスク関数
|
||||
|
||||
* テンプレート
|
||||
* テンプレートエンジン
|
||||
|
||||
* 型アノテーション
|
||||
* 型ヒント
|
||||
|
||||
* サーバーワーカー
|
||||
* Uvicorn ワーカー
|
||||
* Gunicorn ワーカー
|
||||
* ワーカープロセス
|
||||
* ワーカークラス
|
||||
* ワークロード
|
||||
|
||||
* デプロイ
|
||||
* デプロイする
|
||||
|
||||
* SDK
|
||||
* ソフトウェア開発キット
|
||||
|
||||
* `APIRouter`
|
||||
* `requirements.txt`
|
||||
* Bearer Token
|
||||
* 破壊的変更
|
||||
* バグ
|
||||
* ボタン
|
||||
* 呼び出し可能
|
||||
* コード
|
||||
* コミット
|
||||
* コンテキストマネージャ
|
||||
* コルーチン
|
||||
* データベースセッション
|
||||
* ディスク
|
||||
* ドメイン
|
||||
* エンジン
|
||||
* フェイクの X
|
||||
* HTTP GET メソッド
|
||||
* アイテム
|
||||
* ライブラリ
|
||||
* ライフスパン
|
||||
* ロック
|
||||
* ミドルウェア
|
||||
* モバイルアプリケーション
|
||||
* モジュール
|
||||
* マウント
|
||||
* ネットワーク
|
||||
* オリジン
|
||||
* オーバーライド
|
||||
* ペイロード
|
||||
* プロセッサ
|
||||
* プロパティ
|
||||
* プロキシ
|
||||
* プルリクエスト
|
||||
* クエリ
|
||||
* RAM
|
||||
* リモートマシン
|
||||
* ステータスコード
|
||||
* 文字列
|
||||
* タグ
|
||||
* Web フレームワーク
|
||||
* ワイルドカード
|
||||
* 返す
|
||||
* 検証する
|
||||
|
||||
////
|
||||
|
||||
//// tab | 情報
|
||||
|
||||
これはドキュメントで見られる(主に)技術用語の不完全かつ規範的でない一覧です。プロンプト設計者が、LLM がどの用語で手助けを必要としているかを把握するのに役立つかもしれません。例えば、良い翻訳を最適でない翻訳に戻してしまう場合や、あなたの言語での活用・格変化に問題がある場合などです。
|
||||
|
||||
`docs/de/llm-prompt.md` の「### List of English terms and their preferred German translations」の節を参照してください。
|
||||
|
||||
////
|
||||
@@ -0,0 +1,3 @@
|
||||
# 概要 { #about }
|
||||
|
||||
FastAPI の概要、その設計やインスピレーションなどについて解説します。🤓
|
||||
@@ -0,0 +1,247 @@
|
||||
# OpenAPI の追加レスポンス { #additional-responses-in-openapi }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
これは比較的高度なトピックです。
|
||||
|
||||
FastAPI を使い始めたばかりであれば、これは不要かもしれません。
|
||||
|
||||
///
|
||||
|
||||
追加のステータスコード、メディアタイプ、説明などを伴う追加レスポンスを宣言できます。
|
||||
|
||||
それらの追加レスポンスは OpenAPI スキーマに含まれ、API ドキュメントにも表示されます。
|
||||
|
||||
ただし、それらの追加レスポンスについては、ステータスコードとコンテンツを指定して `JSONResponse` などの `Response` を直接返す必要があります。
|
||||
|
||||
## `model` を使った追加レスポンス { #additional-response-with-model }
|
||||
|
||||
*path operation デコレータ*に `responses` パラメータを渡せます。
|
||||
|
||||
これは `dict` を受け取り、キーは各レスポンスのステータスコード(例: `200`)、値は各レスポンスの情報を含む別の `dict` です。
|
||||
|
||||
それぞれのレスポンス `dict` には、`response_model` と同様に Pydantic モデルを格納する `model` キーを含められます。
|
||||
|
||||
FastAPI はそのモデルから JSON Schema を生成し、OpenAPI の適切な場所に含めます。
|
||||
|
||||
例えば、ステータスコード `404` と Pydantic モデル `Message` を持つ別のレスポンスを宣言するには、次のように書けます:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
`JSONResponse` を直接返す必要がある点に注意してください。
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`model` キーは OpenAPI の一部ではありません。
|
||||
|
||||
FastAPI はそこから Pydantic モデルを取得して JSON Schema を生成し、適切な場所に配置します。
|
||||
|
||||
適切な場所は次のとおりです:
|
||||
|
||||
- `content` キーの中。これは値として別の JSON オブジェクト(`dict`)を持ち、その中に次が含まれます:
|
||||
- メディアタイプ(例: `application/json`)をキーとし、値としてさらに別の JSON オブジェクトを持ち、その中に次が含まれます:
|
||||
- `schema` キー。値としてモデル由来の JSON Schema を持ち、ここが正しい配置場所です。
|
||||
- FastAPI はここに、スキーマを直接埋め込む代わりに OpenAPI 内のグローバルな JSON Schema への参照を追加します。これにより、他のアプリケーションやクライアントがそれらの JSON Schema を直接利用し、より良いコード生成ツール等を提供できます。
|
||||
|
||||
///
|
||||
|
||||
この *path operation* のために OpenAPI に生成されるレスポンスは次のとおりです:
|
||||
|
||||
```JSON hl_lines="3-12"
|
||||
{
|
||||
"responses": {
|
||||
"404": {
|
||||
"description": "Additional Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Message"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Item"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
スキーマは OpenAPI スキーマ内の別の場所への参照になります:
|
||||
|
||||
```JSON hl_lines="4-16"
|
||||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
"Message": {
|
||||
"title": "Message",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"title": "Message",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Item": {
|
||||
"title": "Item",
|
||||
"required": [
|
||||
"id",
|
||||
"value"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"title": "Id",
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"title": "Value",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ValidationError": {
|
||||
"title": "ValidationError",
|
||||
"required": [
|
||||
"loc",
|
||||
"msg",
|
||||
"type"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"msg": {
|
||||
"title": "Message",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"title": "Error Type",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"HTTPValidationError": {
|
||||
"title": "HTTPValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"title": "Detail",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## メインのレスポンスに追加のメディアタイプ { #additional-media-types-for-the-main-response }
|
||||
|
||||
同じ `responses` パラメータを使って、同一のメインレスポンスに別のメディアタイプを追加できます。
|
||||
|
||||
例えば、`image/png` の追加メディアタイプを加え、あなたの *path operation* が JSON オブジェクト(メディアタイプ `application/json`)または PNG 画像を返せることを宣言できます:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
画像は `FileResponse` を使って直接返す必要がある点に注意してください。
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`responses` パラメータで明示的に別のメディアタイプを指定しない限り、FastAPI はレスポンスがメインのレスポンスクラスと同じメディアタイプ(デフォルトは `application/json`)であるとみなします。
|
||||
|
||||
ただし、メディアタイプが `None` のカスタムレスポンスクラスを指定している場合、モデルが関連付けられた追加レスポンスには FastAPI は `application/json` を使用します。
|
||||
|
||||
///
|
||||
|
||||
## 情報の結合 { #combining-information }
|
||||
|
||||
`response_model`、`status_code`、`responses` パラメータなど、複数の場所からのレスポンス情報を組み合わせることもできます。
|
||||
|
||||
`response_model` を宣言し、デフォルトのステータスコード `200`(必要なら任意のコード)を使い、その同じレスポンスに対する追加情報を `responses` で OpenAPI スキーマに直接記述できます。
|
||||
|
||||
FastAPI は `responses` にある追加情報を保持し、モデルの JSON Schema と結合します。
|
||||
|
||||
例えば、Pydantic モデルを用い、独自の `description` を持つステータスコード `404` のレスポンスを宣言できます。
|
||||
|
||||
さらに、`response_model` を使うステータスコード `200` のレスポンスに独自の `example` を含めることもできます:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}
|
||||
|
||||
これらはすべて結合されて OpenAPI に含まれ、API ドキュメントに表示されます:
|
||||
|
||||
<img src="/img/tutorial/additional-responses/image01.png">
|
||||
|
||||
## 事前定義レスポンスとカスタムの組み合わせ { #combine-predefined-responses-and-custom-ones }
|
||||
|
||||
多くの *path operations* に適用できる事前定義のレスポンスを用意しつつ、各 *path operation* ごとに必要なカスタムレスポンスと組み合わせたい場合があります。
|
||||
|
||||
そのような場合、Python の `**dict_to_unpack` による `dict` の「アンパック」テクニックを使えます:
|
||||
|
||||
```Python
|
||||
old_dict = {
|
||||
"old key": "old value",
|
||||
"second old key": "second old value",
|
||||
}
|
||||
new_dict = {**old_dict, "new key": "new value"}
|
||||
```
|
||||
|
||||
ここでは、`new_dict` には `old_dict` のすべてのキーと値に加え、新しいキーと値が含まれます:
|
||||
|
||||
```Python
|
||||
{
|
||||
"old key": "old value",
|
||||
"second old key": "second old value",
|
||||
"new key": "new value",
|
||||
}
|
||||
```
|
||||
|
||||
このテクニックを使うと、*path operations* で事前定義レスポンスを再利用し、さらにカスタムのレスポンスを組み合わせられます。
|
||||
|
||||
例えば:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}
|
||||
|
||||
## OpenAPI レスポンスの詳細 { #more-information-about-openapi-responses }
|
||||
|
||||
レスポンスに正確に何を含められるかは、OpenAPI 仕様の次のセクションを参照してください:
|
||||
|
||||
- <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object" class="external-link" target="_blank">OpenAPI の Responses Object</a>。ここには `Response Object` が含まれます。
|
||||
- <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object" class="external-link" target="_blank">OpenAPI の Response Object</a>。`responses` パラメータ内の各レスポンスに、ここで定義されている要素を直接含められます。`description`、`headers`、`content`(ここで異なるメディアタイプや JSON Schema を宣言します)、`links` など。
|
||||
@@ -1,41 +1,41 @@
|
||||
# 追加のステータスコード
|
||||
# 追加のステータスコード { #additional-status-codes }
|
||||
|
||||
デフォルトでは、 **FastAPI** は `JSONResponse` を使ってレスポンスを返します。その `JSONResponse` の中には、 *path operation* が返した内容が入ります。
|
||||
デフォルトでは、 **FastAPI** は `JSONResponse` を使ってレスポンスを返し、*path operation* から返した内容をその `JSONResponse` の中に入れます。
|
||||
|
||||
それは、デフォルトのステータスコードか、 *path operation* でセットしたものを利用します。
|
||||
デフォルトのステータスコード、または *path operation* で設定したステータスコードが使用されます。
|
||||
|
||||
## 追加のステータスコード
|
||||
## 追加のステータスコード { #additional-status-codes_1 }
|
||||
|
||||
メインのステータスコードとは別に、他のステータスコードを返したい場合は、`Response` (`JSONResponse` など) に追加のステータスコードを設定して直接返します。
|
||||
メインのステータスコードとは別に追加のステータスコードを返したい場合は、`JSONResponse` のような `Response` を直接返し、追加のステータスコードを直接設定できます。
|
||||
|
||||
例えば、itemを更新し、成功した場合は200 "OK"のHTTPステータスコードを返す *path operation* を作りたいとします。
|
||||
たとえば、item を更新でき、成功時に HTTP ステータスコード 200 "OK" を返す *path operation* を作りたいとします。
|
||||
|
||||
しかし、新しいitemも許可したいです。itemが存在しない場合は、それらを作成して201 "Created"を返します。
|
||||
しかし、新しい item も受け付けたいとします。そして、item が以前存在しなかった場合には作成し、HTTP ステータスコード 201「Created」を返します。
|
||||
|
||||
これを達成するには、 `JSONResponse` をインポートし、 `status_code` を設定して直接内容を返します。
|
||||
これを実現するには、`JSONResponse` をインポートし、望む `status_code` を設定して、そこで内容を直接返します。
|
||||
|
||||
{* ../../docs_src/additional_status_codes/tutorial001.py hl[4,25] *}
|
||||
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
|
||||
|
||||
/// warning | 注意
|
||||
/// warning
|
||||
|
||||
上記の例のように `Response` を明示的に返す場合、それは直接返されます。
|
||||
上の例のように `Response` を直接返すと、それはそのまま返されます。
|
||||
|
||||
モデルなどはシリアライズされません。
|
||||
モデルなどによってシリアライズされません。
|
||||
|
||||
必要なデータが含まれていることや、値が有効なJSONであること (`JSONResponse` を使う場合) を確認してください。
|
||||
必要なデータが含まれていること、そして(`JSONResponse` を使用している場合)値が有効な JSON であることを確認してください。
|
||||
|
||||
///
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
`from starlette.responses import JSONResponse` を利用することもできます。
|
||||
`from starlette.responses import JSONResponse` を使うこともできます。
|
||||
|
||||
**FastAPI** は `fastapi.responses` と同じ `starlette.responses` を、開発者の利便性のために提供しています。しかし有効なレスポンスはほとんどStarletteから来ています。 `status` についても同じです。
|
||||
**FastAPI** は開発者の利便性のために、`fastapi.responses` と同じ `starlette.responses` を提供しています。しかし、利用可能なレスポンスのほとんどは Starlette から直接提供されています。`status` も同様です。
|
||||
|
||||
///
|
||||
|
||||
## OpenAPIとAPIドキュメント
|
||||
## OpenAPI と API ドキュメント { #openapi-and-api-docs }
|
||||
|
||||
ステータスコードとレスポンスを直接返す場合、それらはOpenAPIスキーマ (APIドキュメント) には含まれません。なぜなら、FastAPIは何が返されるのか事前に知ることができないからです。
|
||||
追加のステータスコードとレスポンスを直接返す場合、それらは OpenAPI スキーマ(API ドキュメント)には含まれません。FastAPI には、事前に何が返されるかを知る方法がないからです。
|
||||
|
||||
しかし、 [Additional Responses](additional-responses.md){.internal-link target=_blank} を使ってコードの中にドキュメントを書くことができます。
|
||||
しかし、[追加のレスポンス](additional-responses.md){.internal-link target=_blank} を使ってコード内にドキュメント化できます。
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
# 高度な依存関係 { #advanced-dependencies }
|
||||
|
||||
## パラメータ化された依存関係 { #parameterized-dependencies }
|
||||
|
||||
これまで見てきた依存関係は、固定の関数またはクラスでした。
|
||||
|
||||
しかし、多くの異なる関数やクラスを宣言せずに、その依存関係にパラメータを設定したい場合があります。
|
||||
|
||||
たとえば、クエリパラメータ `q` に、ある固定の内容が含まれているかを検査する依存関係が欲しいとします。
|
||||
|
||||
ただし、その固定の内容はパラメータ化できるようにしたいです。
|
||||
|
||||
## "callable" なインスタンス { #a-callable-instance }
|
||||
|
||||
Python には、クラスのインスタンスを "callable" にする方法があります。
|
||||
|
||||
クラス自体(これはすでに callable です)ではなく、そのクラスのインスタンスです。
|
||||
|
||||
そのためには、`__call__` メソッドを宣言します:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}
|
||||
|
||||
この場合、この `__call__` が、**FastAPI** が追加のパラメータやサブ依存関係を確認するために使うものになり、後であなたの *path operation 関数* のパラメータに値を渡すために呼び出されるものになります。
|
||||
|
||||
## インスタンスのパラメータ化 { #parameterize-the-instance }
|
||||
|
||||
そして、`__init__` を使って、依存関係を「パラメータ化」するために利用できるインスタンスのパラメータを宣言できます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}
|
||||
|
||||
この場合、**FastAPI** は `__init__` に触れたり気にかけたりすることはありません。私たちがコード内で直接使います。
|
||||
|
||||
## インスタンスの作成 { #create-an-instance }
|
||||
|
||||
このクラスのインスタンスは次のように作成できます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
|
||||
|
||||
このようにして依存関係を「パラメータ化」できます。いまや `"bar"` が属性 `checker.fixed_content` として中に保持されています。
|
||||
|
||||
## インスタンスを依存関係として使う { #use-the-instance-as-a-dependency }
|
||||
|
||||
その後、`Depends(FixedContentQueryChecker)` の代わりに `Depends(checker)` でこの `checker` を使えます。依存関係はクラスそのものではなく、インスタンスである `checker` だからです。
|
||||
|
||||
依存関係を解決するとき、**FastAPI** はこの `checker` を次のように呼び出します:
|
||||
|
||||
```Python
|
||||
checker(q="somequery")
|
||||
```
|
||||
|
||||
...そして、その戻り値を *path operation 関数* 内の依存関係の値として、パラメータ `fixed_content_included` に渡します:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ここまでの内容は回りくどく感じられるかもしれません。まだどのように役立つかが明確でないかもしれません。
|
||||
|
||||
これらの例は意図的に単純ですが、仕組みを示しています。
|
||||
|
||||
セキュリティの章では、同じやり方で実装されたユーティリティ関数があります。
|
||||
|
||||
ここまでを理解できていれば、そうしたセキュリティ用ユーティリティが内部でどのように動いているかも理解できています。
|
||||
|
||||
///
|
||||
|
||||
## `yield`、`HTTPException`、`except` とバックグラウンドタスクを伴う依存関係 { #dependencies-with-yield-httpexception-except-and-background-tasks }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
これらの技術的詳細は、ほとんどの場合は不要です。
|
||||
|
||||
主に、0.121.0 より前の FastAPI アプリケーションがあり、`yield` を使う依存関係で問題が発生している場合に有用です。
|
||||
|
||||
///
|
||||
|
||||
`yield` を使う依存関係は、さまざまなユースケースに対応し、いくつかの問題を修正するために時間とともに進化してきました。ここでは変更点の概要を説明します。
|
||||
|
||||
### `yield` と `scope` を伴う依存関係 { #dependencies-with-yield-and-scope }
|
||||
|
||||
バージョン 0.121.0 で、`yield` を使う依存関係に対して `Depends(scope="function")` がサポートされました。
|
||||
|
||||
`Depends(scope="function")` を使うと、`yield` の後の終了コードは、クライアントへレスポンスが返される前、*path operation 関数* が終了した直後に実行されます。
|
||||
|
||||
そして、`Depends(scope="request")`(デフォルト)を使う場合、`yield` の後の終了コードはレスポンス送信後に実行されます。
|
||||
|
||||
詳しくはドキュメント「[`yield` を使う依存関係 - 早期終了と `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope)」を参照してください。
|
||||
|
||||
### `yield` と `StreamingResponse` を伴う依存関係、技術詳細 { #dependencies-with-yield-and-streamingresponse-technical-details }
|
||||
|
||||
FastAPI 0.118.0 より前では、`yield` を使う依存関係を使用すると、*path operation 関数* が戻ってからレスポンス送信直前に終了コードが実行されていました。
|
||||
|
||||
これは、レスポンスがネットワーク上を移動するのを待っている間に、不要にリソースを保持しないようにする意図でした。
|
||||
|
||||
この変更により、`StreamingResponse` を返す場合、`yield` を持つ依存関係の終了コードはすでに実行されていることになりました。
|
||||
|
||||
たとえば、`yield` を持つ依存関係の中でデータベースセッションを持っていた場合、`StreamingResponse` はデータをストリーミングしている間にそのセッションを使えません。というのも、`yield` の後の終了コードでそのセッションがすでにクローズされているからです。
|
||||
|
||||
この挙動は 0.118.0 で元に戻され、`yield` の後の終了コードはレスポンス送信後に実行されるようになりました。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
以下で見るように、これはバージョン 0.106.0 より前の挙動ととても似ていますが、いくつかのコーナーケースに対する改良とバグ修正が含まれています。
|
||||
|
||||
///
|
||||
|
||||
#### 早期終了コードのユースケース { #use-cases-with-early-exit-code }
|
||||
|
||||
特定の条件では、レスポンス送信前に `yield` を持つ依存関係の終了コードを実行する、古い挙動の恩恵を受けられるユースケースがあります。
|
||||
|
||||
例えば、`yield` を持つ依存関係でデータベースセッションを使ってユーザ検証だけを行い、その後は *path operation 関数* 内ではそのデータベースセッションを一切使わない、かつレスポンス送信に長い時間がかかる(例えばデータをゆっくり送る `StreamingResponse`)が、何らかの理由でデータベースは使わない、というケースです。
|
||||
|
||||
この場合、レスポンスの送信が終わるまでデータベースセッションが保持されますが、使わないのであれば保持する必要はありません。
|
||||
|
||||
次のようになります:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py *}
|
||||
|
||||
終了コード、すなわち `Session` の自動クローズは:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
|
||||
|
||||
...の部分で定義されており、遅いデータ送信が終わった後に実行されます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
|
||||
|
||||
しかし、`generate_stream()` はデータベースセッションを使わないため、レスポンス送信中にセッションを開いたままにしておく必要は実際にはありません。
|
||||
|
||||
SQLModel(または SQLAlchemy)でこの特定のユースケースがある場合は、不要になった時点でセッションを明示的にクローズできます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}
|
||||
|
||||
このようにすると、セッションはデータベース接続を解放するため、他のリクエストがそれを使えるようになります。
|
||||
|
||||
`yield` を持つ依存関係で早期終了が必要な別のユースケースがある場合は、あなたの具体的なユースケースと、なぜ `yield` を持つ依存関係の早期クローズが有益かを説明して、<a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussion の質問</a>を作成してください。
|
||||
|
||||
`yield` を持つ依存関係の早期クローズに納得できるユースケースがある場合は、早期クローズにオプトインする新しい方法を追加することを検討します。
|
||||
|
||||
### `yield` と `except` を伴う依存関係、技術詳細 { #dependencies-with-yield-and-except-technical-details }
|
||||
|
||||
FastAPI 0.110.0 より前では、`yield` を持つ依存関係を使い、その依存関係内で `except` によって例外を捕捉し、再度その例外を送出しなかった場合でも、その例外は自動的に送出(フォワード)され、任意の例外ハンドラまたは内部サーバエラーハンドラに渡されていました。
|
||||
|
||||
これは、ハンドラのないフォワードされた例外(内部サーバエラー)による未処理のメモリ消費を修正し、通常の Python コードの挙動と一貫性を持たせるため、バージョン 0.110.0 で変更されました。
|
||||
|
||||
### バックグラウンドタスクと `yield` を伴う依存関係、技術詳細 { #background-tasks-and-dependencies-with-yield-technical-details }
|
||||
|
||||
FastAPI 0.106.0 より前では、`yield` の後で例外を送出することはできませんでした。`yield` を持つ依存関係の終了コードはレスポンス送信「後」に実行されるため、[例外ハンドラ](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} はすでに実行済みでした。
|
||||
|
||||
これは主に、依存関係が "yield" した同じオブジェクトをバックグラウンドタスク内で利用できるようにするための設計でした。終了コードはバックグラウンドタスク完了後に実行されるからです。
|
||||
|
||||
これは、レスポンスがネットワーク上を移動するのを待っている間にリソースを保持しないようにする意図で、FastAPI 0.106.0 で変更されました。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
加えて、バックグラウンドタスクは通常、独立したロジックの集合であり、(例えば専用のデータベース接続など)それ自身のリソースで個別に扱うべきです。
|
||||
|
||||
そのため、このやり方の方がコードはおそらくよりクリーンになります。
|
||||
|
||||
///
|
||||
|
||||
この挙動に依存していた場合は、バックグラウンドタスク用のリソースをバックグラウンドタスク内部で作成し、`yield` を持つ依存関係のリソースに依存しないデータだけを内部で使用するようにしてください。
|
||||
|
||||
例えば、同じデータベースセッションを使うのではなく、バックグラウンドタスク内で新しいデータベースセッションを作成し、この新しいセッションでデータベースからオブジェクトを取得します。そして、バックグラウンドタスク関数の引数としてデータベースのオブジェクト自体を渡すのではなく、そのオブジェクトの ID を渡し、バックグラウンドタスク関数内でもう一度そのオブジェクトを取得します。
|
||||
@@ -0,0 +1,61 @@
|
||||
# 高度な Python の型 { #advanced-python-types }
|
||||
|
||||
Python の型を扱うときに役立つ追加のアイデアをいくつか紹介します。
|
||||
|
||||
## `Union` または `Optional` の利用 { #using-union-or-optional }
|
||||
|
||||
何らかの理由で `|` が使えない場合、たとえば型アノテーションではなく `response_model=` のような場所では、縦棒(`|`)の代わりに `typing` の `Union` を使えます。
|
||||
|
||||
例えば、`str` または `None` になり得ることを宣言できます:
|
||||
|
||||
```python
|
||||
from typing import Union
|
||||
|
||||
|
||||
def say_hi(name: Union[str, None]):
|
||||
print(f"Hi {name}!")
|
||||
```
|
||||
|
||||
`typing` には、`None` を取り得ることを宣言するための短縮形として `Optional` もあります。
|
||||
|
||||
ここからは私のとても主観的な提案です:
|
||||
|
||||
- 🚨 `Optional[SomeType]` の使用は避けましょう
|
||||
- 代わりに ✨ **`Union[SomeType, None]` を使いましょう** ✨。
|
||||
|
||||
どちらも等価で内部的には同一ですが、「optional(任意)」という語が値が任意だと誤解させやすく、実際の意味は「`None` を取り得る」であり、任意ではなく依然として必須である場合でもそうです。そのため `Optional` より `Union` を勧めます。
|
||||
|
||||
`Union[SomeType, None]` の方が意味がより明確だと思います。
|
||||
|
||||
これは用語や名前付けの話に過ぎませんが、その言葉があなたやチームメイトのコードの捉え方に影響します。
|
||||
|
||||
例として次の関数を見てみましょう:
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def say_hi(name: Optional[str]):
|
||||
print(f"Hey {name}!")
|
||||
```
|
||||
|
||||
パラメータ `name` は `Optional[str]` と定義されていますが、任意ではありません。このパラメータなしで関数を呼び出すことはできません:
|
||||
|
||||
```Python
|
||||
say_hi() # あっ、これはエラーになります!😱
|
||||
```
|
||||
|
||||
`name` パラメータにはデフォルト値がないため、依然として必須(任意ではない)です。ただし、`name` は値として `None` を受け付けます:
|
||||
|
||||
```Python
|
||||
say_hi(name=None) # これは動作します。None は有効です 🎉
|
||||
```
|
||||
|
||||
朗報として、多くの場合は単純に `|` を使って型の Union を定義できます:
|
||||
|
||||
```python
|
||||
def say_hi(name: str | None):
|
||||
print(f"Hey {name}!")
|
||||
```
|
||||
|
||||
したがって、通常は `Optional` や `Union` といった名前を気にする必要はありません。😎
|
||||
@@ -0,0 +1,99 @@
|
||||
# 非同期テスト { #async-tests }
|
||||
|
||||
これまでに、提供されている `TestClient` を使って **FastAPI** アプリケーションをテストする方法を見てきました。ここまでは、`async` 関数を使わない同期テストのみでした。
|
||||
|
||||
テストで非同期関数を使えると、たとえばデータベースへ非同期にクエリする場合などに便利です。非同期データベースライブラリを使いながら、FastAPI アプリにリクエストを送り、その後バックエンドが正しいデータをデータベースに書き込めたかを検証したい、といったケースを想像してください。
|
||||
|
||||
その方法を見ていきます。
|
||||
|
||||
## pytest.mark.anyio { #pytest-mark-anyio }
|
||||
|
||||
テスト内で非同期関数を呼び出したい場合、テスト関数自体も非同期である必要があります。AnyIO はこれを実現するための便利なプラグインを提供しており、特定のテスト関数を非同期で呼び出すことを指定できます。
|
||||
|
||||
## HTTPX { #httpx }
|
||||
|
||||
**FastAPI** アプリケーションが通常の `def` 関数を使っていても、その内側は依然として `async` アプリケーションです。
|
||||
|
||||
`TestClient` は、標準の pytest を使って通常の `def` のテスト関数から非同期の FastAPI アプリを呼び出すための「おまじない」を内部で行います。しかし、その「おまじない」はテスト関数自体が非同期の場合には機能しません。テストを非同期で実行すると、テスト関数内で `TestClient` は使えなくなります。
|
||||
|
||||
`TestClient` は <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> を基に作られており、幸いなことに API のテストには HTTPX を直接利用できます。
|
||||
|
||||
## 例 { #example }
|
||||
|
||||
簡単な例として、[大きなアプリケーション](../tutorial/bigger-applications.md){.internal-link target=_blank} と [テスト](../tutorial/testing.md){.internal-link target=_blank} で説明したものに似たファイル構成を考えます:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ └── test_main.py
|
||||
```
|
||||
|
||||
`main.py` は次のようになります:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/main.py *}
|
||||
|
||||
`test_main.py` は `main.py` のテストを持ち、次のようになります:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py *}
|
||||
|
||||
## 実行 { #run-it }
|
||||
|
||||
テストはいつも通り次で実行できます:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pytest
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## 詳細 { #in-detail }
|
||||
|
||||
マーカー `@pytest.mark.anyio` は、このテスト関数を非同期で呼び出すべきであることを pytest に伝えます:
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`TestClient` を使っていたときと異なり、テスト関数は `def` ではなく `async def` になっている点に注意してください。
|
||||
|
||||
///
|
||||
|
||||
次に、アプリを渡して `AsyncClient` を作成し、`await` を使って非同期リクエストを送信できます。
|
||||
|
||||
{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}
|
||||
|
||||
これは次と同等です:
|
||||
|
||||
```Python
|
||||
response = client.get('/')
|
||||
```
|
||||
|
||||
...これまでは `TestClient` でリクエストを送っていました。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
新しい `AsyncClient` では async/await を使っている点に注意してください。リクエストは非同期です。
|
||||
|
||||
///
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
アプリケーションが lifespan イベントに依存している場合、`AsyncClient` はそれらのイベントをトリガーしません。確実にトリガーするには、<a href="https://github.com/florimondmanca/asgi-lifespan#usage" class="external-link" target="_blank">florimondmanca/asgi-lifespan</a> の `LifespanManager` を使用してください。
|
||||
|
||||
///
|
||||
|
||||
## その他の非同期関数呼び出し { #other-asynchronous-function-calls }
|
||||
|
||||
テスト関数が非同期になったので、FastAPI アプリへのリクエスト送信以外の `async` 関数も、コードの他の場所と同様に呼び出して(`await` して)使えます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
テストに非同期関数呼び出しを統合した際に(例: <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB の MotorClient</a> 使用時)、`RuntimeError: Task attached to a different loop` に遭遇した場合は、イベントループを必要とするオブジェクトは非同期関数内でのみインスタンス化するようにしてください。例えば `@app.on_event("startup")` コールバック内で行います。
|
||||
|
||||
///
|
||||
@@ -0,0 +1,466 @@
|
||||
# プロキシの背後 { #behind-a-proxy }
|
||||
|
||||
多くの状況で、FastAPI アプリの前段に **Traefik** や **Nginx** のような**プロキシ**を置きます。
|
||||
|
||||
これらのプロキシは HTTPS 証明書などの処理を担います。
|
||||
|
||||
## プロキシの転送ヘッダー { #proxy-forwarded-headers }
|
||||
|
||||
アプリケーションの前段にある **プロキシ** は通常、リクエストを **サーバー** に送る前に、そのリクエストがプロキシによって転送されたことを知らせるためのヘッダーを動的に付与し、使用中の元の(公開)URL(ドメインを含む)や HTTPS 使用などの情報を伝えます。
|
||||
|
||||
**サーバー** プログラム(例えば **FastAPI CLI** 経由の **Uvicorn**)はこれらのヘッダーを解釈し、その情報をアプリケーションに渡すことができます。
|
||||
|
||||
しかしセキュリティ上、サーバーは自分が信頼できるプロキシの背後にあると分からないため、これらのヘッダーを解釈しません。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
プロキシのヘッダーは次のとおりです:
|
||||
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
|
||||
|
||||
///
|
||||
|
||||
### プロキシ転送ヘッダーを有効化 { #enable-proxy-forwarded-headers }
|
||||
|
||||
FastAPI CLI を *CLI オプション* `--forwarded-allow-ips` 付きで起動し、転送ヘッダーを信頼して読んでよい IP アドレスを指定できます。
|
||||
|
||||
`--forwarded-allow-ips="*"` とすると、すべての送信元 IP を信頼します。
|
||||
|
||||
**サーバー** が信頼できる **プロキシ** の背後にあり、そのプロキシからのみ接続される場合、プロキシの IP を受け入れるようになります。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run --forwarded-allow-ips="*"
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### HTTPS を伴うリダイレクト { #redirects-with-https }
|
||||
|
||||
例えば、*path operation* `/items/` を定義しているとします:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}
|
||||
|
||||
クライアントが `/items` にアクセスすると、既定では `/items/` にリダイレクトされます。
|
||||
|
||||
しかし、*CLI オプション* `--forwarded-allow-ips` を設定する前は、`http://localhost:8000/items/` にリダイレクトされる場合があります。
|
||||
|
||||
ですが、アプリケーションは `https://mysuperapp.com` で公開されており、`https://mysuperapp.com/items/` にリダイレクトされるべきかもしれません。
|
||||
|
||||
`--proxy-headers` を設定すると、FastAPI は正しい場所にリダイレクトできるようになります。😎
|
||||
|
||||
```
|
||||
https://mysuperapp.com/items/
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
HTTPS について詳しく知りたい場合は、[HTTPS について](../deployment/https.md){.internal-link target=_blank} を参照してください。
|
||||
|
||||
///
|
||||
|
||||
### プロキシ転送ヘッダーの仕組み { #how-proxy-forwarded-headers-work }
|
||||
|
||||
クライアントと **アプリケーションサーバー** の間で、**プロキシ** がどのように転送ヘッダーを追加するかを図示します:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant Proxy as Proxy/Load Balancer
|
||||
participant Server as FastAPI Server
|
||||
|
||||
Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items
|
||||
|
||||
Note over Proxy: Proxy adds forwarded headers
|
||||
|
||||
Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items
|
||||
|
||||
Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)
|
||||
|
||||
Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs
|
||||
|
||||
Proxy->>Client: HTTPS Response
|
||||
```
|
||||
|
||||
**プロキシ** は元のクライアントリクエストを受け取り、**アプリケーションサーバー** に渡す前に特別な「転送」ヘッダー(`X-Forwarded-*`)を追加します。
|
||||
|
||||
これらのヘッダーは、通常は失われる元のリクエストの情報を保持します:
|
||||
|
||||
* **X-Forwarded-For**: 元のクライアントの IP アドレス
|
||||
* **X-Forwarded-Proto**: 元のプロトコル(`https`)
|
||||
* **X-Forwarded-Host**: 元のホスト(`mysuperapp.com`)
|
||||
|
||||
**FastAPI CLI** を `--forwarded-allow-ips` で設定すると、これらのヘッダーを信頼して使用し、たとえばリダイレクトで正しい URL を生成します。
|
||||
|
||||
## パスプレフィックスを削除するプロキシ { #proxy-with-a-stripped-path-prefix }
|
||||
|
||||
アプリケーションにパスプレフィックスを付与するプロキシを使う場合があります。
|
||||
|
||||
そのような場合は `root_path` でアプリケーションを設定できます。
|
||||
|
||||
`root_path` は(FastAPI が Starlette を通して基づいている)ASGI 仕様で提供されている仕組みです。
|
||||
|
||||
`root_path` はこの種のケースを扱うために使われます。
|
||||
|
||||
これはサブアプリケーションをマウントする際にも内部的に使用されます。
|
||||
|
||||
ここでいう「パスプレフィックスを削除するプロキシ」とは、コード上では `/app` というパスを宣言していても、その上にプロキシ層を追加して **FastAPI** アプリケーションを `/api/v1` のようなパスの下に配置することを指します。
|
||||
|
||||
この場合、元のパス `/app` は実際には `/api/v1/app` で提供されます。
|
||||
|
||||
すべてのコードは `/app` だけを前提に書かれているにもかかわらず、です。
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}
|
||||
|
||||
そしてプロキシは、アプリサーバー(おそらく FastAPI CLI 経由の Uvicorn)に転送する前に、その場で **パスプレフィックス** を**「削除」**し、アプリケーション側には自分が `/app` で提供されているように見せかけます。これにより、コードのすべてを `/api/v1` のプレフィックス付きに書き換える必要がありません。
|
||||
|
||||
ここまでは通常どおりに動作します。
|
||||
|
||||
しかし、統合ドキュメント UI(フロントエンド)を開くと、OpenAPI スキーマを `/api/v1/openapi.json` ではなく `/openapi.json` から取得しようとします。
|
||||
|
||||
そのため、フロントエンド(ブラウザで動作)は `/openapi.json` にアクセスしようとして、OpenAPI スキーマを取得できません。
|
||||
|
||||
このアプリには `/api/v1` のパスプレフィックスを付与するプロキシがあるため、フロントエンドは `/api/v1/openapi.json` から取得する必要があります。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
|
||||
browser("Browser")
|
||||
proxy["Proxy on http://0.0.0.0:9999/api/v1/app"]
|
||||
server["Server on http://127.0.0.1:8000/app"]
|
||||
|
||||
browser --> proxy
|
||||
proxy --> server
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
IP `0.0.0.0` は、そのマシン/サーバーで利用可能なすべての IP で待ち受けることを意味する表現として一般的に使われます。
|
||||
|
||||
///
|
||||
|
||||
ドキュメント UI では、この API の `server` が(プロキシの背後で)`/api/v1` にあることを宣言する OpenAPI スキーマも必要です。例えば:
|
||||
|
||||
```JSON hl_lines="4-8"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
// ほかの項目
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// ほかの項目
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
この例では「Proxy」は **Traefik** のようなもの、サーバーは **Uvicorn** と FastAPI CLI で FastAPI アプリケーションを実行しているものを想定しています。
|
||||
|
||||
### `root_path` の指定 { #providing-the-root-path }
|
||||
|
||||
これを実現するには、次のようにコマンドラインオプション `--root-path` を使用します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Hypercorn を使う場合も、同様に `--root-path` オプションがあります。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
このユースケース向けに、ASGI 仕様は `root_path` を定義しています。
|
||||
|
||||
そして `--root-path` コマンドラインオプションは、その `root_path` を提供します。
|
||||
|
||||
///
|
||||
|
||||
### 現在の `root_path` の確認 { #checking-the-current-root-path }
|
||||
|
||||
各リクエストでアプリケーションが使用している現在の `root_path` は取得できます。これは(ASGI 仕様の一部である)`scope` 辞書に含まれます。
|
||||
|
||||
ここではデモのため、メッセージに含めています。
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}
|
||||
|
||||
そのうえで、次のように Uvicorn を起動すると:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
レスポンスは次のようになります:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
### FastAPI アプリでの `root_path` 設定 { #setting-the-root-path-in-the-fastapi-app }
|
||||
|
||||
あるいは、`--root-path` のようなコマンドラインオプションを渡せない場合は、FastAPI アプリ作成時にパラメータ `root_path` を設定できます:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}
|
||||
|
||||
`FastAPI` に `root_path` を渡すのは、Uvicorn や Hypercorn にコマンドラインオプション `--root-path` を渡すのと同等です。
|
||||
|
||||
### `root_path` について { #about-root-path }
|
||||
|
||||
サーバー(Uvicorn)は、その `root_path` をアプリに渡す以外の用途では使用しない点に注意してください。
|
||||
|
||||
しかし、ブラウザで <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a> にアクセスすると、通常どおりのレスポンスが表示されます:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
つまり、`http://127.0.0.1:8000/api/v1/app` でアクセスされることは想定していません。
|
||||
|
||||
Uvicorn は、プロキシが `http://127.0.0.1:8000/app` にアクセスしてくることを想定しており、その上に追加の `/api/v1` プレフィックスを付けるのはプロキシの責務です。
|
||||
|
||||
## パスプレフィックスを削除するプロキシについて { #about-proxies-with-a-stripped-path-prefix }
|
||||
|
||||
パスプレフィックスを削除するプロキシは、設定方法の一例にすぎない点に注意してください。
|
||||
|
||||
多くの場合、プロキシはパスプレフィックスを削除しない設定が既定でしょう。
|
||||
|
||||
そのような場合(パスプレフィックスを削除しない場合)は、プロキシは `https://myawesomeapp.com` のようなアドレスで待ち受け、ブラウザが `https://myawesomeapp.com/api/v1/app` にアクセスし、サーバー(例: Uvicorn)が `http://127.0.0.1:8000` で待ち受けているなら、プロキシ(プレフィックスを削除しない)は同じパス `http://127.0.0.1:8000/api/v1/app` で Uvicorn にアクセスします。
|
||||
|
||||
## Traefik を使ったローカル検証 { #testing-locally-with-traefik }
|
||||
|
||||
<a href="https://docs.traefik.io/" class="external-link" target="_blank">Traefik</a> を使えば、パスプレフィックスを削除する構成をローカルで簡単に試せます。
|
||||
|
||||
<a href="https://github.com/containous/traefik/releases" class="external-link" target="_blank">Traefik をダウンロード</a> してください。単一バイナリなので、圧縮ファイルを展開して端末から直接実行できます。
|
||||
|
||||
次の内容で `traefik.toml` というファイルを作成します:
|
||||
|
||||
```TOML hl_lines="3"
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":9999"
|
||||
|
||||
[providers]
|
||||
[providers.file]
|
||||
filename = "routes.toml"
|
||||
```
|
||||
|
||||
これは Traefik にポート 9999 で待ち受け、別のファイル `routes.toml` を使用するよう指示します。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
標準の HTTP ポート 80 ではなく 9999 を使うのは、管理者(`sudo`)権限で実行する必要をなくすためです。
|
||||
|
||||
///
|
||||
|
||||
次に、その `routes.toml` ファイルを作成します:
|
||||
|
||||
```TOML hl_lines="5 12 20"
|
||||
[http]
|
||||
[http.middlewares]
|
||||
|
||||
[http.middlewares.api-stripprefix.stripPrefix]
|
||||
prefixes = ["/api/v1"]
|
||||
|
||||
[http.routers]
|
||||
|
||||
[http.routers.app-http]
|
||||
entryPoints = ["http"]
|
||||
service = "app"
|
||||
rule = "PathPrefix(`/api/v1`)"
|
||||
middlewares = ["api-stripprefix"]
|
||||
|
||||
[http.services]
|
||||
|
||||
[http.services.app]
|
||||
[http.services.app.loadBalancer]
|
||||
[[http.services.app.loadBalancer.servers]]
|
||||
url = "http://127.0.0.1:8000"
|
||||
```
|
||||
|
||||
このファイルは Traefik に `/api/v1` のパスプレフィックスを使うよう設定します。
|
||||
|
||||
そして Traefik は、`http://127.0.0.1:8000` で動作している Uvicorn へリクエストを転送します。
|
||||
|
||||
では Traefik を起動します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ ./traefik --configFile=traefik.toml
|
||||
|
||||
INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
次に、`--root-path` オプションを指定してアプリを起動します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### レスポンスの確認 { #check-the-responses }
|
||||
|
||||
ここで、Uvicorn のポートの URL <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a> にアクセスすると、通常どおりのレスポンスが表示されます:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`http://127.0.0.1:8000/app` にアクセスしているにもかかわらず、オプション `--root-path` から取得した `root_path` が `/api/v1` と表示されている点に注目してください。
|
||||
|
||||
///
|
||||
|
||||
次に、Traefik のポートでプレフィックス付きの URL <a href="http://127.0.0.1:9999/api/v1/app" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/app</a> を開きます。
|
||||
|
||||
同じレスポンスが得られます:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World",
|
||||
"root_path": "/api/v1"
|
||||
}
|
||||
```
|
||||
|
||||
ただし今回は、プロキシが付与したプレフィックス `/api/v1` の付いた URL です。
|
||||
|
||||
もちろん、ここでの想定は全員がプロキシ経由でアプリにアクセスすることです。したがって、パスプレフィックス `/api/v1` のある版が「正しい」アクセス方法になります。
|
||||
|
||||
一方、プレフィックスのない版(`http://127.0.0.1:8000/app`。Uvicorn が直接提供)は、_プロキシ_(Traefik)専用の接続先になります。
|
||||
|
||||
これにより、プロキシ(Traefik)がパスプレフィックスをどのように用い、サーバー(Uvicorn)が `--root-path` の `root_path` をどのように利用するかが分かります。
|
||||
|
||||
### ドキュメント UI の確認 { #check-the-docs-ui }
|
||||
|
||||
ここがポイントです。✨
|
||||
|
||||
「公式な」アクセス方法は、定義したパスプレフィックス付きのプロキシ経由です。したがって想定どおり、プレフィックスなしの URL で Uvicorn が直接提供するドキュメント UI にアクセスすると動作しません。プロキシ経由でアクセスされることを前提としているためです。
|
||||
|
||||
<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> を確認してください:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image01.png">
|
||||
|
||||
しかし、プロキシ(ポート `9999`)を使った「公式」URL `/api/v1/docs` でドキュメント UI にアクセスすると、正しく動作します!🎉
|
||||
|
||||
<a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a> を確認してください:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image02.png">
|
||||
|
||||
ねらいどおりです。✔️
|
||||
|
||||
これは、FastAPI が `root_path` を使って、OpenAPI の既定の `server` を `root_path` の URL で生成するためです。
|
||||
|
||||
## 追加のサーバー { #additional-servers }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
これは高度なユースケースです。読み飛ばしても構いません。
|
||||
|
||||
///
|
||||
|
||||
既定では、**FastAPI** は OpenAPI スキーマ内に `root_path` の URL を持つ `server` を作成します。
|
||||
|
||||
しかし、ステージングと本番の両方と同じドキュメント UI で対話させたい場合など、別の `servers` を指定することもできます。
|
||||
|
||||
カスタムの `servers` リストを渡していて、かつ `root_path`(API がプロキシの背後にあるため)が設定されている場合、**FastAPI** はこの `root_path` を用いた「server」をリストの先頭に挿入します。
|
||||
|
||||
例えば:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}
|
||||
|
||||
次のような OpenAPI スキーマが生成されます:
|
||||
|
||||
```JSON hl_lines="5-7"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
// ほかの項目
|
||||
"servers": [
|
||||
{
|
||||
"url": "/api/v1"
|
||||
},
|
||||
{
|
||||
"url": "https://stag.example.com",
|
||||
"description": "Staging environment"
|
||||
},
|
||||
{
|
||||
"url": "https://prod.example.com",
|
||||
"description": "Production environment"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
// ほかの項目
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`root_path` から取得した `url` 値 `/api/v1` を持つ server が自動生成されている点に注目してください。
|
||||
|
||||
///
|
||||
|
||||
ドキュメント UI(<a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a>)では次のように表示されます:
|
||||
|
||||
<img src="/img/tutorial/behind-a-proxy/image03.png">
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ドキュメント UI は、選択した server と対話します。
|
||||
|
||||
///
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
OpenAPI 仕様の `servers` プロパティは任意です。
|
||||
|
||||
`servers` パラメータを指定せず、かつ `root_path` が `/` の場合、生成される OpenAPI スキーマからは `servers` プロパティが既定で完全に省略されます。これは、`url` が `/` の server が 1 つあるのと同等です。
|
||||
|
||||
///
|
||||
|
||||
### `root_path` 由来の自動 server を無効化 { #disable-automatic-server-from-root-path }
|
||||
|
||||
`root_path` を用いた自動的な server を **FastAPI** に含めてほしくない場合は、パラメータ `root_path_in_servers=False` を使用します:
|
||||
|
||||
{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}
|
||||
|
||||
すると、OpenAPI スキーマには含まれません。
|
||||
|
||||
## サブアプリケーションのマウント { #mounting-a-sub-application }
|
||||
|
||||
`root_path` を伴うプロキシを使用しつつサブアプリケーションをマウントする必要がある場合でも([サブアプリケーション - マウント](sub-applications.md){.internal-link target=_blank} 参照)、通常どおりに行えます。
|
||||
|
||||
FastAPI は内部で `root_path` を適切に扱うため、そのまま動作します。✨
|
||||
@@ -1,34 +1,40 @@
|
||||
# カスタムレスポンス - HTML、ストリーム、ファイル、その他のレスポンス
|
||||
# カスタムレスポンス - HTML、ストリーム、ファイル、その他のレスポンス { #custom-response-html-stream-file-others }
|
||||
|
||||
デフォルトでは、**FastAPI** は `JSONResponse` を使ってレスポンスを返します。
|
||||
|
||||
[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、 `Response` を直接返すことでこの挙動をオーバーライドできます。
|
||||
|
||||
しかし、`Response` を直接返すと、データは自動的に変換されず、ドキュメントも自動生成されません (例えば、生成されるOpenAPIの一部としてHTTPヘッダー `Content-Type` に特定の「メディアタイプ」を含めるなど) 。
|
||||
しかし、`Response` を直接返すと(または `JSONResponse` のような任意のサブクラスを返すと)、データは自動的に変換されず(`response_model` を宣言していても)、ドキュメントも自動生成されません(例えば、生成されるOpenAPIの一部としてHTTPヘッダー `Content-Type` に特定の「メディアタイプ」を含めるなど)。
|
||||
|
||||
しかし、*path operationデコレータ* に、使いたい `Response` を宣言することもできます。
|
||||
`response_class` パラメータを使用して、*path operation デコレータ* で使用したい `Response`(任意の `Response` サブクラス)を宣言することもできます。
|
||||
|
||||
*path operation関数* から返されるコンテンツは、その `Response` に含まれます。
|
||||
*path operation 関数* から返されるコンテンツは、その `Response` に含まれます。
|
||||
|
||||
そしてもし、`Response` が、`JSONResponse` や `UJSONResponse` の場合のようにJSONメディアタイプ (`application/json`) ならば、データは *path operationデコレータ* に宣言したPydantic `response_model` により自動的に変換 (もしくはフィルタ) されます。
|
||||
そしてその `Response` が、`JSONResponse` や `UJSONResponse` の場合のようにJSONメディアタイプ(`application/json`)なら、関数の返り値は *path operationデコレータ* に宣言した任意のPydantic `response_model` により自動的に変換(およびフィルタ)されます。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
メディアタイプを指定せずにレスポンスクラスを利用すると、FastAPIは何もコンテンツがないことを期待します。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットが記載されません。
|
||||
メディアタイプを指定せずにレスポンスクラスを利用すると、FastAPIはレスポンスにコンテンツがないことを期待します。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットが記載されません。
|
||||
|
||||
///
|
||||
|
||||
## `ORJSONResponse` を使う
|
||||
## `ORJSONResponse` を使う { #use-orjsonresponse }
|
||||
|
||||
例えば、パフォーマンスを出したい場合は、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>をインストールし、`ORJSONResponse`をレスポンスとしてセットすることができます。
|
||||
例えば、パフォーマンスを絞り出したい場合は、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>をインストールし、レスポンスとして `ORJSONResponse` をセットできます。
|
||||
|
||||
使いたい `Response` クラス (サブクラス) をインポートし、 *path operationデコレータ* に宣言します。
|
||||
使いたい `Response` クラス(サブクラス)をインポートし、*path operationデコレータ* に宣言します。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *}
|
||||
大きなレスポンスの場合、`Response` を直接返すほうが、辞書を返すよりもはるかに高速です。
|
||||
|
||||
これは、デフォルトではFastAPIがチュートリアルで説明した同じ[JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}を使って、内部の各アイテムを検査し、JSONとしてシリアライズ可能であることを確認するためです。これにより、例えばデータベースモデルのような**任意のオブジェクト**を返せます。
|
||||
|
||||
しかし、返そうとしているコンテンツが **JSONでシリアライズ可能**であることが確実なら、それを直接レスポンスクラスに渡して、FastAPIがレスポンスクラスへ渡す前に返却コンテンツを `jsonable_encoder` に通すことで発生する追加のオーバーヘッドを回避できます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するために利用することもできます。
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するためにも利用されます。
|
||||
|
||||
この場合、HTTPヘッダー `Content-Type` には `application/json` がセットされます。
|
||||
|
||||
@@ -38,70 +44,70 @@
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`ORJSONResponse` は、現在はFastAPIのみで利用可能で、Starletteでは利用できません。
|
||||
`ORJSONResponse` はFastAPIでのみ利用可能で、Starletteでは利用できません。
|
||||
|
||||
///
|
||||
|
||||
## HTMLレスポンス
|
||||
## HTMLレスポンス { #html-response }
|
||||
|
||||
**FastAPI** からHTMLを直接返す場合は、`HTMLResponse` を使います。
|
||||
|
||||
* `HTMLResponse` をインポートする。
|
||||
* *path operation* のパラメータ `content_type` に `HTMLResponse` を渡す。
|
||||
* *path operation デコレータ* のパラメータ `response_class` に `HTMLResponse` を渡す。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するために利用されます。
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するためにも利用されます。
|
||||
|
||||
この場合、HTTPヘッダー `Content-Type` には `text/html` がセットされます。
|
||||
|
||||
そして、OpenAPIにはそのようにドキュメント化されます。
|
||||
そして、OpenAPIにはそのようにドキュメントされます。
|
||||
|
||||
///
|
||||
|
||||
### `Response` を返す
|
||||
### `Response` を返す { #return-a-response }
|
||||
|
||||
[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、レスポンスを直接返すことで、*path operation* の中でレスポンスをオーバーライドできます。
|
||||
[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、レスポンスを返すことで、*path operation* の中でレスポンスを直接オーバーライドすることもできます。
|
||||
|
||||
上記と同じ例において、 `HTMLResponse` を返すと、このようになります:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *}
|
||||
{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
*path operation関数* から直接返される `Response` は、OpenAPIにドキュメントされず (例えば、 `Content-Type` がドキュメントされない) 、自動的な対話的ドキュメントからも閲覧できません。
|
||||
*path operation関数* から直接返される `Response` は、OpenAPIにドキュメントされず(例えば、`Content-Type` がドキュメントされない)、自動的な対話的ドキュメントでも表示されません。
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
|
||||
もちろん、実際の `Content-Type` ヘッダーやステータスコードなどは、返された `Response` オブジェクトに由来しています。
|
||||
もちろん、実際の `Content-Type` ヘッダーやステータスコードなどは、返された `Response` オブジェクトに由来します。
|
||||
|
||||
///
|
||||
|
||||
### OpenAPIドキュメントと `Response` のオーバーライド
|
||||
### OpenAPIドキュメントと `Response` のオーバーライド { #document-in-openapi-and-override-response }
|
||||
|
||||
関数の中でレスポンスをオーバーライドしつつも、OpenAPI に「メディアタイプ」をドキュメント化したいなら、 `response_class` パラメータを使い、 `Response` オブジェクトを返します。
|
||||
関数の中でレスポンスをオーバーライドしつつも、OpenAPI に「メディアタイプ」をドキュメント化したいなら、`response_class` パラメータを使用し、かつ `Response` オブジェクトを返します。
|
||||
|
||||
`response_class` はOpenAPIの *path operation* ドキュメントにのみ使用されますが、 `Response` はそのまま使用されます。
|
||||
`response_class` はOpenAPIの*path operation*のドキュメント化のためにのみ使用され、`Response` はそのまま使用されます。
|
||||
|
||||
#### `HTMLResponse` を直接返す
|
||||
#### `HTMLResponse` を直接返す { #return-an-htmlresponse-directly }
|
||||
|
||||
例えば、このようになります:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *}
|
||||
{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
|
||||
|
||||
この例では、関数 `generate_html_response()` は、`str` のHTMLを返すのではなく `Response` を生成して返しています。
|
||||
この例では、関数 `generate_html_response()` は、`str` のHTMLを返すのではなく、`Response` を生成して返しています。
|
||||
|
||||
`generate_html_response()` を呼び出した結果を返すことにより、**FastAPI** の振る舞いを上書きする `Response` が既に返されています。
|
||||
`generate_html_response()` を呼び出した結果を返すことにより、デフォルトの **FastAPI** の挙動をオーバーライドする `Response` をすでに返しています。
|
||||
|
||||
しかし、一方では `response_class` に `HTMLResponse` を渡しているため、 **FastAPI** はOpenAPIや対話的ドキュメントでHTMLとして `text/html` でドキュメント化する方法を知っています。
|
||||
しかし、`response_class` にも `HTMLResponse` を渡しているため、**FastAPI** はOpenAPIと対話的ドキュメントで、`text/html` のHTMLとしてどのようにドキュメント化すればよいかを理解できます:
|
||||
|
||||
<img src="/img/tutorial/custom-response/image01.png">
|
||||
|
||||
## 利用可能なレスポンス
|
||||
## 利用可能なレスポンス { #available-responses }
|
||||
|
||||
以下が利用可能なレスポンスの一部です。
|
||||
|
||||
@@ -111,11 +117,11 @@
|
||||
|
||||
`from starlette.responses import HTMLResponse` も利用できます。
|
||||
|
||||
**FastAPI** は開発者の利便性のために `fastapi.responses` として `starlette.responses` と同じものを提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。
|
||||
**FastAPI** は開発者の利便性のために、`starlette.responses` と同じものを `fastapi.responses` として提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。
|
||||
|
||||
///
|
||||
|
||||
### `Response`
|
||||
### `Response` { #response }
|
||||
|
||||
メインの `Response` クラスで、他の全てのレスポンスはこれを継承しています。
|
||||
|
||||
@@ -128,41 +134,53 @@
|
||||
* `headers` - 文字列の `dict` 。
|
||||
* `media_type` - メディアタイプを示す `str` 。例えば `"text/html"` 。
|
||||
|
||||
FastAPI (実際にはStarlette) は自動的にContent-Lengthヘッダーを含みます。また、media_typeに基づいたContent-Typeヘッダーを含み、テキストタイプのためにcharsetを追加します。
|
||||
FastAPI(実際にはStarlette)は自動的にContent-Lengthヘッダーを含みます。また、`media_type` に基づいたContent-Typeヘッダーを含み、テキストタイプのためにcharsetを追加します。
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
|
||||
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
|
||||
|
||||
### `HTMLResponse`
|
||||
### `HTMLResponse` { #htmlresponse }
|
||||
|
||||
上で読んだように、テキストやバイトを受け取り、HTMLレスポンスを返します。
|
||||
|
||||
### `PlainTextResponse`
|
||||
### `PlainTextResponse` { #plaintextresponse }
|
||||
|
||||
テキストやバイトを受け取り、プレーンテキストのレスポンスを返します。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *}
|
||||
{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
|
||||
|
||||
### `JSONResponse`
|
||||
### `JSONResponse` { #jsonresponse }
|
||||
|
||||
データを受け取り、 `application/json` としてエンコードされたレスポンスを返します。
|
||||
データを受け取り、`application/json` としてエンコードされたレスポンスを返します。
|
||||
|
||||
上で読んだように、**FastAPI** のデフォルトのレスポンスとして利用されます。
|
||||
|
||||
### `ORJSONResponse`
|
||||
### `ORJSONResponse` { #orjsonresponse }
|
||||
|
||||
上で読んだように、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>を使った、高速な代替のJSONレスポンスです。
|
||||
|
||||
### `UJSONResponse`
|
||||
/// info | 情報
|
||||
|
||||
<a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>を使った、代替のJSONレスポンスです。
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
`ujson` は、いくつかのエッジケースの取り扱いについて、Pythonにビルトインされた実装よりも作りこまれていません。
|
||||
これは、例えば `pip install orjson` で `orjson` をインストールする必要があります。
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *}
|
||||
### `UJSONResponse` { #ujsonresponse }
|
||||
|
||||
<a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>を使った、代替のJSONレスポンスです。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
これは、例えば `pip install ujson` で `ujson` をインストールする必要があります。
|
||||
|
||||
///
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
`ujson` は、いくつかのエッジケースの取り扱いについて、Pythonにビルトインされた実装ほど注意深くありません。
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -170,33 +188,61 @@ FastAPI (実際にはStarlette) は自動的にContent-Lengthヘッダーを含
|
||||
|
||||
///
|
||||
|
||||
### `RedirectResponse`
|
||||
### `RedirectResponse` { #redirectresponse }
|
||||
|
||||
HTTPリダイレクトを返します。デフォルトでは307ステータスコード (Temporary Redirect) となります。
|
||||
HTTPリダイレクトを返します。デフォルトでは307ステータスコード(Temporary Redirect)となります。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *}
|
||||
`RedirectResponse` を直接返せます:
|
||||
|
||||
### `StreamingResponse`
|
||||
{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}
|
||||
|
||||
非同期なジェネレータか通常のジェネレータ・イテレータを受け取り、レスポンスボディをストリームします。
|
||||
---
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *}
|
||||
または、`response_class` パラメータで使用できます:
|
||||
|
||||
#### `StreamingResponse` をファイルライクなオブジェクトとともに使う
|
||||
{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
|
||||
|
||||
ファイルライクなオブジェクト (例えば、 `open()` で返されたオブジェクト) がある場合、 `StreamingResponse` に含めて返すことができます。
|
||||
その場合、*path operation*関数からURLを直接返せます。
|
||||
|
||||
これにはクラウドストレージとの連携や映像処理など、多くのライブラリが含まれています。
|
||||
この場合に使用される `status_code` は `RedirectResponse` のデフォルトである `307` になります。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *}
|
||||
---
|
||||
|
||||
また、`status_code` パラメータを `response_class` パラメータと組み合わせて使うこともできます:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
|
||||
|
||||
### `StreamingResponse` { #streamingresponse }
|
||||
|
||||
非同期ジェネレータ、または通常のジェネレータ/イテレータを受け取り、レスポンスボディをストリームします。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *}
|
||||
|
||||
#### ファイルライクオブジェクトで `StreamingResponse` を使う { #using-streamingresponse-with-file-like-objects }
|
||||
|
||||
<a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> オブジェクト(例: `open()` で返されるオブジェクト)がある場合、そのfile-likeオブジェクトを反復処理するジェネレータ関数を作れます。
|
||||
|
||||
そうすれば、最初にすべてをメモリへ読み込む必要はなく、そのジェネレータ関数を `StreamingResponse` に渡して返せます。
|
||||
|
||||
これにはクラウドストレージとの連携、映像処理など、多くのライブラリが含まれます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
|
||||
|
||||
1. これはジェネレータ関数です。内部に `yield` 文を含むため「ジェネレータ関数」です。
|
||||
2. `with` ブロックを使うことで、ジェネレータ関数が終わった後(つまりレスポンスの送信が完了した後)にfile-likeオブジェクトが確実にクローズされるようにします。
|
||||
3. この `yield from` は、`file_like` という名前のものを反復処理するように関数へ指示します。そして反復された各パートについて、そのパートをこのジェネレータ関数(`iterfile`)から来たものとして `yield` します。
|
||||
|
||||
つまり、内部的に「生成」の作業を別のものへ移譲するジェネレータ関数です。
|
||||
|
||||
このようにすることで `with` ブロックに入れられ、完了後にfile-likeオブジェクトが確実にクローズされます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ここでは `async` や `await` をサポートしていない標準の `open()` を使っているので、通常の `def` でpath operationを宣言していることに注意してください。
|
||||
ここでは `async` と `await` をサポートしていない標準の `open()` を使っているため、通常の `def` でpath operationを宣言している点に注意してください。
|
||||
|
||||
///
|
||||
|
||||
### `FileResponse`
|
||||
### `FileResponse` { #fileresponse }
|
||||
|
||||
レスポンスとしてファイルを非同期的にストリームします。
|
||||
|
||||
@@ -204,29 +250,63 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
|
||||
|
||||
* `path` - ストリームするファイルのファイルパス。
|
||||
* `headers` - 含めたい任意のカスタムヘッダーの辞書。
|
||||
* `media_type` - メディアタイプを示す文字列。セットされなかった場合は、ファイル名やパスからメディアタイプが推察されます。
|
||||
* `filename` - セットされた場合、レスポンスの `Content-Disposition` に含まれます。
|
||||
* `media_type` - メディアタイプを示す文字列。未設定の場合、ファイル名やパスからメディアタイプが推測されます。
|
||||
* `filename` - 設定した場合、レスポンスの `Content-Disposition` に含まれます。
|
||||
|
||||
ファイルレスポンスには、適切な `Content-Length` 、 `Last-Modified` 、 `ETag` ヘッダーが含まれます。
|
||||
ファイルレスポンスには、適切な `Content-Length`、`Last-Modified`、`ETag` ヘッダーが含まれます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *}
|
||||
{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}
|
||||
|
||||
## デフォルトレスポンスクラス
|
||||
`response_class` パラメータを使うこともできます:
|
||||
|
||||
**FastAPI** クラスのインスタンスか `APIRouter` を生成するときに、デフォルトのレスポンスクラスを指定できます。
|
||||
{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
|
||||
|
||||
定義するためのパラメータは、 `default_response_class` です。
|
||||
この場合、*path operation*関数からファイルパスを直接返せます。
|
||||
|
||||
以下の例では、 **FastAPI** は、全ての *path operation* で `JSONResponse` の代わりに `ORJSONResponse` をデフォルトとして利用します。
|
||||
## カスタムレスポンスクラス { #custom-response-class }
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *}
|
||||
`Response` を継承した独自のカスタムレスポンスクラスを作成して利用できます。
|
||||
|
||||
例えば、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>を使いたいが、同梱の `ORJSONResponse` クラスで使われていないカスタム設定も使いたいとします。
|
||||
|
||||
例えば、インデントされ整形されたJSONを返したいので、orjsonオプション `orjson.OPT_INDENT_2` を使いたいとします。
|
||||
|
||||
`CustomORJSONResponse` を作れます。主に必要なのは、コンテンツを `bytes` として返す `Response.render(content)` メソッドを作ることです:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
|
||||
|
||||
これまでは次のように返していたものが:
|
||||
|
||||
```json
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
...このレスポンスでは次のように返されます:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Hello World"
|
||||
}
|
||||
```
|
||||
|
||||
もちろん、JSONの整形よりも、これを活用するもっと良い方法が見つかるはずです。 😉
|
||||
|
||||
## デフォルトレスポンスクラス { #default-response-class }
|
||||
|
||||
**FastAPI** クラスのインスタンス、または `APIRouter` を作成する際に、デフォルトで使用するレスポンスクラスを指定できます。
|
||||
|
||||
これを定義するパラメータは `default_response_class` です。
|
||||
|
||||
以下の例では、**FastAPI** はすべての*path operation*で、`JSONResponse` の代わりに `ORJSONResponse` をデフォルトとして使います。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
前に見たように、 *path operation* の中で `response_class` をオーバーライドできます。
|
||||
これまでと同様に、*path operation*で `response_class` をオーバーライドできます。
|
||||
|
||||
///
|
||||
|
||||
## その他のドキュメント
|
||||
## その他のドキュメント { #additional-documentation }
|
||||
|
||||
また、OpenAPIでは `responses` を使ってメディアタイプやその他の詳細を宣言することもできます: [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}
|
||||
OpenAPIでは `responses` を使ってメディアタイプやその他の詳細を宣言することもできます: [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}。
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# Dataclasses の使用 { #using-dataclasses }
|
||||
|
||||
FastAPI は **Pydantic** の上に構築されており、これまでにリクエストやレスポンスを宣言するために Pydantic モデルを使う方法を紹介してきました。
|
||||
|
||||
しかし FastAPI は、同様の方法で <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a> もサポートします:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
|
||||
|
||||
これは **Pydantic** によって引き続きサポートされています。Pydantic には <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">`dataclasses` の内部サポート</a> があるためです。
|
||||
|
||||
そのため、上記のように明示的に Pydantic を使っていないコードでも、FastAPI は標準の dataclass を Pydantic 独自の dataclass に変換するために Pydantic を使用しています。
|
||||
|
||||
そして当然ながら、次の点も同様にサポートされます:
|
||||
|
||||
- データ検証
|
||||
- データのシリアライズ
|
||||
- データのドキュメント化 など
|
||||
|
||||
これは Pydantic モデルの場合と同じように動作します。内部的にも同様に Pydantic を使って実現されています。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
dataclasses は、Pydantic モデルができることをすべては行えない点に留意してください。
|
||||
|
||||
そのため、Pydantic モデルを使う必要がある場合もあります。
|
||||
|
||||
しかし既存の dataclass が多数あるなら、FastAPI で Web API を構築する際にそれらを活用するちょっとしたテクニックになります。🤓
|
||||
|
||||
///
|
||||
|
||||
## `response_model` での dataclasses { #dataclasses-in-response-model }
|
||||
|
||||
`response_model` パラメータでも `dataclasses` を使用できます:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}
|
||||
|
||||
dataclass は自動的に Pydantic の dataclass に変換されます。
|
||||
|
||||
このため、そのスキーマは API ドキュメントの UI に表示されます:
|
||||
|
||||
<img src="/img/tutorial/dataclasses/image01.png">
|
||||
|
||||
## ネストしたデータ構造での dataclasses { #dataclasses-in-nested-data-structures }
|
||||
|
||||
`dataclasses` を他の型注釈と組み合わせて、ネストしたデータ構造を作成できます。
|
||||
|
||||
場合によっては、自動生成された API ドキュメントでエラーが発生するなどの理由で、Pydantic 版の `dataclasses` を使う必要があるかもしれません。
|
||||
|
||||
その場合は、標準の `dataclasses` を `pydantic.dataclasses` に置き換えるだけで済みます。これはドロップイン置換です:
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
|
||||
|
||||
1. 依然として標準の `dataclasses` から `field` をインポートします。
|
||||
|
||||
2. `pydantic.dataclasses` は `dataclasses` のドロップイン置換です。
|
||||
|
||||
3. `Author` dataclass は `Item` dataclass のリストを含みます。
|
||||
|
||||
4. `Author` dataclass を `response_model` パラメータとして使用しています。
|
||||
|
||||
5. リクエストボディとしての dataclass と併せて、他の標準の型注釈を使用できます。
|
||||
|
||||
この例では、`Item` dataclass のリストです。
|
||||
|
||||
6. ここでは、dataclass のリストである `items` を含む辞書を返しています。
|
||||
|
||||
FastAPI はデータを JSON に <dfn title="送信可能な形式にデータを変換すること">シリアライズ</dfn> できます。
|
||||
|
||||
7. ここでは `response_model` に `Author` dataclass のリストという型注釈を使用しています。
|
||||
|
||||
このように、`dataclasses` は標準の型注釈と組み合わせられます。
|
||||
|
||||
8. この *path operation 関数* は、`async def` ではなく通常の `def` を使用しています。
|
||||
|
||||
いつもどおり、FastAPI では必要に応じて `def` と `async def` を組み合わせられます。
|
||||
|
||||
どちらをいつ使うかの復習が必要な場合は、[`async` と `await`](../async.md#in-a-hurry){.internal-link target=_blank} に関するドキュメントの _"In a hurry?"_ セクションを参照してください。
|
||||
|
||||
9. この *path operation 関数* は(可能ではありますが)dataclass 自体は返さず、内部データを持つ辞書のリストを返しています。
|
||||
|
||||
FastAPI は dataclass を含む `response_model` パラメータを使ってレスポンスを変換します。
|
||||
|
||||
`dataclasses` は他の型注釈と多様な組み合わせが可能で、複雑なデータ構造を構成できます。
|
||||
|
||||
上記のコード内コメントのヒントを参照して、より具体的な詳細を確認してください。
|
||||
|
||||
## さらに学ぶ { #learn-more }
|
||||
|
||||
`dataclasses` を他の Pydantic モデルと組み合わせたり、継承したり、自分のモデルに含めたりもできます。
|
||||
|
||||
詳しくは、<a href="https://docs.pydantic.dev/latest/concepts/dataclasses/" class="external-link" target="_blank">dataclasses に関する Pydantic ドキュメント</a> を参照してください。
|
||||
|
||||
## バージョン { #version }
|
||||
|
||||
これは FastAPI バージョン `0.67.0` 以降で利用可能です。🔖
|
||||
@@ -0,0 +1,165 @@
|
||||
# Lifespan イベント { #lifespan-events }
|
||||
|
||||
アプリケーションが起動する前に一度だけ実行すべきロジック(コード)を定義できます。これは、アプリケーションがリクエストを受け取り始める前に、そのコードが一度だけ実行される、という意味です。
|
||||
|
||||
同様に、アプリケーションがシャットダウンするときに実行すべきロジック(コード)も定義できます。この場合、そのコードは、(多くのリクエストを処理した)後に一度だけ実行されます。
|
||||
|
||||
このコードは、アプリケーションがリクエストの受け付けを「開始」する前、そして処理を「終了」した直後に実行されるため、アプリケーションの全体の「Lifespan」(この「lifespan」という言葉はすぐ後で重要になります 😉)をカバーします。
|
||||
|
||||
これは、アプリ全体で使用し、リクエスト間で「共有」し、かつ後で「クリーンアップ」する必要があるような「リソース」をセットアップするのにとても便利です。たとえば、データベース接続プールや、共有の機械学習モデルの読み込みなどです。
|
||||
|
||||
## ユースケース { #use-case }
|
||||
|
||||
まずはユースケースの例から始めて、これをどのように解決するかを見ていきます。
|
||||
|
||||
リクエストを処理するために使用したい「機械学習モデル」がいくつかあると想像してください。🤖
|
||||
|
||||
同じモデルをリクエスト間で共有するので、リクエストごとやユーザーごとに別々のモデルを使うわけではありません。
|
||||
|
||||
モデルの読み込みにはディスクから大量のデータを読む必要があり、かなり時間がかかるかもしれません。したがって、リクエストごとに読み込みたくはありません。
|
||||
|
||||
モジュール/ファイルのトップレベルで読み込むこともできますが、その場合は、たとえ簡単な自動テストを実行するだけでも「モデルを読み込む」ことになり、そのモデルの読み込みを待つ必要があるため、独立したコード部分を走らせるだけのテストでも「遅く」なってしまいます。
|
||||
|
||||
これを解決しましょう。リクエストを処理する前にモデルを読み込みますが、コードがロードされている最中ではなく、アプリケーションがリクエストの受け付けを開始する直前だけにします。
|
||||
|
||||
## Lifespan { #lifespan }
|
||||
|
||||
この「起動時」と「シャットダウン時」のロジックは、`FastAPI` アプリの `lifespan` パラメータと「コンテキストマネージャ」(これが何かはすぐに示します)を使って定義できます。
|
||||
|
||||
まずは例を見てから、詳細を説明します。
|
||||
|
||||
次のように、`yield` を使う非同期関数 `lifespan()` を作成します:
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}
|
||||
|
||||
ここでは、`yield` の前で機械学習モデルの辞書に(ダミーの)モデル関数を入れることで、高コストな「起動時」のモデル読み込みをシミュレーションしています。このコードは、アプリケーションがリクエストを「受け付け始める前」に、すなわち起動時に実行されます。
|
||||
|
||||
そして `yield` の直後でモデルをアンロードします。このコードは、アプリケーションがリクエスト処理を「終了」した後、シャットダウン直前に実行されます。たとえばメモリや GPU のようなリソースを解放できます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`shutdown` は、アプリケーションを「停止」するときに発生します。
|
||||
|
||||
新しいバージョンを開始する必要があるか、単に実行をやめたくなったのかもしれません。🤷
|
||||
|
||||
///
|
||||
|
||||
### Lifespan 関数 { #lifespan-function }
|
||||
|
||||
まず注目すべきは、`yield` を使う非同期関数を定義していることです。これは「yield を使う依存関係(Dependencies)」にとてもよく似ています。
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}
|
||||
|
||||
`yield` の前の前半は、アプリケーションが開始される「前」に実行されます。
|
||||
|
||||
`yield` の後半は、アプリケーションの処理が「終了」した「後」に実行されます。
|
||||
|
||||
### 非同期コンテキストマネージャ { #async-context-manager }
|
||||
|
||||
この関数には `@asynccontextmanager` がデコレートされています。
|
||||
|
||||
これにより、この関数は「非同期コンテキストマネージャ」になります。
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}
|
||||
|
||||
Python の「コンテキストマネージャ」は、`with` 文で使えるものです。たとえば、`open()` はコンテキストマネージャとして使えます:
|
||||
|
||||
```Python
|
||||
with open("file.txt") as file:
|
||||
file.read()
|
||||
```
|
||||
|
||||
最近の Python には「非同期コンテキストマネージャ」もあります。`async with` で使います:
|
||||
|
||||
```Python
|
||||
async with lifespan(app):
|
||||
await do_stuff()
|
||||
```
|
||||
|
||||
このようにコンテキストマネージャ(または非同期コンテキストマネージャ)を作ると、`with` ブロックに入る前に `yield` より前のコードが実行され、`with` ブロックを出た後に `yield` より後ろのコードが実行されます。
|
||||
|
||||
上のコード例では直接それを使ってはいませんが、FastAPI に渡して内部で使ってもらいます。
|
||||
|
||||
`FastAPI` アプリの `lifespan` パラメータは「非同期コンテキストマネージャ」を受け取るので、新しく作った `lifespan` 非同期コンテキストマネージャを渡せます。
|
||||
|
||||
{* ../../docs_src/events/tutorial003_py310.py hl[22] *}
|
||||
|
||||
## 代替のイベント(非推奨) { #alternative-events-deprecated }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
推奨される方法は、上で説明したとおり `FastAPI` アプリの `lifespan` パラメータを使って「起動」と「シャットダウン」を扱うことです。`lifespan` パラメータを指定すると、`startup` と `shutdown` のイベントハンドラは呼び出されなくなります。`lifespan` かイベントか、どちらか一方であり、両方同時ではありません。
|
||||
|
||||
この節は読み飛ばしてもかまいません。
|
||||
|
||||
///
|
||||
|
||||
起動時とシャットダウン時に実行されるロジックを定義する別の方法もあります。
|
||||
|
||||
アプリケーションが起動する前、またはシャットダウンするときに実行する必要があるイベントハンドラ(関数)を定義できます。
|
||||
|
||||
これらの関数は `async def` でも、通常の `def` でも構いません。
|
||||
|
||||
### `startup` イベント { #startup-event }
|
||||
|
||||
アプリケーションが開始される前に実行すべき関数を追加するには、イベント `"startup"` で宣言します:
|
||||
|
||||
{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
|
||||
|
||||
この場合、`startup` のイベントハンドラ関数は items の「データベース」(単なる `dict`)をいくつかの値で初期化します。
|
||||
|
||||
イベントハンドラ関数は複数追加できます。
|
||||
|
||||
すべての `startup` イベントハンドラが完了するまで、アプリケーションはリクエストの受け付けを開始しません。
|
||||
|
||||
### `shutdown` イベント { #shutdown-event }
|
||||
|
||||
アプリケーションがシャットダウンするときに実行すべき関数を追加するには、イベント `"shutdown"` で宣言します:
|
||||
|
||||
{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
|
||||
|
||||
ここでは、`shutdown` のイベントハンドラ関数が、テキスト行 `"Application shutdown"` をファイル `log.txt` に書き込みます。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`open()` 関数の `mode="a"` は「追加」(append)を意味します。つまり、そのファイルに既にある内容を上書きせず、行が後ろに追記されます。
|
||||
|
||||
///
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
この例では、ファイルを扱う標準の Python 関数 `open()` を使っています。
|
||||
|
||||
そのため、ディスクへの書き込みを「待つ」必要がある I/O(入力/出力)が関わります。
|
||||
|
||||
しかし `open()` 自体は `async` や `await` を使いません。
|
||||
|
||||
したがって、イベントハンドラ関数は `async def` ではなく通常の `def` で宣言しています。
|
||||
|
||||
///
|
||||
|
||||
### `startup` と `shutdown` をまとめて { #startup-and-shutdown-together }
|
||||
|
||||
起動時とシャットダウン時のロジックは関連していることが多いです。何かを開始してから終了したい、リソースを獲得してから解放したい、などです.
|
||||
|
||||
共有するロジックや変数のない別々の関数でそれを行うのは難しく、グローバル変数などに値を保存する必要が出てきます。
|
||||
|
||||
そのため、現在は上で説明したとおり `lifespan` を使うことが推奨されています。
|
||||
|
||||
## 技術詳細 { #technical-details }
|
||||
|
||||
技術が気になる方への細かな詳細です。🤓
|
||||
|
||||
内部的には、ASGI の技術仕様において、これは <a href="https://asgi.readthedocs.io/en/latest/specs/lifespan.html" class="external-link" target="_blank">Lifespan プロトコル</a> の一部であり、`startup` と `shutdown` というイベントが定義されています。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
Starlette の `lifespan` ハンドラについては、<a href="https://www.starlette.dev/lifespan/" class="external-link" target="_blank">Starlette の Lifespan ドキュメント</a>で詳しく読むことができます。
|
||||
|
||||
コードの他の領域で使える lifespan の状態をどのように扱うかも含まれています。
|
||||
|
||||
///
|
||||
|
||||
## サブアプリケーション { #sub-applications }
|
||||
|
||||
🚨 これらの lifespan イベント(startup と shutdown)はメインのアプリケーションに対してのみ実行され、[サブアプリケーション - マウント](sub-applications.md){.internal-link target=_blank} には実行されないことに注意してください。
|
||||
@@ -0,0 +1,208 @@
|
||||
# SDK の生成 { #generating-sdks }
|
||||
|
||||
**FastAPI** は **OpenAPI** 仕様に基づいているため、その API は多くのツールが理解できる標準形式で記述できます。
|
||||
|
||||
これにより、最新の**ドキュメント**、複数言語のクライアントライブラリ(<abbr title="Software Development Kits - ソフトウェア開発キット">**SDKs**</abbr>)、そしてコードと同期し続ける**テスト**や**自動化ワークフロー**を容易に生成できます。
|
||||
|
||||
本ガイドでは、FastAPI バックエンド向けの **TypeScript SDK** を生成する方法を説明します。
|
||||
|
||||
## オープソースの SDK ジェネレータ { #open-source-sdk-generators }
|
||||
|
||||
多用途な選択肢として <a href="https://openapi-generator.tech/" class="external-link" target="_blank">OpenAPI Generator</a> があります。これは**多数のプログラミング言語**をサポートし、OpenAPI 仕様から SDK を生成できます。
|
||||
|
||||
**TypeScript クライアント**向けには、<a href="https://heyapi.dev/" class="external-link" target="_blank">Hey API</a> が目的特化のソリューションで、TypeScript エコシステムに最適化された体験を提供します。
|
||||
|
||||
他の SDK ジェネレータは <a href="https://openapi.tools/#sdk" class="external-link" target="_blank">OpenAPI.Tools</a> でも見つけられます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
FastAPI は自動的に **OpenAPI 3.1** の仕様を生成します。したがって、使用するツールはこのバージョンをサポートしている必要があります。
|
||||
|
||||
///
|
||||
|
||||
## FastAPI スポンサーによる SDK ジェネレータ { #sdk-generators-from-fastapi-sponsors }
|
||||
|
||||
このセクションでは、FastAPI をスポンサーしている企業による、**ベンチャー支援**および**企業支援**のソリューションを紹介します。これらの製品は、高品質な生成 SDK に加えて、**追加機能**や**統合**を提供します。
|
||||
|
||||
✨ [**FastAPI をスポンサーする**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨ ことで、これらの企業はフレームワークとその**エコシステム**の健全性と**持続可能性**を支援しています。
|
||||
|
||||
この支援は、FastAPI の**コミュニティ**(皆さん)への強いコミットメントの表明でもあり、**優れたサービス**の提供だけでなく、堅牢で発展するフレームワーク FastAPI を支える姿勢を示しています。🙇
|
||||
|
||||
例えば、次のようなものがあります:
|
||||
|
||||
* <a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
|
||||
* <a href="https://www.stainless.com/?utm_source=fastapi&utm_medium=referral" class="external-link" target="_blank">Stainless</a>
|
||||
* <a href="https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi" class="external-link" target="_blank">liblab</a>
|
||||
|
||||
これらのソリューションの中にはオープンソースや無料枠を提供するものもあり、金銭的コミットメントなしで試すことができます。他の商用 SDK ジェネレータも存在し、オンラインで見つけられます。🤓
|
||||
|
||||
## TypeScript SDK を作成する { #create-a-typescript-sdk }
|
||||
|
||||
まずは簡単な FastAPI アプリから始めます:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
|
||||
|
||||
ここで、*path operation* はリクエストとレスポンスのペイロードに使用するモデルを定義しており、`Item` と `ResponseMessage` を使っています。
|
||||
|
||||
### API ドキュメント { #api-docs }
|
||||
|
||||
`/docs` に移動すると、リクエストで送信・レスポンスで受信するデータの**スキーマ**が表示されます:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image01.png">
|
||||
|
||||
これらのスキーマは、アプリ内でモデルとして宣言されているため表示されます。
|
||||
|
||||
その情報はアプリの **OpenAPI スキーマ**に含まれ、API ドキュメントに表示されます。
|
||||
|
||||
OpenAPI に含まれるこれらのモデル情報を使って、**クライアントコードを生成**できます。
|
||||
|
||||
### Hey API { #hey-api }
|
||||
|
||||
モデルを備えた FastAPI アプリがあれば、Hey API で TypeScript クライアントを生成できます。最も手早い方法は npx を使うことです。
|
||||
|
||||
```sh
|
||||
npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
|
||||
```
|
||||
|
||||
これで TypeScript SDK が `./src/client` に生成されます。
|
||||
|
||||
<a href="https://heyapi.dev/openapi-ts/get-started" class="external-link" target="_blank">`@hey-api/openapi-ts` のインストール方法</a>や、<a href="https://heyapi.dev/openapi-ts/output" class="external-link" target="_blank">生成物の詳細</a>は公式サイトを参照してください。
|
||||
|
||||
### SDK の利用 { #using-the-sdk }
|
||||
|
||||
これでクライアントコードを import して利用できます。例えば次のようになり、メソッドに対して補完が効きます:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image02.png">
|
||||
|
||||
送信するペイロードにも補完が適用されます:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image03.png">
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
FastAPI アプリの `Item` モデルで定義した `name` と `price` に補完が効いている点に注目してください。
|
||||
|
||||
///
|
||||
|
||||
送信データに対するインラインエラーも表示されます:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image04.png">
|
||||
|
||||
レスポンスオブジェクトにも補完があります:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image05.png">
|
||||
|
||||
## タグ付きの FastAPI アプリ { #fastapi-app-with-tags }
|
||||
|
||||
実運用ではアプリは大きくなり、*path operation* のグループ分けにタグを使うことが多いでしょう。
|
||||
|
||||
例えば **items** 用と **users** 用のセクションがあり、タグで分けられます:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
|
||||
|
||||
### タグ付き TypeScript クライアントの生成 { #generate-a-typescript-client-with-tags }
|
||||
|
||||
タグを用いた FastAPI アプリからクライアントを生成すると、通常クライアント側のコードもタグごとに分割されます。
|
||||
|
||||
これにより、クライアントコードも正しく整理・グルーピングされます:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image06.png">
|
||||
|
||||
この例では次のようになります:
|
||||
|
||||
* `ItemsService`
|
||||
* `UsersService`
|
||||
|
||||
### クライアントのメソッド名 { #client-method-names }
|
||||
|
||||
現状では、生成されるメソッド名(`createItemItemsPost` など)はあまりきれいではありません:
|
||||
|
||||
```TypeScript
|
||||
ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
|
||||
```
|
||||
|
||||
これは、クライアントジェネレータが各 *path operation* の OpenAPI 内部の **operation ID** を用いるためです。
|
||||
|
||||
OpenAPI では operation ID は全ての *path operation* を通して一意である必要があります。そのため FastAPI は**関数名**、**パス**、**HTTP メソッド/オペレーション**を組み合わせて operation ID を生成し、一意性を保証します。
|
||||
|
||||
次にこれを改善する方法を示します。🤓
|
||||
|
||||
## カスタム operation ID とより良いメソッド名 { #custom-operation-ids-and-better-method-names }
|
||||
|
||||
operation ID の**生成方法**を**変更**して簡潔にし、クライアント側の**メソッド名をシンプル**にできます。
|
||||
|
||||
この場合でも各 operation ID が**一意**であることは別の方法で保証する必要があります。
|
||||
|
||||
例えば、各 *path operation* にタグを付け、**タグ**と *path operation* の**名前**(関数名)から operation ID を生成できます。
|
||||
|
||||
### 一意 ID 生成関数のカスタマイズ { #custom-generate-unique-id-function }
|
||||
|
||||
FastAPI は各 *path operation* に**一意 ID**を用いており、これは **operation ID** のほか、必要に応じてリクエストやレスポンスのカスタムモデル名にも使われます。
|
||||
|
||||
この関数はカスタマイズ可能です。`APIRoute` を受け取り、文字列を返します。
|
||||
|
||||
例えばここでは、最初のタグ(通常は 1 つ)と *path operation* 名(関数名)を使います。
|
||||
|
||||
そのカスタム関数を **FastAPI** の `generate_unique_id_function` パラメータに渡します:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
|
||||
|
||||
### カスタム operation ID で TypeScript クライアントを生成 { #generate-a-typescript-client-with-custom-operation-ids }
|
||||
|
||||
この状態でクライアントを再生成すると、メソッド名が改善されています:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image07.png">
|
||||
|
||||
ご覧のとおり、メソッド名はタグ名と関数名のみになり、URL パスや HTTP オペレーションの情報は含まれません。
|
||||
|
||||
### クライアント生成向けの OpenAPI 仕様の前処理 { #preprocess-the-openapi-specification-for-the-client-generator }
|
||||
|
||||
それでも生成コードには**重複情報**が残っています。
|
||||
|
||||
`ItemsService`(タグ由来)から items 関連であることはすでに分かるのに、メソッド名にもタグ名が前置されています。😕
|
||||
|
||||
OpenAPI 全体としては operation ID の**一意性**のために、このプレフィックスを維持したい場合があるでしょう。
|
||||
|
||||
しかし生成クライアント用には、クライアントを生成する直前に OpenAPI の operation ID を**加工**して、メソッド名をより**見やすく**、**クリーン**にできます。
|
||||
|
||||
OpenAPI の JSON を `openapi.json` として保存し、次のようなスクリプトで**そのタグのプレフィックスを除去**できます:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial004_py310.py *}
|
||||
|
||||
//// tab | Node.js
|
||||
|
||||
```Javascript
|
||||
{!> ../../docs_src/generate_clients/tutorial004.js!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
これにより operation ID は `items-get_items` のような形から単なる `get_items` に置き換わり、クライアントジェネレータはより簡潔なメソッド名を生成できます。
|
||||
|
||||
### 前処理済み OpenAPI から TypeScript クライアントを生成 { #generate-a-typescript-client-with-the-preprocessed-openapi }
|
||||
|
||||
生成元が `openapi.json` になったので、入力の場所を更新します:
|
||||
|
||||
```sh
|
||||
npx @hey-api/openapi-ts -i ./openapi.json -o src/client
|
||||
```
|
||||
|
||||
新しいクライアントを生成すると、**クリーンなメソッド名**になり、**補完**や**インラインエラー**などもそのまま利用できます:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image08.png">
|
||||
|
||||
## 利点 { #benefits }
|
||||
|
||||
自動生成されたクライアントを使うと、次のような対象で**補完**が得られます:
|
||||
|
||||
* メソッド
|
||||
* 本体のリクエストペイロード、クエリパラメータ等
|
||||
* レスポンスのペイロード
|
||||
|
||||
また、あらゆる箇所で**インラインエラー**も得られます。
|
||||
|
||||
バックエンドコードを更新してフロントエンドを**再生成**すれば、新しい *path operation* はメソッドとして追加され、古いものは削除され、その他の変更も生成コードに反映されます。🤓
|
||||
|
||||
つまり、変更があれば自動的にクライアントコードに**反映**されます。クライアントを**ビルド**すれば、使用データに**不整合**があればエラーになります。
|
||||
|
||||
その結果、多くのエラーを開発の初期段階で**早期発見**でき、本番で最終ユーザーに不具合が現れてから原因をデバッグする必要がなくなります。✨
|
||||
@@ -1,27 +1,21 @@
|
||||
# 高度なユーザーガイド
|
||||
# 高度なユーザーガイド { #advanced-user-guide }
|
||||
|
||||
## さらなる機能
|
||||
## さらなる機能 { #additional-features }
|
||||
|
||||
[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}により、**FastAPI**の主要な機能は十分に理解できたことでしょう。
|
||||
メインの[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}だけで、**FastAPI**の主要な機能を一通り把握するには十分なはずです。
|
||||
|
||||
以降のセクションでは、チュートリアルでは説明しきれなかったオプションや設定、および機能について説明します。
|
||||
以降のセクションでは、その他のオプション、設定、追加機能を見ていきます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
以降のセクションは、 **必ずしも"応用編"ではありません**。
|
||||
以降のセクションは、**必ずしも「高度」ではありません**。
|
||||
|
||||
ユースケースによっては、その中から解決策を見つけられるかもしれません。
|
||||
また、あなたのユースケースに対する解決策が、その中のどれかにある可能性もあります。
|
||||
|
||||
///
|
||||
|
||||
## 先にチュートリアルを読む
|
||||
## 先にチュートリアルを読む { #read-the-tutorial-first }
|
||||
|
||||
[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}の知識があれば、**FastAPI**の主要な機能を利用することができます。
|
||||
メインの[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}で得た知識があれば、**FastAPI**の機能の多くは引き続き利用できます。
|
||||
|
||||
以降のセクションは、すでにチュートリアルを読んで、その主要なアイデアを理解できていることを前提としています。
|
||||
|
||||
## テスト駆動開発のコース
|
||||
|
||||
このセクションの内容を補完するために脱初心者用コースを受けたい場合は、**TestDriven.io**による、<a href="https://testdriven.io/courses/tdd-fastapi/" class="external-link" target="_blank">Test-Driven Development with FastAPI and Docker</a>を確認するのがよいかもしれません。
|
||||
|
||||
現在、このコースで得られた利益の10%が**FastAPI**の開発のために寄付されています。🎉 😄
|
||||
また、以降のセクションでは、すでにそれを読んでいて、主要な考え方を理解していることを前提としています。
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
# 高度なミドルウェア { #advanced-middleware }
|
||||
|
||||
メインのチュートリアルでは、アプリケーションに[カスタムミドルウェア](../tutorial/middleware.md){.internal-link target=_blank}を追加する方法を学びました。
|
||||
|
||||
そして、[`CORSMiddleware` を使った CORS の扱い方](../tutorial/cors.md){.internal-link target=_blank}も学びました。
|
||||
|
||||
このセクションでは、その他のミドルウェアの使い方を見ていきます。
|
||||
|
||||
## ASGI ミドルウェアの追加 { #adding-asgi-middlewares }
|
||||
|
||||
**FastAPI** は Starlette を基盤としており、<abbr title="Asynchronous Server Gateway Interface - 非同期サーバーゲートウェイインターフェース">ASGI</abbr> 仕様を実装しているため、任意の ASGI ミドルウェアを利用できます。
|
||||
|
||||
ミドルウェアは ASGI 仕様に従っていれば、FastAPI や Starlette 専用に作られていなくても動作します。
|
||||
|
||||
一般に、ASGI ミドルウェアは最初の引数として ASGI アプリを受け取るクラスです。
|
||||
|
||||
そのため、サードパーティの ASGI ミドルウェアのドキュメントでは、おそらく次のように書かれているでしょう:
|
||||
|
||||
```Python
|
||||
from unicorn import UnicornMiddleware
|
||||
|
||||
app = SomeASGIApp()
|
||||
|
||||
new_app = UnicornMiddleware(app, some_config="rainbow")
|
||||
```
|
||||
|
||||
しかし FastAPI(正確には Starlette)は、内部ミドルウェアがサーバーエラーを処理し、カスタム例外ハンドラが正しく動作することを保証する、より簡単な方法を提供しています。
|
||||
|
||||
そのためには(CORS の例と同様に)`app.add_middleware()` を使います。
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
from unicorn import UnicornMiddleware
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
app.add_middleware(UnicornMiddleware, some_config="rainbow")
|
||||
```
|
||||
|
||||
`app.add_middleware()` は、最初の引数にミドルウェアのクラスを取り、それ以外の追加引数はミドルウェアに渡されます。
|
||||
|
||||
## 組み込みミドルウェア { #integrated-middlewares }
|
||||
|
||||
**FastAPI** は一般的なユースケースに対応するいくつかのミドルウェアを含んでいます。以下でその使い方を見ていきます。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
以下の例では、`from starlette.middleware.something import SomethingMiddleware` を使うこともできます。
|
||||
|
||||
**FastAPI** は開発者であるあなたの便宜のために `fastapi.middleware` にいくつかのミドルウェアを提供しています。しかし、利用可能なミドルウェアの多くは Starlette から直接提供されています。
|
||||
|
||||
///
|
||||
|
||||
## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }
|
||||
|
||||
すべての受信リクエストが `https` または `wss` でなければならないように強制します。
|
||||
|
||||
`http` または `ws` への受信リクエストは、安全なスキームにリダイレクトされます。
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}
|
||||
|
||||
## `TrustedHostMiddleware` { #trustedhostmiddleware }
|
||||
|
||||
HTTP Host Header 攻撃を防ぐため、すべての受信リクエストに正しく設定された `Host` ヘッダーを強制します。
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}
|
||||
|
||||
サポートされる引数は次のとおりです:
|
||||
|
||||
- `allowed_hosts` - 許可するホスト名のドメイン名リスト。`*.example.com` のようなワイルドカードドメインでサブドメインのマッチングもサポートします。任意のホスト名を許可するには、`allowed_hosts=["*"]` を使うか、このミドルウェアを省略します。
|
||||
- `www_redirect` - True に設定すると、許可されたホストの非 www 版へのリクエストを www 版へリダイレクトします。デフォルトは `True` です。
|
||||
|
||||
受信リクエストが正しく検証されない場合、`400` のレスポンスが返されます。
|
||||
|
||||
## `GZipMiddleware` { #gzipmiddleware }
|
||||
|
||||
`Accept-Encoding` ヘッダーに "gzip" を含むリクエストに対して GZip レスポンスを処理します。
|
||||
|
||||
このミドルウェアは、通常のレスポンスとストリーミングレスポンスの両方を処理します。
|
||||
|
||||
{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}
|
||||
|
||||
サポートされる引数は次のとおりです:
|
||||
|
||||
- `minimum_size` - このバイト数の最小サイズ未満のレスポンスは GZip 圧縮しません。デフォルトは `500` です。
|
||||
- `compresslevel` - GZip 圧縮時に使用します。1 から 9 までの整数です。デフォルトは `9`。値が小さいほど圧縮は速くなりますがファイルサイズは大きくなり、値が大きいほど圧縮は遅くなりますがファイルサイズは小さくなります。
|
||||
|
||||
## その他のミドルウェア { #other-middlewares }
|
||||
|
||||
他にも多くの ASGI ミドルウェアがあります。
|
||||
|
||||
例えば:
|
||||
|
||||
- <a href="https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py" class="external-link" target="_blank">Uvicorn の `ProxyHeadersMiddleware`</a>
|
||||
- <a href="https://github.com/florimondmanca/msgpack-asgi" class="external-link" target="_blank">MessagePack</a>
|
||||
|
||||
他に利用可能なミドルウェアについては、<a href="https://www.starlette.dev/middleware/" class="external-link" target="_blank">Starlette のミドルウェアドキュメント</a>や <a href="https://github.com/florimondmanca/awesome-asgi" class="external-link" target="_blank">ASGI Awesome List</a> を参照してください。
|
||||
@@ -0,0 +1,186 @@
|
||||
# OpenAPI コールバック { #openapi-callbacks }
|
||||
|
||||
あなたは、*path operation* を持つ API を作成し、他者(多くの場合、あなたの API を「利用する」同一の開発者)が作成した *外部 API* へリクエストをトリガーできるようにできます。
|
||||
|
||||
あなたの API アプリが *外部 API* を呼び出すときに起きる処理は「コールバック」と呼ばれます。なぜなら、外部開発者が作成したソフトウェアがあなたの API にリクエストを送り、その後であなたの API が「呼び返し」、*外部 API*(おそらく同じ開発者が作成)へリクエストを送るためです。
|
||||
|
||||
この場合、その *外部 API* がどのようである「べき」かをドキュメント化したくなるでしょう。どんな *path operation* を持ち、どんなボディを受け取り、どんなレスポンスを返すか、などです。
|
||||
|
||||
## コールバックのあるアプリ { #an-app-with-callbacks }
|
||||
|
||||
例で見ていきます。
|
||||
|
||||
あなたが請求書を作成できるアプリを開発していると想像してください。
|
||||
|
||||
これらの請求書は `id`、`title`(任意)、`customer`、`total` を持ちます。
|
||||
|
||||
あなたの API の利用者(外部開発者)は、POST リクエストであなたの API に請求書を作成します。
|
||||
|
||||
その後、あなたの API は(仮にこうしましょう):
|
||||
|
||||
* 外部開発者の顧客に請求書を送ります。
|
||||
* 代金を回収します。
|
||||
* API 利用者(外部開発者)に通知を送り返します。
|
||||
* これは(あなたの API から)外部開発者が提供する *外部 API* に POST リクエストを送ることで行われます(これが「コールバック」です)。
|
||||
|
||||
## 通常の FastAPI アプリ { #the-normal-fastapi-app }
|
||||
|
||||
まず、コールバックを追加する前の通常の API アプリがどうなるか見てみましょう。
|
||||
|
||||
`Invoice` ボディを受け取り、クエリパラメータ `callback_url` にコールバック用の URL を含める *path operation* を持ちます。
|
||||
|
||||
この部分はとても普通で、ほとんどのコードはすでに見覚えがあるはずです:
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`callback_url` クエリパラメータは、Pydantic の <a href="https://docs.pydantic.dev/latest/api/networks/" class="external-link" target="_blank">Url</a> 型を使用します。
|
||||
|
||||
///
|
||||
|
||||
唯一の新しい点は、*path operation デコレータ*の引数として `callbacks=invoices_callback_router.routes` を渡すことです。これが何かは次で見ます。
|
||||
|
||||
## コールバックのドキュメント化 { #documenting-the-callback }
|
||||
|
||||
実際のコールバックのコードは、あなた自身の API アプリに大きく依存します。
|
||||
|
||||
そしてアプリごとに大きく異なるでしょう。
|
||||
|
||||
それは次のように 1、2 行のコードかもしれません:
|
||||
|
||||
```Python
|
||||
callback_url = "https://example.com/api/v1/invoices/events/"
|
||||
httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
|
||||
```
|
||||
|
||||
しかし、おそらくコールバックで最も重要な点は、あなたの API 利用者(外部開発者)が、*あなたの API* がコールバックのリクエストボディなどで送るデータに従って、*外部 API* を正しく実装することを確実にすることです。
|
||||
|
||||
そこで次に行うのは、*あなたの API* からのコールバックを受け取るために、その *外部 API* がどうあるべきかをドキュメント化するコードを追加することです。
|
||||
|
||||
そのドキュメントはあなたの API の `/docs` の Swagger UI に表示され、外部開発者に *外部 API* の作り方を知らせます。
|
||||
|
||||
この例ではコールバック自体は実装しません(それは 1 行のコードでもよいでしょう)。ドキュメント部分のみです。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
実際のコールバックは単なる HTTP リクエストです。
|
||||
|
||||
自分でコールバックを実装する場合は、<a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> や <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requests</a> のようなものを使えます。
|
||||
|
||||
///
|
||||
|
||||
## コールバックのドキュメント用コードを書く { #write-the-callback-documentation-code }
|
||||
|
||||
このコードはあなたのアプリで実行されません。*外部 API* がどうあるべきかをドキュメント化するためだけに必要です。
|
||||
|
||||
しかし、あなたはすでに **FastAPI** で API の自動ドキュメントを簡単に作る方法を知っています。
|
||||
|
||||
その知識を使って、*外部 API* がどうあるべきかをドキュメント化します……つまり、外部 API が実装すべき *path operation(s)*(あなたの API が呼び出すもの)を作成します。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
コールバックをドキュメント化するコードを書くときは、あなたがその「外部開発者」だと想像するのが役に立つかもしれません。いま実装しているのは「あなたの API」ではなく、*外部 API* です。
|
||||
|
||||
この(外部開発者の)視点を一時的に採用すると、その *外部 API* に対してパラメータ、ボディ用の Pydantic モデル、レスポンスなどをどこに置くのが自然かがより明確に感じられるでしょう。
|
||||
|
||||
///
|
||||
|
||||
### コールバック用 APIRouter を作成 { #create-a-callback-apirouter }
|
||||
|
||||
まず、1 つ以上のコールバックを含む新しい `APIRouter` を作成します。
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}
|
||||
|
||||
### コールバックの path operation を作成 { #create-the-callback-path-operation }
|
||||
|
||||
上で作成したのと同じ `APIRouter` を使って、コールバックの *path operation* を作成します。
|
||||
|
||||
見た目は通常の FastAPI の *path operation* と同じです:
|
||||
|
||||
* 受け取るボディの宣言(例: `body: InvoiceEvent`)が必要でしょう。
|
||||
* 返すレスポンスの宣言(例: `response_model=InvoiceEventReceived`)も持てます。
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
|
||||
|
||||
通常の *path operation* と異なる主な点が 2 つあります:
|
||||
|
||||
* 実際のコードは不要です。あなたのアプリはこのコードを決して呼びません。これは *外部 API* をドキュメント化するためだけに使われます。したがって、関数本体は `pass` で構いません。
|
||||
* *パス* には、*あなたの API* に送られた元のリクエストのパラメータや一部を変数として使える <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 の式</a>(後述)を含められます。
|
||||
|
||||
### コールバックのパス式 { #the-callback-path-expression }
|
||||
|
||||
コールバックの *パス* には、*あなたの API* に送られた元のリクエストの一部を含められる <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 の式</a>を使用できます。
|
||||
|
||||
この例では、`str` は次のとおりです:
|
||||
|
||||
```Python
|
||||
"{$callback_url}/invoices/{$request.body.id}"
|
||||
```
|
||||
|
||||
つまり、あなたの API 利用者(外部開発者)が *あなたの API* に次のようにリクエストを送った場合:
|
||||
|
||||
```
|
||||
https://yourapi.com/invoices/?callback_url=https://www.external.org/events
|
||||
```
|
||||
|
||||
JSON ボディは:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"id": "2expen51ve",
|
||||
"customer": "Mr. Richie Rich",
|
||||
"total": "9999"
|
||||
}
|
||||
```
|
||||
|
||||
その後 *あなたの API* は請求書を処理し、のちほど `callback_url`(*外部 API*)へコールバックのリクエストを送ります:
|
||||
|
||||
```
|
||||
https://www.external.org/events/invoices/2expen51ve
|
||||
```
|
||||
|
||||
JSON ボディは次のような内容です:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"description": "Payment celebration",
|
||||
"paid": true
|
||||
}
|
||||
```
|
||||
|
||||
そして *外部 API* からは次のような JSON ボディのレスポンスを期待します:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"ok": true
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
使用されるコールバック URL には、クエリパラメータ `callback_url`(`https://www.external.org/events`)で受け取った URL と、JSON ボディ内の請求書 `id`(`2expen51ve`)が含まれている点に注目してください。
|
||||
|
||||
///
|
||||
|
||||
### コールバック用ルーターを追加 { #add-the-callback-router }
|
||||
|
||||
これで、上で作成したコールバック用ルーター内に、必要なコールバックの *path operation(s)*(*外部開発者* が *外部 API* に実装すべきもの)が用意できました。
|
||||
|
||||
次に、*あなたの API の path operation デコレータ*の `callbacks` パラメータに、そのコールバック用ルーターの属性 `.routes`(実体はルート/*path operations* の `list`)を渡します:
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`callback=` に渡すのはルーター本体(`invoices_callback_router`)ではなく、属性 `.routes`(`invoices_callback_router.routes`)である点に注意してください。
|
||||
|
||||
///
|
||||
|
||||
### ドキュメントを確認 { #check-the-docs }
|
||||
|
||||
アプリを起動して <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> にアクセスします。
|
||||
|
||||
あなたの *path operation* に「Callbacks」セクションが含まれ、*外部 API* がどうあるべきかが表示されているのが確認できます:
|
||||
|
||||
<img src="/img/tutorial/openapi-callbacks/image01.png">
|
||||
@@ -0,0 +1,55 @@
|
||||
# OpenAPI の Webhook { #openapi-webhooks }
|
||||
|
||||
アプリがある種の**イベント**を**通知**するために、データ付きで相手のアプリ(リクエスト送信)を呼び出す可能性があることを、API の**ユーザー**に伝えたい場合があります。
|
||||
|
||||
これは、通常のようにユーザーがあなたの API にリクエストを送るのではなく、**あなたの API(あなたのアプリ)**が**相手のシステム**(相手の API、アプリ)にリクエストを送る、ということです。
|
||||
|
||||
これは一般に**Webhook**と呼ばれます。
|
||||
|
||||
## Webhook の手順 { #webhooks-steps }
|
||||
|
||||
通常の流れとして、まずあなたのコード内で、送信するメッセージ、すなわちリクエストの**本文(ボディ)**を**定義**します。
|
||||
|
||||
加えて、アプリがそれらのリクエスト(イベント)を送信する**タイミング**も何らかの形で定義します。
|
||||
|
||||
そして**ユーザー**は、アプリがそのリクエストを送るべき**URL**を(たとえばどこかの Web ダッシュボードで)定義します。
|
||||
|
||||
Webhook の URL を登録する方法や実際にリクエストを送るコードなど、これらの**ロジック**はすべてあなた次第です。**あなた自身のコード**で好きなように実装します。
|
||||
|
||||
## FastAPI と OpenAPI による Webhook のドキュメント化 { #documenting-webhooks-with-fastapi-and-openapi }
|
||||
|
||||
**FastAPI** と OpenAPI を使うと、Webhook の名前、アプリが送信できる HTTP の操作(例: `POST`, `PUT` など)、アプリが送るリクエストの**ボディ**を定義できます。
|
||||
|
||||
これにより、ユーザーがあなたの **Webhook** リクエストを受け取るための**API を実装**するのが大幅に簡単になります。場合によっては、ユーザーが自分たちの API コードを自動生成できるかもしれません。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
Webhook は OpenAPI 3.1.0 以上で利用可能で、FastAPI `0.99.0` 以上が対応しています。
|
||||
|
||||
///
|
||||
|
||||
## Webhook を持つアプリ { #an-app-with-webhooks }
|
||||
|
||||
**FastAPI** アプリケーションを作成すると、`webhooks` という属性があり、ここで *path operations* と同様に(例: `@app.webhooks.post()`)*webhook* を定義できます。
|
||||
|
||||
{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
|
||||
|
||||
定義した webhook は **OpenAPI** スキーマおよび自動生成される **ドキュメント UI** に反映されます。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`app.webhooks` オブジェクトは実際には単なる `APIRouter` で、複数ファイルでアプリを構成する際に使うものと同じ型です。
|
||||
|
||||
///
|
||||
|
||||
Webhook では(`/items/` のような)*パス*を宣言しているわけではない点に注意してください。ここで渡す文字列は webhook の**識別子**(イベント名)です。たとえば `@app.webhooks.post("new-subscription")` での webhook 名は `new-subscription` です。
|
||||
|
||||
これは、**ユーザー**が実際に Webhook リクエストを受け取りたい**URL パス**を、別の方法(例: Web ダッシュボード)で定義することを想定しているためです。
|
||||
|
||||
### ドキュメントの確認 { #check-the-docs }
|
||||
|
||||
アプリを起動し、<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> にアクセスします。
|
||||
|
||||
ドキュメントには通常の *path operations* に加えて、**webhooks** も表示されます:
|
||||
|
||||
<img src="/img/tutorial/openapi-webhooks/image01.png">
|
||||
@@ -1,30 +1,30 @@
|
||||
# Path Operationの高度な設定
|
||||
# Path Operationの高度な設定 { #path-operation-advanced-configuration }
|
||||
|
||||
## OpenAPI operationId
|
||||
## OpenAPI operationId { #openapi-operationid }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
あなたがOpenAPIの「エキスパート」でなければ、これは必要ないかもしれません。
|
||||
OpenAPIの「エキスパート」でなければ、これはおそらく必要ありません。
|
||||
|
||||
///
|
||||
|
||||
*path operation* で `operation_id` パラメータを利用することで、OpenAPIの `operationId` を設定できます。
|
||||
|
||||
`operation_id` は各オペレーションで一意にする必要があります。
|
||||
各オペレーションで一意になるようにする必要があります。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}
|
||||
|
||||
### *path operation関数* の名前をoperationIdとして使用する
|
||||
### *path operation関数* の名前をoperationIdとして使用する { #using-the-path-operation-function-name-as-the-operationid }
|
||||
|
||||
APIの関数名を `operationId` として利用したい場合、すべてのAPIの関数をイテレーションし、各 *path operation* の `operationId` を `APIRoute.name` で上書きすれば可能です。
|
||||
APIの関数名を `operationId` として利用したい場合、すべてのAPI関数をイテレーションし、各 *path operation* の `operation_id` を `APIRoute.name` で上書きすれば可能です。
|
||||
|
||||
そうする場合は、すべての *path operation* を追加した後に行う必要があります。
|
||||
すべての *path operation* を追加した後に行うべきです。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002.py hl[2,12:21,24] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`app.openapi()` を手動でコールする場合、その前に`operationId`を更新する必要があります。
|
||||
`app.openapi()` を手動で呼び出す場合、その前に `operationId` を更新するべきです。
|
||||
|
||||
///
|
||||
|
||||
@@ -32,22 +32,141 @@ APIの関数名を `operationId` として利用したい場合、すべてのAP
|
||||
|
||||
この方法をとる場合、各 *path operation関数* が一意な名前である必要があります。
|
||||
|
||||
それらが異なるモジュール (Pythonファイル) にあるとしてもです。
|
||||
異なるモジュール(Pythonファイル)にある場合でも同様です。
|
||||
|
||||
///
|
||||
|
||||
## OpenAPIから除外する
|
||||
## OpenAPIから除外する { #exclude-from-openapi }
|
||||
|
||||
生成されるOpenAPIスキーマ (つまり、自動ドキュメント生成の仕組み) から *path operation* を除外するには、 `include_in_schema` パラメータを `False` にします。
|
||||
生成されるOpenAPIスキーマ(つまり、自動ドキュメント生成の仕組み)から *path operation* を除外するには、`include_in_schema` パラメータを使用して `False` に設定します。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}
|
||||
|
||||
## docstringによる説明の高度な設定
|
||||
## docstringによる説明の高度な設定 { #advanced-description-from-docstring }
|
||||
|
||||
*path operation関数* のdocstringからOpenAPIに使用する行を制限することができます。
|
||||
*path operation関数* のdocstringからOpenAPIに使用する行を制限できます。
|
||||
|
||||
`\f` (「書式送り (Form Feed)」のエスケープ文字) を付与することで、**FastAPI** はOpenAPIに使用される出力をその箇所までに制限します。
|
||||
`\f`(エスケープされた「書式送り(form feed)」文字)を追加すると、**FastAPI** はその地点でOpenAPIに使用される出力を切り詰めます。
|
||||
|
||||
ドキュメントには表示されませんが、他のツール (例えばSphinx) では残りの部分を利用できるでしょう。
|
||||
ドキュメントには表示されませんが、他のツール(Sphinxなど)は残りの部分を利用できます。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004.py hl[19:29] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
|
||||
## 追加レスポンス { #additional-responses }
|
||||
|
||||
*path operation* に対して `response_model` と `status_code` を宣言する方法はすでに見たことがあるでしょう。
|
||||
|
||||
それにより、*path operation* のメインのレスポンスに関するメタデータが定義されます。
|
||||
|
||||
追加のレスポンスについても、モデルやステータスコードなどとともに宣言できます。
|
||||
|
||||
これについてはドキュメントに章全体があります。 [OpenAPIの追加レスポンス](additional-responses.md){.internal-link target=_blank} で読めます。
|
||||
|
||||
## OpenAPI Extra { #openapi-extra }
|
||||
|
||||
アプリケーションで *path operation* を宣言すると、**FastAPI** はOpenAPIスキーマに含めるために、その *path operation* に関連するメタデータを自動的に生成します。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
OpenAPI仕様では <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Operation Object</a> と呼ばれています。
|
||||
|
||||
///
|
||||
|
||||
これには *path operation* に関するすべての情報が含まれ、自動ドキュメントを生成するために使われます。
|
||||
|
||||
`tags`、`parameters`、`requestBody`、`responses` などが含まれます。
|
||||
|
||||
この *path operation* 固有のOpenAPIスキーマは通常 **FastAPI** により自動生成されますが、拡張することもできます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これは低レベルな拡張ポイントです。
|
||||
|
||||
追加レスポンスを宣言するだけなら、より便利な方法として [OpenAPIの追加レスポンス](additional-responses.md){.internal-link target=_blank} を使うことができます。
|
||||
|
||||
///
|
||||
|
||||
`openapi_extra` パラメータを使って、*path operation* のOpenAPIスキーマを拡張できます。
|
||||
|
||||
### OpenAPI Extensions { #openapi-extensions }
|
||||
|
||||
この `openapi_extra` は、例えば [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) を宣言するのに役立ちます。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}
|
||||
|
||||
自動APIドキュメントを開くと、その拡張は特定の *path operation* の下部に表示されます。
|
||||
|
||||
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
|
||||
|
||||
そして(APIの `/openapi.json` にある)生成されたOpenAPIを見ると、その拡張も特定の *path operation* の一部として確認できます。
|
||||
|
||||
```JSON hl_lines="22"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"paths": {
|
||||
"/items/": {
|
||||
"get": {
|
||||
"summary": "Read Items",
|
||||
"operationId": "read_items_items__get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-aperture-labs-portal": "blue"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### カスタムOpenAPI *path operation* スキーマ { #custom-openapi-path-operation-schema }
|
||||
|
||||
`openapi_extra` 内の辞書は、*path operation* 用に自動生成されたOpenAPIスキーマと深くマージされます。
|
||||
|
||||
そのため、自動生成されたスキーマに追加データを加えることができます。
|
||||
|
||||
例えば、Pydanticを使ったFastAPIの自動機能を使わずに独自のコードでリクエストを読み取り・検証することを選べますが、それでもOpenAPIスキーマでリクエストを定義したい場合があります。
|
||||
|
||||
それは `openapi_extra` で行えます。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}
|
||||
|
||||
この例では、Pydanticモデルを一切宣言していません。実際、リクエストボディはJSONとして <dfn title="bytes などのプレーンな形式から Python オブジェクトに変換される">パース</dfn> されず、直接 `bytes` として読み取られます。そして `magic_data_reader()` 関数が、何らかの方法でそれをパースする責務を担います。
|
||||
|
||||
それでも、リクエストボディに期待されるスキーマを宣言できます。
|
||||
|
||||
### カスタムOpenAPI content type { #custom-openapi-content-type }
|
||||
|
||||
同じトリックを使って、PydanticモデルでJSON Schemaを定義し、それを *path operation* 用のカスタムOpenAPIスキーマセクションに含めることができます。
|
||||
|
||||
また、リクエスト内のデータ型がJSONでない場合でもこれを行えます。
|
||||
|
||||
例えばこのアプリケーションでは、PydanticモデルからJSON Schemaを抽出するFastAPIの統合機能や、JSONの自動バリデーションを使っていません。実際、リクエストのcontent typeをJSONではなくYAMLとして宣言しています。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}
|
||||
|
||||
それでも、デフォルトの統合機能を使っていないにもかかわらず、YAMLで受け取りたいデータのために、Pydanticモデルを使って手動でJSON Schemaを生成しています。
|
||||
|
||||
そしてリクエストを直接使い、ボディを `bytes` として抽出します。これは、FastAPIがリクエストペイロードをJSONとしてパースしようとすらしないことを意味します。
|
||||
|
||||
その後、コード内でそのYAMLコンテンツを直接パースし、さらに同じPydanticモデルを使ってYAMLコンテンツを検証しています。
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ここでは同じPydanticモデルを再利用しています。
|
||||
|
||||
ただし同様に、別の方法で検証することもできます。
|
||||
|
||||
///
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# レスポンス - ステータスコードの変更 { #response-change-status-code }
|
||||
|
||||
すでに、デフォルトの[レスポンスのステータスコード](../tutorial/response-status-code.md){.internal-link target=_blank}を設定できることをご存知かもしれません。
|
||||
|
||||
しかし場合によっては、デフォルトとは異なるステータスコードを返す必要があります。
|
||||
|
||||
## ユースケース { #use-case }
|
||||
|
||||
たとえば、デフォルトでは HTTP ステータスコード "OK" `200` を返したいとします。
|
||||
|
||||
しかし、データが存在しなければそれを作成し、HTTP ステータスコード "CREATED" `201` を返したい。
|
||||
|
||||
それでも、返すデータは `response_model` でフィルタ・変換できるようにしておきたい。
|
||||
|
||||
そのような場合は `Response` パラメータを使えます。
|
||||
|
||||
## `Response` パラメータを使う { #use-a-response-parameter }
|
||||
|
||||
*path operation* 関数で `Response` 型のパラメータを宣言できます(Cookie やヘッダーと同様です)。
|
||||
|
||||
そして、その*一時的な*レスポンスオブジェクトに `status_code` を設定できます。
|
||||
|
||||
{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
|
||||
|
||||
その後は通常どおり、必要な任意のオブジェクト(`dict`、データベースモデルなど)を返せます。
|
||||
|
||||
そして `response_model` を宣言していれば、返したオブジェクトのフィルタと変換には引き続きそれが使われます。
|
||||
|
||||
FastAPI はその*一時的な*レスポンスからステータスコード(および Cookie とヘッダー)を取り出し、`response_model` によってフィルタ済みの返却値を含む最終的なレスポンスに反映します。
|
||||
|
||||
また、`Response` パラメータは依存関係内に宣言してステータスコードを設定することもできます。ただし、最後に設定されたものが優先される点に注意してください。
|
||||
@@ -0,0 +1,51 @@
|
||||
# レスポンスの Cookie { #response-cookies }
|
||||
|
||||
## `Response` パラメータを使う { #use-a-response-parameter }
|
||||
|
||||
*path operation 関数*で `Response` 型のパラメータを宣言できます。
|
||||
|
||||
そして、その*一時的*なレスポンスオブジェクトに Cookie を設定できます。
|
||||
|
||||
{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
|
||||
|
||||
その後は通常どおり、必要な任意のオブジェクト(`dict`、データベースモデルなど)を返せます。
|
||||
|
||||
`response_model` を宣言している場合でも、返したオブジェクトは引き続きフィルタおよび変換されます。
|
||||
|
||||
**FastAPI** はその*一時的*なレスポンスから Cookie(およびヘッダーやステータスコード)を取り出し、`response_model` によってフィルタされた返却値を含む最終的なレスポンスに設定します。
|
||||
|
||||
`Response` パラメータは依存関係でも宣言でき、そこで Cookie(やヘッダー)を設定することも可能です。
|
||||
|
||||
## `Response` を直接返す { #return-a-response-directly }
|
||||
|
||||
コードで `Response` を直接返すときに、Cookie を作成することもできます。
|
||||
|
||||
そのためには、[Response を直接返す](response-directly.md){.internal-link target=_blank} で説明されているとおりにレスポンスを作成します。
|
||||
|
||||
そのレスポンスに Cookie を設定してから返します:
|
||||
|
||||
{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`Response` パラメータを使わずにレスポンスを直接返す場合、FastAPI はそのレスポンスをそのまま返します。
|
||||
|
||||
そのため、データの型が正しいことを確認する必要があります。例えば、`JSONResponse` を返すなら、JSON と互換性がある必要があります。
|
||||
|
||||
また、`response_model` によってフィルタされるべきデータを送っていないことも確認してください。
|
||||
|
||||
///
|
||||
|
||||
### 詳細情報 { #more-info }
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
`from starlette.responses import Response` や `from starlette.responses import JSONResponse` を使うこともできます。
|
||||
|
||||
**FastAPI** は開発者の利便性のために、`starlette.responses` と同じものを `fastapi.responses` として提供しています。ただし、利用可能なレスポンスの大半は Starlette から直接提供されています。
|
||||
|
||||
また、`Response` はヘッダーや Cookie の設定に頻繁に使われるため、`fastapi.Response` としても提供されています。
|
||||
|
||||
///
|
||||
|
||||
利用可能なすべてのパラメータやオプションについては、<a href="https://www.starlette.dev/responses/#set-cookie" class="external-link" target="_blank">Starlette のドキュメント</a>を参照してください。
|
||||
@@ -1,4 +1,4 @@
|
||||
# レスポンスを直接返す
|
||||
# レスポンスを直接返す { #return-a-response-directly }
|
||||
|
||||
**FastAPI** の *path operation* では、通常は任意のデータを返すことができます: 例えば、 `dict`、`list`、Pydanticモデル、データベースモデルなどです。
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
これは例えば、カスタムヘッダーやcookieを返すときに便利です。
|
||||
|
||||
## `Response` を返す
|
||||
## `Response` を返す { #return-a-response }
|
||||
|
||||
実際は、`Response` やそのサブクラスを返すことができます。
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
これは多くの柔軟性を提供します。任意のデータ型を返したり、任意のデータ宣言やバリデーションをオーバーライドできます。
|
||||
|
||||
## `jsonable_encoder` を `Response` の中で使う
|
||||
## `jsonable_encoder` を `Response` の中で使う { #using-the-jsonable-encoder-in-a-response }
|
||||
|
||||
**FastAPI** はあなたが返す `Response` に対して何も変更を加えないので、コンテンツが準備できていることを保証しなければなりません。
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
このようなケースでは、レスポンスにデータを含める前に `jsonable_encoder` を使ってデータを変換できます。
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *}
|
||||
{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
///
|
||||
|
||||
## カスタム `Response` を返す
|
||||
## カスタム `Response` を返す { #returning-a-custom-response }
|
||||
|
||||
上記の例では必要な部分を全て示していますが、あまり便利ではありません。`item` を直接返すことができるし、**FastAPI** はそれを `dict` に変換して `JSONResponse` に含めてくれるなど。すべて、デフォルトの動作です。
|
||||
|
||||
@@ -54,9 +54,9 @@
|
||||
|
||||
XMLを文字列にし、`Response` に含め、それを返します。
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
|
||||
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
|
||||
|
||||
## 備考
|
||||
## 備考 { #notes }
|
||||
|
||||
`Response` を直接返す場合、バリデーションや、変換 (シリアライズ) や、自動ドキュメントは行われません。
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# レスポンスヘッダー { #response-headers }
|
||||
|
||||
## `Response` パラメータを使う { #use-a-response-parameter }
|
||||
|
||||
(Cookie と同様に)*path operation 関数*で `Response` 型のパラメータを宣言できます。
|
||||
|
||||
そして、その*一時的*なレスポンスオブジェクトにヘッダーを設定できます。
|
||||
|
||||
{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}
|
||||
|
||||
その後は通常どおり、必要な任意のオブジェクト(`dict`、データベースモデルなど)を返せます。
|
||||
|
||||
`response_model` を宣言している場合は、返したオブジェクトのフィルタと変換に引き続き使用されます。
|
||||
|
||||
**FastAPI** はその*一時的*なレスポンスからヘッダー(Cookie やステータスコードも含む)を取り出し、`response_model` によってフィルタされた返却値を含む最終的なレスポンスに反映します。
|
||||
|
||||
また、依存関係の中で `Response` パラメータを宣言し、その中でヘッダー(や Cookie)を設定することもできます。
|
||||
|
||||
## `Response` を直接返す { #return-a-response-directly }
|
||||
|
||||
`Response` を直接返す場合にもヘッダーを追加できます。
|
||||
|
||||
[Response を直接返す](response-directly.md){.internal-link target=_blank} で説明したようにレスポンスを作成し、ヘッダーを追加のパラメータとして渡します:
|
||||
|
||||
{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
`from starlette.responses import Response` や `from starlette.responses import JSONResponse` を使うこともできます。
|
||||
|
||||
**FastAPI** は、開発者であるあなたへの便宜として、`starlette.responses` と同じものを `fastapi.responses` として提供しています。しかし、利用可能なレスポンスの大半は直接 Starlette から来ています。
|
||||
|
||||
また、`Response` はヘッダーや Cookie を設定するのによく使われるため、**FastAPI** は `fastapi.Response` でも提供しています。
|
||||
|
||||
///
|
||||
|
||||
## カスタムヘッダー { #custom-headers }
|
||||
|
||||
独自のカスタムヘッダーは、<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">`X-` プレフィックスを使って</a>追加できることに注意してください。
|
||||
|
||||
ただし、ブラウザのクライアントに見えるようにしたいカスタムヘッダーがある場合は、CORS 設定にそれらを追加する必要があります([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank} を参照)。このとき、<a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette の CORS ドキュメント</a>に記載の `expose_headers` パラメータを使用します。
|
||||
@@ -0,0 +1,107 @@
|
||||
# HTTP Basic 認証 { #http-basic-auth }
|
||||
|
||||
最もシンプルなケースでは、HTTP Basic 認証を利用できます。
|
||||
|
||||
HTTP Basic 認証では、アプリケーションはユーザー名とパスワードを含むヘッダーを期待します。
|
||||
|
||||
それを受け取れない場合、HTTP 401 "Unauthorized" エラーを返します。
|
||||
|
||||
そして、値が `Basic` のヘッダー `WWW-Authenticate` を、任意の `realm` パラメータとともに返します。
|
||||
|
||||
これにより、ブラウザは組み込みのユーザー名とパスワード入力プロンプトを表示します。
|
||||
|
||||
その後、そのユーザー名とパスワードを入力すると、ブラウザはそれらをヘッダーに自動的に付与して送信します。
|
||||
|
||||
## シンプルな HTTP Basic 認証 { #simple-http-basic-auth }
|
||||
|
||||
- `HTTPBasic` と `HTTPBasicCredentials` をインポートします。
|
||||
- `HTTPBasic` を使って「`security` スキーム」を作成します。
|
||||
- その `security` を依存関係として path operation に使用します。
|
||||
- `HTTPBasicCredentials` 型のオブジェクトが返ります:
|
||||
- 送信された `username` と `password` を含みます。
|
||||
|
||||
{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}
|
||||
|
||||
URL を最初に開こうとしたとき(またはドキュメントで「Execute」ボタンをクリックしたとき)、ブラウザはユーザー名とパスワードの入力を求めます:
|
||||
|
||||
<img src="/img/tutorial/security/image12.png">
|
||||
|
||||
## ユーザー名の確認 { #check-the-username }
|
||||
|
||||
より完全な例です。
|
||||
|
||||
依存関係を使ってユーザー名とパスワードが正しいかを確認します。
|
||||
|
||||
これには、Python 標準モジュール <a href="https://docs.python.org/3/library/secrets.html" class="external-link" target="_blank">`secrets`</a> を用いてユーザー名とパスワードを検証します。
|
||||
|
||||
`secrets.compare_digest()` は `bytes` か、ASCII 文字(英語の文字)のみを含む `str` を受け取る必要があります。つまり、`Sebastián` のように `á` を含む文字ではそのままでは動作しません。
|
||||
|
||||
これに対処するため、まず `username` と `password` を UTF-8 でエンコードして `bytes` に変換します。
|
||||
|
||||
そのうえで、`secrets.compare_digest()` を使って、`credentials.username` が `"stanleyjobson"` であり、`credentials.password` が `"swordfish"` であることを確認します。
|
||||
|
||||
{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}
|
||||
|
||||
これは次のようなコードに相当します:
|
||||
|
||||
```Python
|
||||
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
|
||||
# Return some error
|
||||
...
|
||||
```
|
||||
|
||||
しかし `secrets.compare_digest()` を使うことで、「タイミング攻撃」と呼ばれる種類の攻撃に対して安全になります。
|
||||
|
||||
### タイミング攻撃 { #timing-attacks }
|
||||
|
||||
「タイミング攻撃」とは何でしょうか?
|
||||
|
||||
攻撃者がユーザー名とパスワードを推測しようとしていると想像してください。
|
||||
|
||||
そして、ユーザー名 `johndoe`、パスワード `love123` を使ってリクエストを送ります。
|
||||
|
||||
その場合、アプリケーション内の Python コードは次のようなものと等価になります:
|
||||
|
||||
```Python
|
||||
if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
|
||||
...
|
||||
```
|
||||
|
||||
しかし、Python は `johndoe` の最初の `j` と `stanleyjobson` の最初の `s` を比較した時点で、両者の文字列が同じでないと判断してすぐに `False` を返します。つまり「残りの文字を比較して計算資源を無駄にする必要はない」と考えるわけです。そしてアプリケーションは「ユーザー名またはパスワードが正しくありません」と返します。
|
||||
|
||||
次に、攻撃者がユーザー名 `stanleyjobsox`、パスワード `love123` で試すとします。
|
||||
|
||||
アプリケーションのコードは次のようになります:
|
||||
|
||||
```Python
|
||||
if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
|
||||
...
|
||||
```
|
||||
|
||||
この場合、Python は `stanleyjobsox` と `stanleyjobson` の両方で `stanleyjobso` 全体を比較してから、文字列が同じでないと気づきます。したがって、「ユーザー名またはパスワードが正しくありません」と応答するまでに余分に数マイクロ秒かかります。
|
||||
|
||||
#### 応答時間が攻撃者を助ける { #the-time-to-answer-helps-the-attackers }
|
||||
|
||||
ここで、サーバーが「ユーザー名またはパスワードが正しくありません」というレスポンスを返すまでに、わずかに長い時間がかかったことに気づけば、攻撃者は何かしら正解に近づいた、すなわち先頭のいくつかの文字が正しかったことを知ることができます。
|
||||
|
||||
すると、`johndoe` よりも `stanleyjobsox` に近いものを狙って再試行できます。
|
||||
|
||||
#### 「プロ」レベルの攻撃 { #a-professional-attack }
|
||||
|
||||
もちろん、攻撃者はこれらを手作業では行わず、プログラムを書いて、1 秒間に数千〜数百万回のテストを行うでしょう。そして 1 回に 1 文字ずつ正しい文字を見つけていきます。
|
||||
|
||||
そうすることで、数分から数時間のうちに、攻撃者は私たちのアプリケーションの「助け」(応答にかかった時間)だけを利用して、正しいユーザー名とパスワードを推測できてしまいます。
|
||||
|
||||
#### `secrets.compare_digest()` で対策 { #fix-it-with-secrets-compare-digest }
|
||||
|
||||
しかし、私たちのコードでは実際に `secrets.compare_digest()` を使用しています。
|
||||
|
||||
要するに、`stanleyjobsox` と `stanleyjobson` を比較するのにかかる時間は、`johndoe` と `stanleyjobson` を比較するのにかかる時間と同じになります。パスワードでも同様です。
|
||||
|
||||
このように、アプリケーションコードで `secrets.compare_digest()` を使うと、この種の一連のセキュリティ攻撃に対して安全になります。
|
||||
|
||||
### エラーを返す { #return-the-error }
|
||||
|
||||
認証情報が不正であることを検出したら、ステータスコード 401(認証情報が提供されない場合と同じ)で `HTTPException` を返し、ブラウザに再度ログインプロンプトを表示させるためにヘッダー `WWW-Authenticate` を追加します:
|
||||
|
||||
{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}
|
||||
@@ -0,0 +1,19 @@
|
||||
# 高度なセキュリティ { #advanced-security }
|
||||
|
||||
## 追加機能 { #additional-features }
|
||||
|
||||
[チュートリアル - ユーザーガイド: セキュリティ](../../tutorial/security/index.md){.internal-link target=_blank}で扱ったもの以外にも、セキュリティを扱うための追加機能がいくつかあります。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
次の節は必ずしも「高度」ではありません。
|
||||
|
||||
あなたのユースケースでは、その中のいずれかに解決策があるかもしれません。
|
||||
|
||||
///
|
||||
|
||||
## まずチュートリアルを読む { #read-the-tutorial-first }
|
||||
|
||||
以下の節は、すでにメインの[チュートリアル - ユーザーガイド: セキュリティ](../../tutorial/security/index.md){.internal-link target=_blank}を読んでいることを前提とします。
|
||||
|
||||
いずれも同じ概念に基づいていますが、いくつかの追加機能を利用できます。
|
||||
@@ -0,0 +1,274 @@
|
||||
# OAuth2 のスコープ { #oauth2-scopes }
|
||||
|
||||
OAuth2 のスコープは **FastAPI** で直接利用でき、シームレスに統合されています。
|
||||
|
||||
これにより、OAuth2 標準に従った、よりきめ細かな権限システムを、OpenAPI 対応アプリケーション(および API ドキュメント)に統合できます。
|
||||
|
||||
スコープ付きの OAuth2 は、Facebook、Google、GitHub、Microsoft、X (Twitter) など、多くの大手認証プロバイダで使われている仕組みです。ユーザーやアプリケーションに特定の権限を付与するために利用されます。
|
||||
|
||||
「Facebook でログイン」「Google でログイン」「GitHub でログイン」「Microsoft でログイン」「X (Twitter) でログイン」するたびに、そのアプリケーションはスコープ付きの OAuth2 を使っています。
|
||||
|
||||
この節では、同じスコープ付き OAuth2 を使って、**FastAPI** アプリケーションで認証と認可を管理する方法を見ていきます。
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
これはやや高度な内容です。はじめたばかりであれば読み飛ばしても構いません。
|
||||
|
||||
OAuth2 のスコープは必ずしも必要ではなく、認証と認可は好きなやり方で実装できます。
|
||||
|
||||
ただし、スコープ付きの OAuth2 は、API(OpenAPI)や API ドキュメントにきれいに統合できます。
|
||||
|
||||
とはいえ、これらのスコープやその他のセキュリティ/認可要件の適用は、必要に応じてコードの中で行う必要があります。
|
||||
|
||||
多くの場合、スコープ付き OAuth2 はオーバースペックになりえます。
|
||||
|
||||
それでも必要だと分かっている場合や、興味がある場合は、このまま読み進めてください。
|
||||
|
||||
///
|
||||
|
||||
## OAuth2 のスコープと OpenAPI { #oauth2-scopes-and-openapi }
|
||||
|
||||
OAuth2 仕様では、「スコープ」は空白で区切られた文字列の一覧として定義されています。
|
||||
|
||||
各文字列の内容は任意ですが、空白は含められません。
|
||||
|
||||
これらのスコープは「権限」を表します。
|
||||
|
||||
OpenAPI(例: API ドキュメント)では、「セキュリティスキーム」を定義できます。
|
||||
|
||||
これらのセキュリティスキームの一つが OAuth2 を使う場合、スコープを宣言して利用できます。
|
||||
|
||||
各「スコープ」は、ただの文字列(空白なし)です。
|
||||
|
||||
通常、特定のセキュリティ権限を宣言するために使われます。例えば:
|
||||
|
||||
- `users:read` や `users:write` は一般的な例です。
|
||||
- `instagram_basic` は Facebook / Instagram で使われています。
|
||||
- `https://www.googleapis.com/auth/drive` は Google で使われています。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
OAuth2 において「スコープ」は、必要な特定の権限を宣言する単なる文字列です。
|
||||
|
||||
`:` のような他の文字が含まれていても、URL であっても問題ありません。
|
||||
|
||||
それらの詳細は実装依存です。
|
||||
|
||||
OAuth2 にとっては、単に文字列に過ぎません。
|
||||
|
||||
///
|
||||
|
||||
## 全体像 { #global-view }
|
||||
|
||||
まず、メインの**チュートリアル - ユーザーガイド**にある [OAuth2(パスワード[ハッシュ化あり])、Bearer と JWT トークン](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank} の例から変更される部分を、スコープ付き OAuth2 を使って手早く見てみましょう。
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}
|
||||
|
||||
では、これらの変更を一つずつ確認していきます。
|
||||
|
||||
## OAuth2 のセキュリティスキーム { #oauth2-security-scheme }
|
||||
|
||||
最初の変更点は、`me` と `items` の 2 つのスコープを持つ OAuth2 セキュリティスキームを宣言していることです。
|
||||
|
||||
`scopes` パラメータは、各スコープをキー、その説明を値とする `dict` を受け取ります:
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}
|
||||
|
||||
これらのスコープを宣言しているため、ログイン/認可時に API ドキュメントに表示されます。
|
||||
|
||||
そして、付与するスコープ(`me`、`items`)を選択できます。
|
||||
|
||||
これは、Facebook、Google、GitHub などでログイン時に権限を付与する際と同じ仕組みです:
|
||||
|
||||
<img src="/img/tutorial/security/image11.png">
|
||||
|
||||
## スコープ付きの JWT トークン { #jwt-token-with-scopes }
|
||||
|
||||
次に、トークンの path operation を修正して、要求されたスコープを返すようにします。
|
||||
|
||||
引き続き同じ `OAuth2PasswordRequestForm` を使用します。これには、リクエストで受け取った各スコープを含む、`str` の `list` である `scopes` プロパティが含まれます。
|
||||
|
||||
そして、そのスコープを JWT トークンの一部として返します。
|
||||
|
||||
/// danger | 警告
|
||||
|
||||
簡単のため、ここでは受け取ったスコープをそのままトークンに追加しています。
|
||||
|
||||
しかし、本番アプリケーションではセキュリティのため、ユーザーが実際に持つことができるスコープ、または事前に定義したスコープだけを追加するようにしてください。
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}
|
||||
|
||||
## path operation と依存関係でスコープを宣言 { #declare-scopes-in-path-operations-and-dependencies }
|
||||
|
||||
ここでは、`/users/me/items/` の path operation が `items` スコープを必要とするように宣言します。
|
||||
|
||||
そのために、`fastapi` から `Security` をインポートして使います。
|
||||
|
||||
`Security` は(`Depends` と同様に)依存関係を宣言できますが、さらにスコープ(文字列)のリストを受け取る `scopes` パラメータも持ちます。
|
||||
|
||||
この場合、`Security` に依存関数 `get_current_active_user` を渡します(`Depends` と同様です)。
|
||||
|
||||
加えて、`items` という 1 つのスコープ(複数でも可)を含む `list` も渡します。
|
||||
|
||||
依存関数 `get_current_active_user` は、`Depends` だけでなく `Security` でもサブ依存関係を宣言できます。自身のサブ依存関数(`get_current_user`)を宣言し、さらにスコープ要件を追加します。
|
||||
|
||||
この場合、`me` スコープを要求します(複数のスコープも可)。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
異なる場所で異なるスコープを追加する必要は必ずしもありません。
|
||||
|
||||
ここでは、**FastAPI** が異なるレベルで宣言されたスコープをどのように扱うかを示すためにそうしています。
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}
|
||||
|
||||
/// info | 技術詳細
|
||||
|
||||
`Security` は実際には `Depends` のサブクラスで、後述する追加パラメータが 1 つあるだけです。
|
||||
|
||||
しかし `Depends` の代わりに `Security` を使うことで、**FastAPI** はセキュリティスコープを宣言・内部利用でき、OpenAPI で API をドキュメント化できると判断します。
|
||||
|
||||
なお、`fastapi` から `Query`、`Path`、`Depends`、`Security` などをインポートする際、それらは実際には特殊なクラスを返す関数です。
|
||||
|
||||
///
|
||||
|
||||
## `SecurityScopes` を使う { #use-securityscopes }
|
||||
|
||||
次に、依存関数 `get_current_user` を更新します。
|
||||
|
||||
これは上記の依存関係から使用されます。
|
||||
|
||||
ここで、先ほど作成した同じ OAuth2 スキームを依存関係(`oauth2_scheme`)として宣言して使います。
|
||||
|
||||
この依存関数自体はスコープ要件を持たないため、`oauth2_scheme` には `Depends` を使えます。セキュリティスコープを指定する必要がない場合は `Security` を使う必要はありません。
|
||||
|
||||
さらに、`fastapi.security` からインポートする特別な型 `SecurityScopes` のパラメータを宣言します。
|
||||
|
||||
この `SecurityScopes` クラスは `Request` に似ています(`Request` はリクエストオブジェクトを直接取得するために使いました)。
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}
|
||||
|
||||
## `scopes` を使う { #use-the-scopes }
|
||||
|
||||
パラメータ `security_scopes` は `SecurityScopes` 型になります。
|
||||
|
||||
このオブジェクトは、自身およびこれをサブ依存として使うすべての依存関係で要求されるスコープを含む `scopes` プロパティ(リスト)を持ちます。つまり、すべての「依存元」... 少し分かりにくいかもしれませんが、後で再度説明します。
|
||||
|
||||
`security_scopes`(`SecurityScopes` クラスのインスタンス)は、要求されたスコープを空白で連結した 1 つの文字列を返す `scope_str` も提供します(これを使います)。
|
||||
|
||||
後で複数箇所で再利用(raise)できるように、`HTTPException` を 1 つ作成します。
|
||||
|
||||
この例外には、要求されたスコープがあればそれらを空白区切りの文字列(`scope_str` を使用)として含めます。このスコープ文字列は `WWW-Authenticate` ヘッダに入れます(仕様の一部です)。
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}
|
||||
|
||||
## `username` とデータ構造の検証 { #verify-the-username-and-data-shape }
|
||||
|
||||
`username` を取得できていることを確認し、スコープを取り出します。
|
||||
|
||||
そして、そのデータを Pydantic モデルで検証します(`ValidationError` 例外を捕捉)。JWT トークンの読み取りや Pydantic によるデータ検証でエラーが発生した場合は、先ほど作成した `HTTPException` を送出します。
|
||||
|
||||
そのために、Pydantic モデル `TokenData` に新しいプロパティ `scopes` を追加します。
|
||||
|
||||
Pydantic でデータを検証することで、例えばスコープは `str` の `list`、`username` は `str` といった、正確な型になっていることを保証できます。
|
||||
|
||||
そうしておけば、例えば誤って `dict` などが入って後でアプリケーションを破壊してしまい、セキュリティリスクになる、といった事態を避けられます。
|
||||
|
||||
また、その `username` を持つユーザーが存在することも確認し、存在しなければ、やはり先ほどの例外を送出します。
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}
|
||||
|
||||
## `scopes` の検証 { #verify-the-scopes }
|
||||
|
||||
この依存関数およびすべての依存元(path operation を含む)が要求するすべてのスコープが、受け取ったトークンに含まれていることを検証し、含まれていなければ `HTTPException` を送出します。
|
||||
|
||||
そのために、これらすべてのスコープを `str` の `list` として含む `security_scopes.scopes` を使います。
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}
|
||||
|
||||
## 依存関係ツリーとスコープ { #dependency-tree-and-scopes }
|
||||
|
||||
依存関係ツリーとスコープをもう一度見てみましょう。
|
||||
|
||||
`get_current_active_user` 依存関係は `get_current_user` をサブ依存として持つため、`get_current_active_user` で宣言された `"me"` スコープは、`get_current_user` に渡される `security_scopes.scopes` の必須スコープ一覧に含まれます。
|
||||
|
||||
path operation 自体も `"items"` スコープを宣言するため、これも `get_current_user` に渡される `security_scopes.scopes` に含まれます。
|
||||
|
||||
依存関係とスコープの階層は次のようになります:
|
||||
|
||||
- *path operation* `read_own_items` には:
|
||||
- 依存関係に対して必須スコープ `["items"]` がある:
|
||||
- `get_current_active_user`:
|
||||
- 依存関数 `get_current_active_user` には:
|
||||
- 依存関係に対して必須スコープ `["me"]` がある:
|
||||
- `get_current_user`:
|
||||
- 依存関数 `get_current_user` には:
|
||||
- 自身に必須スコープはない。
|
||||
- `oauth2_scheme` を使う依存関係がある。
|
||||
- `SecurityScopes` 型の `security_scopes` パラメータがある:
|
||||
- この `security_scopes` パラメータは、上で宣言されたすべてのスコープを含む `list` を持つ `scopes` プロパティを持つ。したがって:
|
||||
- *path operation* `read_own_items` では、`security_scopes.scopes` は `["me", "items"]` を含む。
|
||||
- *path operation* `read_users_me` では、`security_scopes.scopes` は `["me"]` を含む。これは依存関係 `get_current_active_user` に宣言されているため。
|
||||
- *path operation* `read_system_status` では、`security_scopes.scopes` は `[]`(空)になる。`scopes` を持つ `Security` を宣言しておらず、その依存関係 `get_current_user` も `scopes` を宣言していないため。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
重要で「魔法のよう」な点は、`get_current_user` が path operation ごとに異なる `scopes` のリストをチェックすることになる、ということです。
|
||||
|
||||
それは、それぞれの path operation と、その path operation の依存関係ツリー内の各依存関係で宣言された `scopes` によって決まります。
|
||||
|
||||
///
|
||||
|
||||
## `SecurityScopes` の詳細 { #more-details-about-securityscopes }
|
||||
|
||||
`SecurityScopes` はどの地点でも、複数箇所でも使えます。「ルート」の依存関係である必要はありません。
|
||||
|
||||
常に、その時点の `Security` 依存関係と、**その特定の** path operation と **その特定の** 依存関係ツリーにおける、すべての依存元で宣言されたセキュリティスコープを持ちます。
|
||||
|
||||
`SecurityScopes` には依存元で宣言されたすべてのスコープが入るため、トークンが必要なスコープを持っているかどうかを中央の依存関数で検証し、path operation ごとに異なるスコープ要件を宣言する、といった使い方ができます。
|
||||
|
||||
これらは path operation ごとに独立して検証されます。
|
||||
|
||||
## チェック { #check-it }
|
||||
|
||||
API ドキュメントを開くと、認証して、許可するスコープを指定できます。
|
||||
|
||||
<img src="/img/tutorial/security/image11.png">
|
||||
|
||||
どのスコープも選択しない場合は「認証済み」にはなりますが、`/users/me/` や `/users/me/items/` にアクセスしようとすると、権限が不足しているというエラーになります。`/status/` には引き続きアクセスできます。
|
||||
|
||||
`me` スコープだけを選択し、`items` スコープを選択しない場合は、`/users/me/` にはアクセスできますが、`/users/me/items/` にはアクセスできません。
|
||||
|
||||
これは、ユーザーがアプリケーションに与えた権限の範囲に応じて、サードパーティアプリケーションがこれらの path operation のいずれかに、ユーザーから提供されたトークンでアクセスしようとしたときに起こる動作です。
|
||||
|
||||
## サードパーティ統合について { #about-third-party-integrations }
|
||||
|
||||
この例では、OAuth2 の「password」フローを使用しています。
|
||||
|
||||
これは、(おそらく自前のフロントエンドで)自分たちのアプリケーションにログインする場合に適しています。
|
||||
|
||||
自分たちで管理しているため、`username` と `password` を受け取る相手を信頼できるからです。
|
||||
|
||||
しかし、他者が接続する OAuth2 アプリケーション(Facebook、Google、GitHub などに相当する認証プロバイダ)を構築する場合は、他のいずれかのフローを使用すべきです。
|
||||
|
||||
最も一般的なのは implicit フローです。
|
||||
|
||||
最も安全なのは code フローですが、手順が多く実装がより複雑です。複雑なため、多くのプロバイダは結局 implicit フローを推奨することがあります。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
各認証プロバイダがフローに独自の名称を付け、自社のブランドの一部にするのは一般的です。
|
||||
|
||||
しかし、最終的には同じ OAuth2 標準を実装しています。
|
||||
|
||||
///
|
||||
|
||||
**FastAPI** には、これらすべての OAuth2 認証フロー向けのユーティリティが `fastapi.security.oauth2` に含まれています。
|
||||
|
||||
## デコレータ `dependencies` での `Security` { #security-in-decorator-dependencies }
|
||||
|
||||
デコレータの `dependencies` パラメータに `Depends` の `list` を定義できるのと同様([path operation デコレータでの依存関係](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} 参照)、ここで `scopes` を指定した `Security` も使用できます。
|
||||
@@ -0,0 +1,302 @@
|
||||
# 設定と環境変数 { #settings-and-environment-variables }
|
||||
|
||||
多くの場合、アプリケーションは外部の設定や構成を必要とします。たとえば、シークレットキー、データベース認証情報、メールサービスの認証情報などです。
|
||||
|
||||
これらの設定の多くは可変(変更されうる)で、データベースのURLのようなものがあります。また、多くはシークレットのように機微な情報です。
|
||||
|
||||
そのため、アプリケーションが読み取る環境変数で提供するのが一般的です。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
環境変数について理解するには、[環境変数](../environment-variables.md){.internal-link target=_blank}を参照してください。
|
||||
|
||||
///
|
||||
|
||||
## 型とバリデーション { #types-and-validation }
|
||||
|
||||
これらの環境変数は Python の外部にあり、他のプログラムやシステム全体(Linux、Windows、macOS といった異なるOSを含む)と互換性が必要なため、文字列テキストのみを扱えます。
|
||||
|
||||
つまり、Python で環境変数から読み取られる値はすべて `str` になり、他の型への変換やバリデーションはコードで行う必要があります。
|
||||
|
||||
## Pydantic の `Settings` { #pydantic-settings }
|
||||
|
||||
幸いなことに、Pydantic には環境変数から来る設定を扱うための優れたユーティリティがあり、<a href="https://docs.pydantic.dev/latest/concepts/pydantic_settings/" class="external-link" target="_blank">Pydantic: Settings management</a> で提供されています。
|
||||
|
||||
### `pydantic-settings` のインストール { #install-pydantic-settings }
|
||||
|
||||
まず、[仮想環境](../virtual-environments.md){.internal-link target=_blank}を作成して有効化し、`pydantic-settings` パッケージをインストールします:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install pydantic-settings
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
また、次のように `all` エクストラをインストールすると付属します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[all]"
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### `Settings` オブジェクトを作成 { #create-the-settings-object }
|
||||
|
||||
Pydantic から `BaseSettings` をインポートして、そのサブクラスを作成します。これは Pydantic モデルとほぼ同じです。
|
||||
|
||||
Pydantic モデルと同様に、型アノテーションと(必要なら)デフォルト値を持つクラス属性を宣言します。
|
||||
|
||||
`Field()` による追加バリデーションなど、Pydantic モデルで使えるのと同じバリデーション機能をすべて利用できます。
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
コピペ用に手早く使いたい場合は、この例ではなく、下の最後の例を使ってください。
|
||||
|
||||
///
|
||||
|
||||
その後、その `Settings` クラスのインスタンス(この例では `settings` オブジェクト)を作成すると、Pydantic は環境変数を大文字小文字を区別せずに読み取ります。つまり、大文字の `APP_NAME` という変数は、属性 `app_name` に対しても読み取られます。
|
||||
|
||||
次に、データが変換・バリデーションされます。したがって、`settings` オブジェクトを使うと、宣言した型のデータ(例: `items_per_user` は `int`)が得られます。
|
||||
|
||||
### `settings` の使用 { #use-the-settings }
|
||||
|
||||
次に、アプリケーションで新しい `settings` オブジェクトを使用できます:
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}
|
||||
|
||||
### サーバーを実行 { #run-the-server }
|
||||
|
||||
次に、設定を環境変数として渡してサーバーを実行します。たとえば、`ADMIN_EMAIL` と `APP_NAME` を次のように設定できます:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.py
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
1つのコマンドに複数の環境変数を設定するには、スペースで区切ってコマンドの前に並べます。
|
||||
|
||||
///
|
||||
|
||||
すると、`admin_email` の設定は `"deadpool@example.com"` に設定されます。
|
||||
|
||||
`app_name` は `"ChimichangApp"` になります。
|
||||
|
||||
`items_per_user` はデフォルト値の `50` のままです。
|
||||
|
||||
## 別モジュールでの設定 { #settings-in-another-module }
|
||||
|
||||
[大規模アプリケーション - 複数ファイル](../tutorial/bigger-applications.md){.internal-link target=_blank} で見たように、これらの設定を別のモジュールファイルに置くこともできます。
|
||||
|
||||
たとえば、`config.py` というファイルに次のように書けます:
|
||||
|
||||
{* ../../docs_src/settings/app01_py310/config.py *}
|
||||
|
||||
そして、`main.py` というファイルでそれを使います:
|
||||
|
||||
{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
[大規模アプリケーション - 複数ファイル](../tutorial/bigger-applications.md){.internal-link target=_blank} で見たように、`__init__.py` ファイルも必要です。
|
||||
|
||||
///
|
||||
|
||||
## 依存関係での設定 { #settings-in-a-dependency }
|
||||
|
||||
場合によっては、どこでも使うグローバルな `settings` オブジェクトを持つ代わりに、依存関係から設定を提供すると便利なことがあります。
|
||||
|
||||
これは特にテスト時に有用で、依存関係を独自のカスタム設定で簡単にオーバーライドできるからです。
|
||||
|
||||
### 設定ファイル { #the-config-file }
|
||||
|
||||
前の例から続けると、`config.py` ファイルは次のようになります:
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}
|
||||
|
||||
ここでは、デフォルトのインスタンス `settings = Settings()` を作成していないことに注意してください。
|
||||
|
||||
### メインアプリファイル { #the-main-app-file }
|
||||
|
||||
ここでは、新しい `config.Settings()` を返す依存関係を作成します。
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`@lru_cache` については後で説明します。
|
||||
|
||||
今は `get_settings()` が普通の関数だと考えてください。
|
||||
|
||||
///
|
||||
|
||||
そして、*path operation 関数*から依存関係として要求し、必要な場所でどこでも使えます。
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}
|
||||
|
||||
### 設定とテスト { #settings-and-testing }
|
||||
|
||||
次に、`get_settings` の依存関係オーバーライドを作ることで、テスト中に別の設定オブジェクトを提供するのがとても簡単になります:
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}
|
||||
|
||||
依存関係オーバーライドでは、新しい `Settings` オブジェクトを作る際に `admin_email` に新しい値を設定し、その新しいオブジェクトを返します。
|
||||
|
||||
そして、それが使用されていることをテストできます。
|
||||
|
||||
## `.env` ファイルの読み込み { #reading-a-env-file }
|
||||
|
||||
変更が多くなりそうな設定が多数ある場合、環境ごとにファイルに入れて、環境変数としてそこから読み込むと便利なことがあります。
|
||||
|
||||
このプラクティスは十分に一般的で名前もあり、これらの環境変数は通常 `.env` というファイルに置かれ、そのファイルは「dotenv」と呼ばれます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ドット(`.`)で始まるファイルは、Linux や macOS のような Unix 系システムでは隠しファイルです。
|
||||
|
||||
ただし、dotenv ファイルは必ずしもその正確なファイル名である必要はありません。
|
||||
|
||||
///
|
||||
|
||||
Pydantic は外部ライブラリを使ってこの種のファイルからの読み込みをサポートしています。詳細は <a href="https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support" class="external-link" target="_blank">Pydantic Settings: Dotenv (.env) support</a> を参照してください。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これを機能させるには、`pip install python-dotenv` が必要です。
|
||||
|
||||
///
|
||||
|
||||
### `.env` ファイル { #the-env-file }
|
||||
|
||||
次のような `.env` ファイルを用意できます:
|
||||
|
||||
```bash
|
||||
ADMIN_EMAIL="deadpool@example.com"
|
||||
APP_NAME="ChimichangApp"
|
||||
```
|
||||
|
||||
### `.env` から設定を読む { #read-settings-from-env }
|
||||
|
||||
そして、`config.py` を次のように更新します:
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`model_config` 属性は Pydantic の設定専用です。詳しくは <a href="https://docs.pydantic.dev/latest/concepts/config/" class="external-link" target="_blank">Pydantic: Concepts: Configuration</a> を参照してください。
|
||||
|
||||
///
|
||||
|
||||
ここでは、Pydantic の `Settings` クラス内で設定 `env_file` を定義し、使用したい dotenv ファイルのファイル名を指定しています。
|
||||
|
||||
### `lru_cache` で `Settings` を一度だけ作成 { #creating-the-settings-only-once-with-lru-cache }
|
||||
|
||||
ディスクからファイルを読むのは通常コスト(遅延)が高い処理なので、1回だけ実行して同じ設定オブジェクトを再利用し、各リクエストごとに読み直さないのが望ましいです。
|
||||
|
||||
しかし、次のようにするたびに:
|
||||
|
||||
```Python
|
||||
Settings()
|
||||
```
|
||||
|
||||
新しい `Settings` オブジェクトが作成され、その作成時に `.env` ファイルが再度読み込まれます。
|
||||
|
||||
依存関数が次のようであれば:
|
||||
|
||||
```Python
|
||||
def get_settings():
|
||||
return Settings()
|
||||
```
|
||||
|
||||
各リクエストごとにそのオブジェクトを作成し、各リクエストごとに `.env` ファイルを読み込むことになります。⚠️
|
||||
|
||||
しかし、上に `@lru_cache` デコレータを使っているので、`Settings` オブジェクトは最初に呼び出されたときに一度だけ作成されます。✔️
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}
|
||||
|
||||
その後のリクエスト用の依存関係で `get_settings()` が呼ばれるたびに、`get_settings()` の内部コードを実行して新しい `Settings` オブジェクトを作るのではなく、最初の呼び出しで返されたのと同じオブジェクトを何度でも返します。
|
||||
|
||||
#### `lru_cache` の技術詳細 { #lru-cache-technical-details }
|
||||
|
||||
`@lru_cache` は、毎回関数のコードを実行して再計算するのではなく、最初に返した値を返すように、修飾する関数を変更します。
|
||||
|
||||
したがって、その下の関数は引数の組み合わせごとに一度だけ実行されます。そして、その各引数の組み合わせで返された値は、まったく同じ引数の組み合わせで呼び出されたときに何度でも再利用されます。
|
||||
|
||||
たとえば、次のような関数があるとします:
|
||||
|
||||
```Python
|
||||
@lru_cache
|
||||
def say_hi(name: str, salutation: str = "Ms."):
|
||||
return f"Hello {salutation} {name}"
|
||||
```
|
||||
|
||||
プログラムは次のように実行されます:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
participant code as Code
|
||||
participant function as say_hi()
|
||||
participant execute as Execute function
|
||||
|
||||
rect rgba(0, 255, 0, .1)
|
||||
code ->> function: say_hi(name="Camila")
|
||||
function ->> execute: execute function code
|
||||
execute ->> code: return the result
|
||||
end
|
||||
|
||||
rect rgba(0, 255, 255, .1)
|
||||
code ->> function: say_hi(name="Camila")
|
||||
function ->> code: return stored result
|
||||
end
|
||||
|
||||
rect rgba(0, 255, 0, .1)
|
||||
code ->> function: say_hi(name="Rick")
|
||||
function ->> execute: execute function code
|
||||
execute ->> code: return the result
|
||||
end
|
||||
|
||||
rect rgba(0, 255, 0, .1)
|
||||
code ->> function: say_hi(name="Rick", salutation="Mr.")
|
||||
function ->> execute: execute function code
|
||||
execute ->> code: return the result
|
||||
end
|
||||
|
||||
rect rgba(0, 255, 255, .1)
|
||||
code ->> function: say_hi(name="Rick")
|
||||
function ->> code: return stored result
|
||||
end
|
||||
|
||||
rect rgba(0, 255, 255, .1)
|
||||
code ->> function: say_hi(name="Camila")
|
||||
function ->> code: return stored result
|
||||
end
|
||||
```
|
||||
|
||||
今回の依存関数 `get_settings()` の場合、関数は引数を一切取りません。そのため、常に同じ値を返します。
|
||||
|
||||
この方法は、ほとんどグローバル変数のように振る舞います。しかし、依存関数を使っているので、テストのために簡単にオーバーライドできます。
|
||||
|
||||
`@lru_cache` は Python 標準ライブラリの `functools` の一部です。詳細は <a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">Python の `@lru_cache` ドキュメント</a>を参照してください。
|
||||
|
||||
## まとめ { #recap }
|
||||
|
||||
Pydantic Settings を使うことで、アプリケーションの設定や構成を、Pydantic モデルの力を活かして扱えます。
|
||||
|
||||
* 依存関係を使うことで、テストを簡素化できます。
|
||||
* `.env` ファイルを利用できます。
|
||||
* `@lru_cache` を使うと、各リクエストごとに dotenv ファイルを繰り返し読み込むのを避けつつ、テスト時にはオーバーライドできます。
|
||||
@@ -0,0 +1,67 @@
|
||||
# サブアプリケーション - マウント { #sub-applications-mounts }
|
||||
|
||||
それぞれ独立した OpenAPI とドキュメント UI を持つ2つの独立した FastAPI アプリケーションが必要な場合、メインアプリに1つ(以上)のサブアプリケーションを「マウント」できます。
|
||||
|
||||
## FastAPI アプリケーションのマウント { #mounting-a-fastapi-application }
|
||||
|
||||
「マウント」とは、特定のパスに完全に「独立した」アプリケーションを追加し、そのサブアプリケーションで宣言された path operation によって、そのパス以下のすべてを処理させることを意味します。
|
||||
|
||||
### トップレベルアプリケーション { #top-level-application }
|
||||
|
||||
まず、メインのトップレベル **FastAPI** アプリケーションと、その path operation を作成します:
|
||||
|
||||
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}
|
||||
|
||||
### サブアプリケーション { #sub-application }
|
||||
|
||||
次に、サブアプリケーションとその path operation を作成します。
|
||||
|
||||
このサブアプリケーションは通常の FastAPI アプリケーションですが、これを「マウント」します:
|
||||
|
||||
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}
|
||||
|
||||
### サブアプリケーションをマウント { #mount-the-sub-application }
|
||||
|
||||
トップレベルのアプリケーション `app` に、サブアプリケーション `subapi` をマウントします。
|
||||
|
||||
この例では、パス `/subapi` にマウントされます:
|
||||
|
||||
{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}
|
||||
|
||||
### 自動 API ドキュメントの確認 { #check-the-automatic-api-docs }
|
||||
|
||||
では、`fastapi` コマンドでこのファイルを実行します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev main.py
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
そして、<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> を開きます。
|
||||
|
||||
メインアプリ用の自動 API ドキュメントが表示され、そのアプリ自身の path operation のみが含まれます:
|
||||
|
||||
<img src="/img/tutorial/sub-applications/image01.png">
|
||||
|
||||
次に、サブアプリケーションのドキュメント <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a> を開きます。
|
||||
|
||||
サブアプリケーション用の自動 API ドキュメントが表示され、そのアプリ自身の path operation のみが、正しいサブパス接頭辞 `/subapi` の下で表示されます:
|
||||
|
||||
<img src="/img/tutorial/sub-applications/image02.png">
|
||||
|
||||
どちらの UI でも操作すれば正しく動作します。ブラウザがそれぞれのアプリ/サブアプリと通信できるためです。
|
||||
|
||||
### 技術詳細: `root_path` { #technical-details-root-path }
|
||||
|
||||
上記のようにサブアプリケーションをマウントすると、FastAPI は ASGI 仕様の `root_path` と呼ばれる仕組みを使って、そのサブアプリケーションへのマウントパスを伝播します。
|
||||
|
||||
このため、サブアプリケーションはドキュメント UI でそのパス接頭辞を使用すべきことを認識できます。
|
||||
|
||||
さらに、サブアプリケーション自身が別のサブアプリケーションをマウントしていても問題ありません。FastAPI がこれらの `root_path` をすべて自動的に処理するためです。
|
||||
|
||||
`root_path` の詳細や明示的な指定方法については、[プロキシの背後で](behind-a-proxy.md){.internal-link target=_blank} の節で学べます。
|
||||
@@ -0,0 +1,126 @@
|
||||
# テンプレート { #templates }
|
||||
|
||||
**FastAPI** では任意のテンプレートエンジンを使用できます。
|
||||
|
||||
Flask などでも使われている Jinja2 が一般的な選択肢です。
|
||||
|
||||
Starlette によって提供され、**FastAPI** アプリで直接使える、簡単に設定できるユーティリティがあります。
|
||||
|
||||
## 依存関係のインストール { #install-dependencies }
|
||||
|
||||
[仮想環境](../virtual-environments.md){.internal-link target=_blank} を作成して有効化し、`jinja2` をインストールします:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install jinja2
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## `Jinja2Templates` の使用 { #using-jinja2templates }
|
||||
|
||||
* `Jinja2Templates` をインポートします。
|
||||
* 後で再利用できる `templates` オブジェクトを作成します。
|
||||
* テンプレートを返す path operation に `Request` パラメータを宣言します。
|
||||
* 作成した `templates` を使って `TemplateResponse` をレンダリングして返します。テンプレート名、リクエストオブジェクト、Jinja2 テンプレート内で使用するキーと値のペアからなる "context" の辞書を渡します。
|
||||
|
||||
{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
FastAPI 0.108.0、Starlette 0.29.0 以前では、`name` は最初のパラメータでした。
|
||||
|
||||
またそれ以前のバージョンでは、`request` オブジェクトは Jinja2 用のコンテキスト内のキーと値のペアの一部として渡されていました。
|
||||
|
||||
///
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`response_class=HTMLResponse` を宣言すると、ドキュメント UI がレスポンスが HTML であることを認識できます。
|
||||
|
||||
///
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
`from starlette.templating import Jinja2Templates` を使うこともできます。
|
||||
|
||||
**FastAPI** は、開発者であるあなたの利便性のために、`starlette.templating` と同じものを `fastapi.templating` として提供しています。しかし、利用可能なレスポンスのほとんどは Starlette から直接提供されています。`Request` や `StaticFiles` も同様です。
|
||||
|
||||
///
|
||||
|
||||
## テンプレートの作成 { #writing-templates }
|
||||
|
||||
例えば、`templates/item.html` に次のようなテンプレートを書きます:
|
||||
|
||||
```jinja hl_lines="7"
|
||||
{!../../docs_src/templates/templates/item.html!}
|
||||
```
|
||||
|
||||
### テンプレートのコンテキスト値 { #template-context-values }
|
||||
|
||||
次のような HTML 内で:
|
||||
|
||||
{% raw %}
|
||||
|
||||
```jinja
|
||||
Item ID: {{ id }}
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
|
||||
...渡した "context" の `dict` から取得した `id` が表示されます:
|
||||
|
||||
```Python
|
||||
{"id": id}
|
||||
```
|
||||
|
||||
例えば、ID が `42` の場合は次のようにレンダリングされます:
|
||||
|
||||
```html
|
||||
Item ID: 42
|
||||
```
|
||||
|
||||
### テンプレートの `url_for` の引数 { #template-url-for-arguments }
|
||||
|
||||
テンプレート内でも `url_for()` を使用できます。引数には、対応する path operation 関数で使われるのと同じ引数を取ります。
|
||||
|
||||
したがって、次の部分は:
|
||||
|
||||
{% raw %}
|
||||
|
||||
```jinja
|
||||
<a href="{{ url_for('read_item', id=id) }}">
|
||||
```
|
||||
|
||||
{% endraw %}
|
||||
|
||||
...path operation 関数 `read_item(id=id)` が処理するのと同じ URL へのリンクを生成します。
|
||||
|
||||
例えば、ID が `42` の場合は次のようにレンダリングされます:
|
||||
|
||||
```html
|
||||
<a href="/items/42">
|
||||
```
|
||||
|
||||
## テンプレートと静的ファイル { #templates-and-static-files }
|
||||
|
||||
テンプレート内で `url_for()` を使用し、例えば `name="static"` でマウントした `StaticFiles` に対して利用できます。
|
||||
|
||||
```jinja hl_lines="4"
|
||||
{!../../docs_src/templates/templates/item.html!}
|
||||
```
|
||||
|
||||
この例では、`static/styles.css` の CSS ファイルにリンクします:
|
||||
|
||||
```CSS hl_lines="4"
|
||||
{!../../docs_src/templates/static/styles.css!}
|
||||
```
|
||||
|
||||
また、`StaticFiles` を使用しているため、その CSS ファイルは **FastAPI** アプリケーションから URL `/static/styles.css` で自動的に配信されます。
|
||||
|
||||
## さらに詳しく { #more-details }
|
||||
|
||||
より詳しい内容(テンプレートのテスト方法など)については、<a href="https://www.starlette.dev/templates/" class="external-link" target="_blank">Starlette のテンプレートに関するドキュメント</a>を参照してください。
|
||||
@@ -0,0 +1,53 @@
|
||||
# 依存関係のオーバーライドによるテスト { #testing-dependencies-with-overrides }
|
||||
|
||||
## テスト時の依存関係のオーバーライド { #overriding-dependencies-during-testing }
|
||||
|
||||
テスト中に依存関係をオーバーライドしたい場面がいくつかあります。
|
||||
|
||||
元の依存関係(およびそれにぶら下がるサブ依存関係)を実行したくない場合です。
|
||||
|
||||
代わりに、テストの間だけ(特定のテストだけでも)使われる別の依存関係を提供し、元の依存関係の値が使われていた箇所で利用できる値を返したいのです。
|
||||
|
||||
### ユースケース: 外部サービス { #use-cases-external-service }
|
||||
|
||||
例として、呼び出す必要がある外部の認証プロバイダがあるとします。
|
||||
|
||||
トークンを送ると、認証済みユーザーが返ってきます。
|
||||
|
||||
このプロバイダはリクエストごとに課金されるかもしれず、テスト用に固定のモックユーザーを使う場合に比べて呼び出しに余分な時間がかかるかもしれません。
|
||||
|
||||
外部プロバイダ自体の動作は一度はテストしたいでしょうが、実行されるすべてのテストで毎回呼び出す必要はありません。
|
||||
|
||||
この場合、そのプロバイダを呼び出す依存関係をオーバーライドし、テストのときだけモックユーザーを返すカスタムの依存関係を使えます。
|
||||
|
||||
### app.dependency_overrides 属性を使う { #use-the-app-dependency-overrides-attribute }
|
||||
|
||||
このような場合のために、**FastAPI** アプリケーションには `app.dependency_overrides` という属性があり、これは単純な `dict` です。
|
||||
|
||||
テスト用に依存関係をオーバーライドするには、キーに元の依存関係(関数)を、値にオーバーライドする依存関係(別の関数)を設定します。
|
||||
|
||||
すると **FastAPI** は元の依存関係の代わりにそのオーバーライドを呼び出します。
|
||||
|
||||
{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
アプリケーション内のどこで使われている依存関係に対しても、依存関係のオーバーライドを設定できます。
|
||||
|
||||
元の依存関係は、*path operation 関数*、*path operation デコレータ*(戻り値を使わない場合)、`.include_router()` の呼び出しなど、さまざまな場所で使われていてもかまいません。
|
||||
|
||||
FastAPI はそれでもオーバーライドできます。
|
||||
|
||||
///
|
||||
|
||||
その後、`app.dependency_overrides` を空の `dict` に設定することで、オーバーライドをリセット(削除)できます:
|
||||
|
||||
```Python
|
||||
app.dependency_overrides = {}
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
一部のテストの間だけ依存関係をオーバーライドしたい場合は、テストの開始時(テスト関数内)にオーバーライドを設定し、終了時(テスト関数の末尾)にリセットするとよいです。
|
||||
|
||||
///
|
||||
@@ -0,0 +1,11 @@
|
||||
# イベントのテスト: lifespan と startup - shutdown { #testing-events-lifespan-and-startup-shutdown }
|
||||
|
||||
テストで `lifespan` を実行する必要がある場合は、`with` 文と併用して `TestClient` を使用できます:
|
||||
|
||||
{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}
|
||||
|
||||
より詳しい内容は、[公式 Starlette ドキュメントの「テストでの lifespan の実行」](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) を参照してください。
|
||||
|
||||
非推奨の `startup` および `shutdown` イベントについては、次のように `TestClient` を使用できます:
|
||||
|
||||
{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}
|
||||
@@ -0,0 +1,13 @@
|
||||
# WebSocket のテスト { #testing-websockets }
|
||||
|
||||
WebSocket をテストするのにも同じ `TestClient` を使用できます。
|
||||
|
||||
そのために、`with` 文の中で `TestClient` を使用し、WebSocket に接続します:
|
||||
|
||||
{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
詳細については、Starlette のドキュメント「<a href="https://www.starlette.dev/testclient/#testing-websocket-sessions" class="external-link" target="_blank">WebSocket のテスト</a>」を参照してください。
|
||||
|
||||
///
|
||||
@@ -0,0 +1,56 @@
|
||||
# Request を直接使う { #using-the-request-directly }
|
||||
|
||||
これまで、必要なリクエストの各部分を、その型とともに宣言してきました。
|
||||
|
||||
次の場所からデータを取得します:
|
||||
|
||||
- パスのパラメータ
|
||||
- ヘッダー
|
||||
- クッキー
|
||||
- など
|
||||
|
||||
こうすることで、**FastAPI** はそのデータを検証し、変換し、API のドキュメントを自動生成します。
|
||||
|
||||
しかし、`Request` オブジェクトに直接アクセスする必要がある場面もあります。
|
||||
|
||||
## `Request` オブジェクトの詳細 { #details-about-the-request-object }
|
||||
|
||||
**FastAPI** は内部的には **Starlette** の上にいくつかのツール層を載せたものなので、必要に応じて Starlette の <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">`Request`</a> オブジェクトを直接使えます。
|
||||
|
||||
また、`Request` オブジェクトから直接データ(例: ボディ)を取得する場合、そのデータは FastAPI によって検証・変換・ドキュメント化(OpenAPI による自動 API ユーザーインターフェース向け)されません。
|
||||
|
||||
ただし、通常どおりに宣言された他のパラメータ(例: Pydantic モデルのボディ)は引き続き検証・変換・注釈付けなどが行われます。
|
||||
|
||||
それでも、`Request` オブジェクトを取得するのが有用な特定のケースがあります。
|
||||
|
||||
## `Request` オブジェクトを直接使う { #use-the-request-object-directly }
|
||||
|
||||
たとえば、path operation 関数内でクライアントの IP アドレス/ホストを取得したいとします。
|
||||
|
||||
そのためには、リクエストに直接アクセスする必要があります。
|
||||
|
||||
{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}
|
||||
|
||||
path operation 関数の引数として `Request` 型のパラメータを宣言すると、**FastAPI** はその引数に `Request` を渡します。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
この例では、`Request` 型の引数に加えて、パスパラメータも宣言しています。
|
||||
|
||||
そのため、パスパラメータは取り出され、検証され、指定した型に変換され、OpenAPI で注釈(ドキュメント化)されます。
|
||||
|
||||
同様に、通常どおり任意の他のパラメータを宣言しつつ、追加で `Request` も受け取れます。
|
||||
|
||||
///
|
||||
|
||||
## `Request` のドキュメント { #request-documentation }
|
||||
|
||||
より詳しくは、<a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">公式 Starlette ドキュメントサイトの `Request` オブジェクト</a>を参照してください。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
`from starlette.requests import Request` を使うこともできます。
|
||||
|
||||
**FastAPI** は開発者である皆さんの便宜のために直接提供していますが、これは Starlette からそのまま提供されているものです。
|
||||
|
||||
///
|
||||
@@ -1,10 +1,10 @@
|
||||
# WebSocket
|
||||
# WebSockets { #websockets }
|
||||
|
||||
**FastAPI**で<a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSocket</a>が使用できます。
|
||||
**FastAPI**で<a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSockets</a>が使用できます。
|
||||
|
||||
## `WebSockets`のインストール
|
||||
## `websockets`のインストール { #install-websockets }
|
||||
|
||||
まず `WebSockets`のインストールが必要です。
|
||||
[仮想環境](../virtual-environments.md){.internal-link target=_blank}を作成し、それを有効化してから、「WebSocket」プロトコルを簡単に使えるようにするPythonライブラリの`websockets`をインストールしてください。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -16,13 +16,13 @@ $ pip install websockets
|
||||
|
||||
</div>
|
||||
|
||||
## WebSocket クライアント
|
||||
## WebSockets クライアント { #websockets-client }
|
||||
|
||||
### 本番環境
|
||||
### 本番環境 { #in-production }
|
||||
|
||||
本番環境では、React、Vue.js、Angularなどの最新のフレームワークで作成されたフロントエンドを使用しているでしょう。
|
||||
|
||||
そして、バックエンドとWebSocketを使用して通信するために、おそらくフロントエンドのユーティリティを使用することになるでしょう。
|
||||
そして、バックエンドとWebSocketsを使用して通信するために、おそらくフロントエンドのユーティリティを使用することになるでしょう。
|
||||
|
||||
または、ネイティブコードでWebSocketバックエンドと直接通信するネイティブモバイルアプリケーションがあるかもしれません。
|
||||
|
||||
@@ -30,21 +30,21 @@ $ pip install websockets
|
||||
|
||||
---
|
||||
|
||||
ただし、この例では非常にシンプルなHTML文書といくつかのJavaScriptを、すべてソースコードの中に入れて使用することにします。
|
||||
ただし、この例では非常にシンプルなHTML文書といくつかのJavaScriptを、すべて長い文字列の中に入れて使用することにします。
|
||||
|
||||
もちろん、これは最適な方法ではありませんし、本番環境で使うことはないでしょう。
|
||||
|
||||
本番環境では、上記の方法のいずれかの選択肢を採用することになるでしょう。
|
||||
|
||||
しかし、これはWebSocketのサーバーサイドに焦点を当て、実用的な例を示す最も簡単な方法です。
|
||||
しかし、これはWebSocketsのサーバーサイドに焦点を当て、動作する例を示す最も簡単な方法です。
|
||||
|
||||
{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *}
|
||||
{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}
|
||||
|
||||
## `websocket` を作成する
|
||||
## `websocket` を作成する { #create-a-websocket }
|
||||
|
||||
**FastAPI** アプリケーションで、`websocket` を作成します。
|
||||
|
||||
{* ../../docs_src/websockets/tutorial001.py hl[1,46:47] *}
|
||||
{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
@@ -54,22 +54,22 @@ $ pip install websockets
|
||||
|
||||
///
|
||||
|
||||
## メッセージの送受信
|
||||
## メッセージを待機して送信する { #await-for-messages-and-send-messages }
|
||||
|
||||
WebSocketルートでは、 `await` を使ってメッセージの送受信ができます。
|
||||
WebSocketルートでは、メッセージを待機して送信するために `await` を使用できます。
|
||||
|
||||
{* ../../docs_src/websockets/tutorial001.py hl[48:52] *}
|
||||
{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}
|
||||
|
||||
バイナリやテキストデータ、JSONデータを送受信できます。
|
||||
|
||||
## 試してみる
|
||||
## 試してみる { #try-it }
|
||||
|
||||
ファイル名が `main.py` である場合、以下の方法でアプリケーションを実行します。
|
||||
ファイル名が `main.py` である場合、以下でアプリケーションを実行します。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
$ fastapi dev main.py
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
@@ -86,7 +86,7 @@ $ uvicorn main:app --reload
|
||||
|
||||
<img src="/img/tutorial/websockets/image02.png">
|
||||
|
||||
そして、 WebSocketを使用した**FastAPI**アプリケーションが応答します。
|
||||
そして、 WebSocketsを使用した**FastAPI**アプリケーションが応答します。
|
||||
|
||||
<img src="/img/tutorial/websockets/image03.png">
|
||||
|
||||
@@ -96,7 +96,7 @@ $ uvicorn main:app --reload
|
||||
|
||||
そして、これらの通信はすべて同じWebSocket接続を使用します。
|
||||
|
||||
## 依存関係
|
||||
## `Depends` などの使用 { #using-depends-and-others }
|
||||
|
||||
WebSocketエンドポイントでは、`fastapi` から以下をインポートして使用できます。
|
||||
|
||||
@@ -107,28 +107,26 @@ WebSocketエンドポイントでは、`fastapi` から以下をインポート
|
||||
* `Path`
|
||||
* `Query`
|
||||
|
||||
これらは、他のFastAPI エンドポイント/*path operation* の場合と同じように機能します。
|
||||
これらは、他のFastAPI エンドポイント/*path operations* の場合と同じように機能します。
|
||||
|
||||
{* ../../docs_src/websockets/tutorial002.py hl[58:65,68:83] *}
|
||||
{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
WebSocket で `HTTPException` を発生させることはあまり意味がありません。したがって、WebSocketの接続を直接閉じる方がよいでしょう。
|
||||
これはWebSocketであるため、`HTTPException` を発生させることはあまり意味がありません。代わりに `WebSocketException` を発生させます。
|
||||
|
||||
クロージングコードは、<a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">仕様で定義された有効なコード</a>の中から使用することができます。
|
||||
|
||||
将来的には、どこからでも `raise` できる `WebSocketException` が用意され、専用の例外ハンドラを追加できるようになる予定です。これは、Starlette の <a href="https://github.com/encode/starlette/pull/527" class="external-link" target="_blank">PR #527</a> に依存するものです。
|
||||
|
||||
///
|
||||
|
||||
### 依存関係を用いてWebSocketsを試してみる
|
||||
### 依存関係を用いてWebSocketsを試してみる { #try-the-websockets-with-dependencies }
|
||||
|
||||
ファイル名が `main.py` である場合、以下の方法でアプリケーションを実行します。
|
||||
ファイル名が `main.py` である場合、以下でアプリケーションを実行します。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
$ fastapi dev main.py
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
@@ -137,14 +135,14 @@ $ uvicorn main:app --reload
|
||||
|
||||
ブラウザで <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> を開きます。
|
||||
|
||||
クライアントが設定できる項目は以下の通りです。
|
||||
そこで、以下を設定できます。
|
||||
|
||||
* パスで使用される「Item ID」
|
||||
* クエリパラメータとして使用される「Token」
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
クエリ `token` は依存パッケージによって処理されることに注意してください。
|
||||
クエリ `token` は依存関係によって処理されることに注意してください。
|
||||
|
||||
///
|
||||
|
||||
@@ -152,11 +150,11 @@ $ uvicorn main:app --reload
|
||||
|
||||
<img src="/img/tutorial/websockets/image05.png">
|
||||
|
||||
## 切断や複数クライアントへの対応
|
||||
## 切断や複数クライアントの処理 { #handling-disconnections-and-multiple-clients }
|
||||
|
||||
WebSocket接続が閉じられると、 `await websocket.receive_text()` は例外 `WebSocketDisconnect` を発生させ、この例のようにキャッチして処理することができます。
|
||||
|
||||
{* ../../docs_src/websockets/tutorial003.py hl[81:83] *}
|
||||
{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}
|
||||
|
||||
試してみるには、
|
||||
|
||||
@@ -174,15 +172,15 @@ Client #1596980209979 left the chat
|
||||
|
||||
上記のアプリは、複数の WebSocket 接続に対してメッセージを処理し、ブロードキャストする方法を示すための最小限のシンプルな例です。
|
||||
|
||||
しかし、すべての接続がメモリ内の単一のリストで処理されるため、プロセスの実行中にのみ機能し、単一のプロセスでのみ機能することに注意してください。
|
||||
しかし、すべてがメモリ内の単一のリストで処理されるため、プロセスの実行中にのみ機能し、単一のプロセスでのみ機能することに注意してください。
|
||||
|
||||
もしFastAPIと簡単に統合できて、RedisやPostgreSQLなどでサポートされている、より堅牢なものが必要なら、<a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a> を確認してください。
|
||||
FastAPIと簡単に統合できて、RedisやPostgreSQLなどでサポートされている、より堅牢なものが必要なら、<a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a> を確認してください。
|
||||
|
||||
///
|
||||
|
||||
## その他のドキュメント
|
||||
## 詳細情報 { #more-info }
|
||||
|
||||
オプションの詳細については、Starletteのドキュメントを確認してください。
|
||||
|
||||
* <a href="https://www.starlette.dev/websockets/" class="external-link" target="_blank"> `WebSocket` クラス</a>
|
||||
* <a href="https://www.starlette.dev/endpoints/#websocketendpoint" class="external-link" target="_blank">クラスベースのWebSocket処理</a>
|
||||
* <a href="https://www.starlette.dev/websockets/" class="external-link" target="_blank">`WebSocket` クラス</a>.
|
||||
* <a href="https://www.starlette.dev/endpoints/#websocketendpoint" class="external-link" target="_blank">クラスベースのWebSocket処理</a>.
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# WSGI の組み込み - Flask、Django など { #including-wsgi-flask-django-others }
|
||||
|
||||
[サブアプリケーション - マウント](sub-applications.md){.internal-link target=_blank}、[プロキシの背後](behind-a-proxy.md){.internal-link target=_blank} で見たように、WSGI アプリケーションをマウントできます。
|
||||
|
||||
そのために `WSGIMiddleware` を使用して、Flask や Django などの WSGI アプリをラップできます。
|
||||
|
||||
## `WSGIMiddleware` の使用 { #using-wsgimiddleware }
|
||||
|
||||
/// info | 情報
|
||||
|
||||
これには `a2wsgi` のインストールが必要です。例: `pip install a2wsgi`。
|
||||
|
||||
///
|
||||
|
||||
`a2wsgi` から `WSGIMiddleware` をインポートします。
|
||||
|
||||
次に、そのミドルウェアで WSGI(例: Flask)アプリをラップします。
|
||||
|
||||
そして、それをあるパスの下にマウントします。
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
以前は `fastapi.middleware.wsgi` の `WSGIMiddleware` を使用することが推奨されていましたが、現在は非推奨です。
|
||||
|
||||
代わりに `a2wsgi` パッケージを使用することを推奨します。使い方は同じです。
|
||||
|
||||
`a2wsgi` パッケージがインストールされていることを確認し、`a2wsgi` から `WSGIMiddleware` を正しくインポートしてください。
|
||||
|
||||
///
|
||||
|
||||
## チェック { #check-it }
|
||||
|
||||
これで、パス `/v1/` 配下へのすべてのリクエストは Flask アプリケーションが処理します。
|
||||
|
||||
それ以外は **FastAPI** が処理します。
|
||||
|
||||
実行して <a href="http://localhost:8000/v1/" class="external-link" target="_blank">http://localhost:8000/v1/</a> にアクセスすると、Flask からのレスポンスが表示されます:
|
||||
|
||||
```txt
|
||||
Hello, World from Flask!
|
||||
```
|
||||
|
||||
さらに <a href="http://localhost:8000/v2" class="external-link" target="_blank">http://localhost:8000/v2</a> にアクセスすると、FastAPI からのレスポンスが表示されます:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"message": "Hello World"
|
||||
}
|
||||
```
|
||||
@@ -1,8 +1,8 @@
|
||||
# 代替ツールから受けたインスピレーションと比較
|
||||
# 代替ツールから受けたインスピレーションと比較 { #alternatives-inspiration-and-comparisons }
|
||||
|
||||
何が**FastAPI**にインスピレーションを与えたのか、他の代替ツールと比較してどうか、そしてそこから何を学んだのかについて。
|
||||
|
||||
## はじめに
|
||||
## はじめに { #intro }
|
||||
|
||||
**FastAPI**は、代替ツールのこれまでの働きがなければ存在しなかったでしょう。
|
||||
|
||||
@@ -12,17 +12,17 @@
|
||||
|
||||
しかし、その時点では、これらの機能をすべて提供し、以前のツールから優れたアイデアを取り入れ、可能な限り最高の方法でそれらを組み合わせ、それまで利用できなかった言語機能 (Python 3.6以降の型ヒント) を利用したものを作る以外に選択肢はありませんでした。
|
||||
|
||||
## 以前のツール
|
||||
## 以前のツール { #previous-tools }
|
||||
|
||||
### <a href="https://www.djangoproject.com/" class="external-link" target="_blank">Django</a>
|
||||
### <a href="https://www.djangoproject.com/" class="external-link" target="_blank">Django</a> { #django }
|
||||
|
||||
Pythonのフレームワークの中で最もポピュラーで、広く信頼されています。Instagramのようなシステムの構築に使われています。
|
||||
|
||||
リレーショナルデータベース (MySQLやPostgreSQLなど) と比較的強固に結合されているので、NoSQLデータベース (Couchbase、MongoDB、Cassandraなど) をメインに利用することは簡単ではありません。
|
||||
|
||||
バックエンドでHTMLを生成するために作られたものであり、現代的なフロントエンド (ReactやVue.js、Angularなど) や、他のシステム (IoTデバイスなど) と通信するAPIを構築するために作られたものではありません。
|
||||
バックエンドでHTMLを生成するために作られたものであり、現代的なフロントエンド (ReactやVue.js、Angularなど) や、他のシステム (<abbr title="Internet of Things - モノのインターネット">IoT</abbr>デバイスなど) と通信するAPIを構築するために作られたものではありません。
|
||||
|
||||
### <a href="https://www.django-rest-framework.org/" class="external-link" target="_blank">Django REST Framework</a>
|
||||
### <a href="https://www.django-rest-framework.org/" class="external-link" target="_blank">Django REST Framework</a> { #django-rest-framework }
|
||||
|
||||
Django REST Frameworkは、Djangoを下敷きにしてWeb APIを構築する柔軟なツールキットとして、APIの機能を向上させるために作られました。
|
||||
|
||||
@@ -42,7 +42,7 @@ Django REST Framework は Tom Christie によって作成されました。Starl
|
||||
|
||||
///
|
||||
|
||||
### <a href="http://flask.pocoo.org/" class="external-link" target="_blank">Flask</a>
|
||||
### <a href="https://flask.palletsprojects.com" class="external-link" target="_blank">Flask</a> { #flask }
|
||||
|
||||
Flask は「マイクロフレームワーク」であり、データベースとの統合のようなDjangoがデフォルトで持つ多くの機能は含まれていません。
|
||||
|
||||
@@ -64,7 +64,7 @@ Flaskのシンプルさを考えると、APIを構築するのに適している
|
||||
|
||||
///
|
||||
|
||||
### <a href="http://docs.python-requests.org" class="external-link" target="_blank">Requests</a>
|
||||
### <a href="https://requests.readthedocs.io" class="external-link" target="_blank">Requests</a> { #requests }
|
||||
|
||||
**FastAPI**は実際には**Requests**の代替ではありません。それらのスコープは大きく異なります。
|
||||
|
||||
@@ -80,7 +80,7 @@ Requestsは非常にシンプルかつ直感的なデザインで使いやすく
|
||||
|
||||
公式サイトで以下のように言われているのは、それが理由です。
|
||||
|
||||
> Requestsは今までで最もダウンロードされたPythonパッケージである
|
||||
> Requestsは史上最もダウンロードされたPythonパッケージのひとつです
|
||||
|
||||
使い方はとても簡単です。例えば、`GET`リクエストを実行するには、このように書けば良いです:
|
||||
|
||||
@@ -88,7 +88,7 @@ Requestsは非常にシンプルかつ直感的なデザインで使いやすく
|
||||
response = requests.get("http://example.com/some/url")
|
||||
```
|
||||
|
||||
対応するFastAPIのパスオペレーションはこのようになります:
|
||||
対応するFastAPIのAPIのpath operationはこのようになります:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@app.get("/some/url")
|
||||
@@ -106,7 +106,7 @@ def read_url():
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://swagger.io/" class="external-link" target="_blank">Swagger</a> / <a href="https://github.com/OAI/OpenAPI-Specification/" class="external-link" target="_blank">OpenAPI</a>
|
||||
### <a href="https://swagger.io/" class="external-link" target="_blank">Swagger</a> / <a href="https://github.com/OAI/OpenAPI-Specification/" class="external-link" target="_blank">OpenAPI</a> { #swagger-openapi }
|
||||
|
||||
私がDjango REST Frameworkに求めていた主な機能は、APIの自動的なドキュメント生成でした。
|
||||
|
||||
@@ -131,13 +131,13 @@ def read_url():
|
||||
|
||||
///
|
||||
|
||||
### Flask REST フレームワーク
|
||||
### Flask REST フレームワーク { #flask-rest-frameworks }
|
||||
|
||||
いくつかのFlask RESTフレームワークがありますが、それらを調査してみたところ、多くのものが不適切な問題が残ったまま、中断されたり放置されていることがわかりました。
|
||||
|
||||
### <a href="https://marshmallow.readthedocs.io/en/3.0/" class="external-link" target="_blank">Marshmallow</a>
|
||||
### <a href="https://marshmallow.readthedocs.io/en/stable/" class="external-link" target="_blank">Marshmallow</a> { #marshmallow }
|
||||
|
||||
APIシステムで必要とされる主な機能の一つに、コード (Python) からデータを取り出して、ネットワークを介して送れるものに変換するデータの「<abbr title="marshalling, conversion">シリアライゼーション</abbr>」があります。例えば、データベースのデータを含むオブジェクトをJSONオブジェクトに変換したり、`datetime` オブジェクトを文字列に変換するなどです。
|
||||
APIシステムで必要とされる主な機能の一つに、コード (Python) からデータを取り出して、ネットワークを介して送れるものに変換するデータの「<dfn title="別名: marshalling、変換">シリアライゼーション</dfn>」があります。例えば、データベースのデータを含むオブジェクトをJSONオブジェクトに変換したり、`datetime` オブジェクトを文字列に変換するなどです。
|
||||
|
||||
APIが必要とするもう一つの大きな機能はデータのバリデーションであり、特定のパラメータが与えられた場合にデータが有効であることを確認することです。例えば、あるフィールドがランダムな文字列ではなく `int` であることなどです。これは特に受信するデータに対して便利です。
|
||||
|
||||
@@ -145,7 +145,7 @@ APIが必要とするもう一つの大きな機能はデータのバリデー
|
||||
|
||||
これらの機能は、Marshmallowが提供するものです。Marshmallowは素晴らしいライブラリで、私も以前に何度も使ったことがあります。
|
||||
|
||||
しかし、それはPythonの型ヒントが存在する前に作られたものです。そのため、すべての<abbr title="データがどのように形成されるべきかの定義">スキーマ</abbr>を定義するためには、Marshmallowが提供する特定のユーティリティやクラスを使用する必要があります。
|
||||
しかし、それはPythonの型ヒントが存在する前に作られたものです。そのため、すべての<dfn title="データがどのように構成されるべきかの定義">スキーマ</dfn>を定義するためには、Marshmallowが提供する特定のユーティリティやクラスを使用する必要があります。
|
||||
|
||||
/// check | **FastAPI**へ与えたインスピレーション
|
||||
|
||||
@@ -153,9 +153,9 @@ APIが必要とするもう一つの大きな機能はデータのバリデー
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a>
|
||||
### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a> { #webargs }
|
||||
|
||||
APIに求められる他の大きな機能として、<abbr title="Pythonデータの読み込みと変換">受信したリクエストデータのパース</abbr>があります。
|
||||
APIに求められる他の大きな機能として、<dfn title="Pythonデータへの読み込みと変換">受信したリクエストデータのパース</dfn>があります。
|
||||
|
||||
WebargsはFlaskをはじめとするいくつかのフレームワークの上にそれを提供するために作られたツールです。
|
||||
|
||||
@@ -175,7 +175,7 @@ Webargsは、Marshmallowと同じ開発者により作られました。
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://apispec.readthedocs.io/en/stable/" class="external-link" target="_blank">APISpec</a>
|
||||
### <a href="https://apispec.readthedocs.io/en/stable/" class="external-link" target="_blank">APISpec</a> { #apispec }
|
||||
|
||||
MarshmallowとWebargsはバリデーション、パース、シリアライゼーションをプラグインとして提供しています。
|
||||
|
||||
@@ -205,7 +205,7 @@ OpenAPIという、APIについてのオープンな標準をサポートして
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://flask-apispec.readthedocs.io/en/latest/" class="external-link" target="_blank">Flask-apispec</a>
|
||||
### <a href="https://flask-apispec.readthedocs.io/en/latest/" class="external-link" target="_blank">Flask-apispec</a> { #flask-apispec }
|
||||
|
||||
Webargs、Marshmallow、APISpecを連携させたFlaskプラグインです。
|
||||
|
||||
@@ -237,7 +237,7 @@ Flask-apispecはMarshmallowと同じ開発者により作成されました。
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://nestjs.com/" class="external-link" target="_blank">NestJS</a> (と<a href="https://angular.io/" class="external-link" target="_blank">Angular</a>)
|
||||
### <a href="https://nestjs.com/" class="external-link" target="_blank">NestJS</a> (と<a href="https://angular.io/" class="external-link" target="_blank">Angular</a>) { #nestjs-and-angular }
|
||||
|
||||
NestJSはAngularにインスパイアされたJavaScript (TypeScript) NodeJSフレームワークで、Pythonですらありません。
|
||||
|
||||
@@ -259,13 +259,13 @@ Angular 2にインスピレーションを受けた、統合された依存性
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://sanic.readthedocs.io/en/latest/" class="external-link" target="_blank">Sanic</a>
|
||||
### <a href="https://sanic.readthedocs.io/en/latest/" class="external-link" target="_blank">Sanic</a> { #sanic }
|
||||
|
||||
`asyncio`に基づいた、Pythonのフレームワークの中でも非常に高速なものの一つです。Flaskと非常に似た作りになっています。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
Pythonの`asyncio`ループの代わりに、`uvloop`が利用されています。それにより、非常に高速です。
|
||||
Pythonの`asyncio`ループの代わりに、<a href="https://github.com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a>が利用されています。それにより、非常に高速です。
|
||||
|
||||
`Uvicorn`と`Starlette`に明らかなインスピレーションを与えており、それらは現在オープンなベンチマークにおいてSanicより高速です。
|
||||
|
||||
@@ -279,12 +279,10 @@ Pythonの`asyncio`ループの代わりに、`uvloop`が利用されています
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://falconframework.org/" class="external-link" target="_blank">Falcon</a>
|
||||
### <a href="https://falconframework.org/" class="external-link" target="_blank">Falcon</a> { #falcon }
|
||||
|
||||
Falconはもう一つの高性能Pythonフレームワークで、ミニマムに設計されており、Hugのような他のフレームワークの基盤として動作します。
|
||||
|
||||
Pythonのウェブフレームワーク標準規格 (WSGI) を使用していますが、それは同期的であるためWebSocketなどの利用には対応していません。とはいえ、それでも非常に高い性能を持っています。
|
||||
|
||||
これは、「リクエスト」と「レスポンス」の2つのパラメータを受け取る関数を持つように設計されています。そして、リクエストからデータを「読み込み」、レスポンスにデータを「書き込み」ます。この設計のため、Python標準の型ヒントでリクエストのパラメータやボディを関数の引数として宣言することはできません。
|
||||
|
||||
そのため、データのバリデーション、シリアライゼーション、ドキュメント化は、自動的にできずコードの中で行わなければなりません。あるいは、HugのようにFalconの上にフレームワークとして実装されなければなりません。このような分断は、パラメータとして1つのリクエストオブジェクトと1つのレスポンスオブジェクトを持つというFalconのデザインにインスピレーションを受けた他のフレームワークでも起こります。
|
||||
@@ -299,7 +297,7 @@ Hug (HugはFalconをベースにしています) と一緒に、**FastAPI**が`r
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://moltenframework.com/" class="external-link" target="_blank">Molten</a>
|
||||
### <a href="https://moltenframework.com/" class="external-link" target="_blank">Molten</a> { #molten }
|
||||
|
||||
**FastAPI**を構築する最初の段階でMoltenを発見しました。そして、それは非常に似たようなアイデアを持っています。
|
||||
|
||||
@@ -323,7 +321,7 @@ Pydanticのようなデータのバリデーション、シリアライゼーシ
|
||||
|
||||
///
|
||||
|
||||
### <a href="http://www.hug.rest/" class="external-link" target="_blank">Hug</a>
|
||||
### <a href="https://github.com/hugapi/hug" class="external-link" target="_blank">Hug</a> { #hug }
|
||||
|
||||
Hugは、Pythonの型ヒントを利用してAPIパラメータの型宣言を実装した最初のフレームワークの1つです。これは素晴らしいアイデアで、他のツールが同じことをするきっかけとなりました。
|
||||
|
||||
@@ -353,7 +351,7 @@ Hugは、**FastAPI**がヘッダーやクッキーを設定するために関数
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://github.com/encode/apistar" class="external-link" target="_blank">APIStar</a> (<= 0.5)
|
||||
### <a href="https://github.com/encode/apistar" class="external-link" target="_blank">APIStar</a> (<= 0.5) { #apistar-0-5 }
|
||||
|
||||
**FastAPI**を構築することを決める直前に、**APIStar**サーバーを見つけました。それは私が探していたものがほぼすべて含まれており、素晴らしいデザインでした。
|
||||
|
||||
@@ -401,9 +399,9 @@ APIStarはTom Christieにより開発されました。以下の開発者でも
|
||||
|
||||
///
|
||||
|
||||
## **FastAPI**が利用しているもの
|
||||
## **FastAPI**が利用しているもの { #used-by-fastapi }
|
||||
|
||||
### <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>
|
||||
### <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> { #pydantic }
|
||||
|
||||
Pydanticは、Pythonの型ヒントを元にデータのバリデーション、シリアライゼーション、 (JSON Schemaを使用した) ドキュメントを定義するライブラリです。
|
||||
|
||||
@@ -419,9 +417,9 @@ Marshmallowに匹敵しますが、ベンチマークではMarshmallowよりも
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>
|
||||
### <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> { #starlette }
|
||||
|
||||
Starletteは、軽量な<abbr title="非同期Python webを構築するための新標準">ASGI</abbr>フレームワーク/ツールキットで、高性能な非同期サービスの構築に最適です。
|
||||
Starletteは、軽量な<dfn title="非同期Python Webアプリケーションを構築するための新しい標準">ASGI</dfn>フレームワーク/ツールキットで、高性能な非同期サービスの構築に最適です。
|
||||
|
||||
非常にシンプルで直感的です。簡単に拡張できるように設計されており、モジュール化されたコンポーネントを持っています。
|
||||
|
||||
@@ -429,15 +427,14 @@ Starletteは、軽量な<abbr title="非同期Python webを構築するための
|
||||
|
||||
* 非常に感動的な性能。
|
||||
* WebSocketのサポート。
|
||||
* GraphQLのサポート。
|
||||
* インプロセスのバックグラウンドタスク。
|
||||
* 起動およびシャットダウンイベント。
|
||||
* requestsに基づいて構築されたテストクライアント。
|
||||
* HTTPXに基づいて構築されたテストクライアント。
|
||||
* CORS、GZip、静的ファイル、ストリーミング応答。
|
||||
* セッションとクッキーのサポート。
|
||||
* 100%のテストカバレッジ。
|
||||
* 100%の型注釈付きコードベース。
|
||||
* ハードな依存関係はない。
|
||||
* ハードな依存関係は少ない。
|
||||
|
||||
Starletteは、現在テストされているPythonフレームワークの中で最も速いフレームワークです。フレームワークではなくサーバーであるUvicornだけが上回っています。
|
||||
|
||||
@@ -465,7 +462,7 @@ webに関するコアな部分を全て扱います。その上に機能を追
|
||||
|
||||
///
|
||||
|
||||
### <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a>
|
||||
### <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a> { #uvicorn }
|
||||
|
||||
Uvicornは非常に高速なASGIサーバーで、uvloopとhttptoolsにより構成されています。
|
||||
|
||||
@@ -477,12 +474,12 @@ Starletteや**FastAPI**のサーバーとして推奨されています。
|
||||
|
||||
**FastAPI**アプリケーションを実行するメインのウェブサーバーである点。
|
||||
|
||||
Gunicornと組み合わせることで、非同期でマルチプロセスなサーバーを持つことがきます。
|
||||
コマンドラインオプション `--workers` を使って、非同期のマルチプロセスサーバーにできます。
|
||||
|
||||
詳細は[デプロイ](deployment/index.md){.internal-link target=_blank}の項目で確認してください。
|
||||
|
||||
///
|
||||
|
||||
## ベンチマーク と スピード
|
||||
## ベンチマーク と スピード { #benchmarks-and-speed }
|
||||
|
||||
Uvicorn、Starlette、FastAPIの違いを理解、比較、確認するには、[ベンチマーク](benchmarks.md){.internal-link target=_blank}を確認してください。
|
||||
|
||||
+212
-167
@@ -1,18 +1,18 @@
|
||||
# 並行処理と async / await
|
||||
# 並行処理と async / await { #concurrency-and-async-await }
|
||||
|
||||
*path operation 関数*のための `async def` に関する詳細と非同期 (asynchronous) コード、並行処理 (Concurrency)、そして、並列処理 (Parallelism) の背景について。
|
||||
*path operation 関数*のための `async def` 構文に関する詳細と、非同期コード、並行処理、並列処理の背景についてです。
|
||||
|
||||
## 急いでいますか?
|
||||
## 急いでいますか? { #in-a-hurry }
|
||||
|
||||
<abbr title="too long; didn't read (長すぎて読めない人のための要約という意味のスラング)"><strong>TL;DR:</strong></abbr>
|
||||
<abbr title="too long; didn't read - 長すぎて読まなかった"><strong>TL;DR:</strong></abbr>
|
||||
|
||||
次のような、`await` を使用して呼び出すべきサードパーティライブラリを使用している場合:
|
||||
次のように `await` で呼び出すよう指示されているサードパーティライブラリを使っているなら:
|
||||
|
||||
```Python
|
||||
results = await some_library()
|
||||
```
|
||||
|
||||
以下の様に `async def` を使用して*path operation 関数*を宣言します。
|
||||
*path operation 関数*は次のように `async def` で宣言します:
|
||||
|
||||
```Python hl_lines="2"
|
||||
@app.get('/')
|
||||
@@ -23,13 +23,13 @@ async def read_results():
|
||||
|
||||
/// note | 備考
|
||||
|
||||
`async def` を使用して作成された関数の内部でしか `await` は使用できません。
|
||||
`await` は `async def` で作られた関数の内部でしか使えません。
|
||||
|
||||
///
|
||||
|
||||
---
|
||||
|
||||
データベース、API、ファイルシステムなどと通信し、`await` の使用をサポートしていないサードパーティライブラリ (現在のほとんどのデータベースライブラリに当てはまります) を使用している場合、次の様に、単に `def` を使用して通常通り *path operation 関数* を宣言してください:
|
||||
データベース、API、ファイルシステムなどと通信しつつ `await` の使用をサポートしていないサードパーティライブラリ (現在のところ多くのデータベースライブラリが該当します) を使っている場合、*path operation 関数*は通常どおり `def` で宣言してください:
|
||||
|
||||
```Python hl_lines="2"
|
||||
@app.get('/')
|
||||
@@ -40,272 +40,307 @@ def results():
|
||||
|
||||
---
|
||||
|
||||
アプリケーションが (どういうわけか) 他の何とも通信せず、応答を待つ必要がない場合は、`async def` を使用して下さい。
|
||||
アプリケーションが (何らかの理由で) ほかの何とも通信せず応答を待つ必要がないなら、`await` を内部で使わなくても `async def` を使ってください。
|
||||
|
||||
---
|
||||
|
||||
よく分からない場合は、通常の `def` を使用して下さい。
|
||||
よく分からない場合は、通常の `def` を使ってください。
|
||||
|
||||
---
|
||||
|
||||
**備考**: *path operation 関数*に必要なだけ `def` と `async def` を混在させ、それぞれに最適なオプションを使用して定義できます。それに応じてFastAPIは正しい処理を行います。
|
||||
**備考**: 必要に応じて *path operation 関数* では `def` と `async def` を混在させ、それぞれに最適な選択肢で定義できます。FastAPI は適切に処理します。
|
||||
|
||||
とにかく、上記のいずれの場合でもFastAPIは非同期で動作し、非常に高速です。
|
||||
いずれの場合でも、FastAPI は非同期で動作し非常に高速です。
|
||||
|
||||
しかし、上記のステップに従うことで、パフォーマンスの最適化を行えます。
|
||||
ただし上記の手順に従うことで、さらにパフォーマンス最適化が可能になります。
|
||||
|
||||
## 技術詳細
|
||||
## 技術詳細 { #technical-details }
|
||||
|
||||
現代版のPythonは「**非同期コード**」を、「**コルーチン**」と称されるものを利用してサポートしています。これは **`async` と `await`** 構文を用います。
|
||||
モダンな Python は **「非同期コード」** を **「コルーチン」** と呼ばれる仕組みでサポートしており、構文は **`async` と `await`** です。
|
||||
|
||||
次のセクションで、フレーズ内のパーツを順に見ていきましょう:
|
||||
以下のセクションで、このフレーズをパーツごとに見ていきます:
|
||||
|
||||
* **非同期コード**
|
||||
* **`async` と `await`**
|
||||
* **コルーチン**
|
||||
|
||||
## 非同期コード
|
||||
## 非同期コード { #asynchronous-code }
|
||||
|
||||
非同期コードとは、言語💬がコード内のどこかで、コンピュータ/プログラム🤖に *他の何か* がどこか別の箇所で終了するのを待つように伝える手段を持っていることを意味します。*他の何か* は「遅いファイル📝」と呼ばれているとしましょう.
|
||||
非同期コードとは、言語 💬 がコードのどこかの時点で、コンピュータ/プログラム 🤖 に「どこか別のところで終わるまで、別の何か」を待つ必要があると伝える手段を持っている、ということです。その「別の何か」を「遅いファイル」📝 と呼ぶことにしましょう。
|
||||
|
||||
したがって、コンピュータは「遅いファイル📝」が終了するまで、他の処理ができます。
|
||||
その間、コンピュータは「遅いファイル」📝 が終わるまで、他の作業を進められます。
|
||||
|
||||
コンピュータ/プログラム🤖は再び待機する機会があるときや、その時点で行っていたすべての作業が完了するたびに戻ってきます。そして、必要な処理をしながら、コンピュータ/プログラム🤖が待っていた処理のどれかが終わっているかどうか確認します。
|
||||
その後、コンピュータ/プログラム 🤖 は、また待つ機会が来たときや、その時点で抱えていた作業をすべて終えたときに戻ってきます。そして、待っていたタスクのどれかが終わっていないか確認し、必要な処理を実行します。
|
||||
|
||||
次に、それ🤖が最初のタスク (要するに、先程の「遅いファイル📝」)を終わらせて、そのタスクの結果を使う必要がある処理を続けます。
|
||||
次に、最初に終わったタスク (たとえば「遅いファイル」📝) を取り、続きの処理を行います。
|
||||
|
||||
この「他の何かを待つ」とは、通常以下の様なものを待つような (プロセッサとRAMメモリの速度に比べて) 相対的に「遅い」<abbr title="インプットとアウトプット">I/O</abbr> 操作を指します:
|
||||
この「別の何かを待つ」は、通常 <abbr title="Input and Output - 入出力">I/O</abbr> 操作を指し、(プロセッサや RAM の速度に比べて) 相対的に「遅い」待機を伴います。例えば次のようなものです:
|
||||
|
||||
* ネットワーク経由でクライアントから送信されるデータ
|
||||
* ネットワーク経由でクライアントが受信する、プログラムから送信されたデータ
|
||||
* システムによって読み取られ、プログラムに渡されるディスク内のファイル内容
|
||||
* プログラムがシステムに渡して、ディスクに書き込む内容
|
||||
* リモートAPI操作
|
||||
* クライアントからネットワーク経由でデータが送られてくるのを待つ
|
||||
* プログラムが送信したデータをクライアントがネットワーク経由で受け取るのを待つ
|
||||
* ディスク上のファイル内容がシステムにより読み取られ、プログラムに渡されるのを待つ
|
||||
* プログラムがシステムに渡した内容がディスクに書き込まれるのを待つ
|
||||
* リモート API 操作
|
||||
* データベース操作の完了
|
||||
* データベースクエリが結果を返すこと
|
||||
* など。
|
||||
* データベースクエリが結果を返すのを待つ
|
||||
* など
|
||||
|
||||
実行時間のほとんどが<abbr title="インプットとアウトプット">I/O</abbr> 操作の待ち時間が占めるため、このような操作を「I/O バウンド」操作と言います。
|
||||
実行時間の大半が <abbr title="Input and Output - 入出力">I/O</abbr> 操作の待ち時間に費やされるため、これらは「I/O バウンド」な操作と呼ばれます。
|
||||
|
||||
コンピュータ/プログラムがこのような遅いタスクと「同期 (タスクの結果を取得して作業を続行するために、何もせずに、タスクが完了する瞬間を正確に待つ)」する必要がないため、「非同期」と呼ばれます。
|
||||
「非同期」と呼ばれるのは、コンピュータ/プログラムがその遅いタスクと「同期」(タスクがちょうど終わる瞬間を、何もせずに待つ) する必要がないからです。結果を受け取って処理を続けるために、空待ちする必要がありません。
|
||||
|
||||
その代わりに、「非同期」システムであることにより、いったん終了すると、タスクは、コンピュータ/プログラムが既に開始した処理がすべて完了するのをほんの少し (数マイクロ秒) 待って、結果を受け取りに戻ってきます。そして、処理を継続します。
|
||||
代わりに「非同期」システムでは、タスクが終わったら、コンピュータ/プログラムが取りかかっている作業が終わるまで (数マイクロ秒ほど) 少し待ち、結果を受け取りに戻って処理を続けられます。
|
||||
|
||||
「同期」の場合 (「非同期」とは異なり)、「シーケンシャル」という用語もよく使用されます。これは、コンピュータ/プログラムがすべてのステップを (待機が伴う場合でも別のタスクに切り替えることなく) 順番に実行するためです。
|
||||
「非同期」と対になる「同期」は、「シーケンシャル」と呼ばれることもあります。待機が含まれていても、別のタスクに切り替える前にコンピュータ/プログラムが手順を順番に実行するためです。
|
||||
|
||||
### 並行処理とハンバーガー
|
||||
### 並行処理とハンバーガー { #concurrency-and-burgers }
|
||||
|
||||
上記の**非同期**コードのアイデアは、**「並行処理」**と呼ばれることもあります。 **「並列処理」**とは異なります。
|
||||
上で説明した**非同期**コードの考え方は、**「並行処理」** と呼ばれることもあります。これは **「並列処理」** とは異なります。
|
||||
|
||||
**並行処理**と**並列処理**はどちらも「多かれ少なかれ同時に発生するさまざまなこと」に関連しています。
|
||||
**並行処理** も **並列処理** も、「複数のことがだいたい同時に起きる」ことに関係します。
|
||||
|
||||
ただし、*並行処理*と*並列処理*の詳細はまったく異なります。
|
||||
ただし、*並行処理* と *並列処理* の詳細はかなり異なります。
|
||||
|
||||
違いを確認するには、ハンバーガーに関する次の物語を想像してみてください:
|
||||
違いを見るために、ハンバーガーに関する次の物語を想像してみてください。
|
||||
|
||||
### 並行ハンバーガー
|
||||
### 並行ハンバーガー { #concurrent-burgers }
|
||||
|
||||
ファストフード🍔を食べようと、好きな人😍とレジに並んでおり、レジ係💁があなたの前にいる人達の注文を受けつけています。
|
||||
あなたは好きな人とファストフードを買いに行き、前の人たちの注文をレジ係が受ける間、列に並びます。😍
|
||||
|
||||
それからあなたの番になり、好きな人😍と自分のために、2つの非常に豪華なハンバーガー🍔を注文します。
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
|
||||
|
||||
料金を支払います💸。
|
||||
やがてあなたの番になり、好きな人と自分のために、とても豪華なハンバーガーを2つ注文します。🍔🍔
|
||||
|
||||
レジ係💁はキッチンの男👨🍳に向かって、あなたのハンバーガー🍔を準備しなければならないと伝えるために何か言いました (彼は現在、前のお客さんの商品を準備していますが)。
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
|
||||
|
||||
レジ係💁はあなたに番号札を渡します。
|
||||
レジ係はキッチンの料理人に、あなたのハンバーガーを用意するよう声をかけます (料理人はいま前のお客さんの分を作っています)。
|
||||
|
||||
待っている間、好きな人😍と一緒にテーブルを選んで座り、好きな人😍と長い間話をします (注文したハンバーガーは非常に豪華で、準備に少し時間がかかるので✨🍔✨)。
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
|
||||
|
||||
ハンバーガー🍔を待ちながら好きな人😍とテーブルに座っている間、あなたの好きな人がなんて素晴らしく、かわいくて頭がいいんだと✨😍✨惚れ惚れしながら時間を費やすことができます。
|
||||
支払いをします。💸
|
||||
|
||||
好きな人😍と話しながら待っている間、ときどき、カウンターに表示されている番号をチェックして、自分の番かどうかを確認します。
|
||||
レジ係はあなたに番号札を渡します。
|
||||
|
||||
その後、ついにあなたの番になりました。カウンターに行き、ハンバーガー🍔を手に入れてテーブルに戻ります。
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-04.png" class="illustration">
|
||||
|
||||
あなたとあなたの好きな人😍はハンバーガー🍔を食べて、楽しい時間を過ごします✨。
|
||||
待っている間、好きな人とテーブルに移動して座り、(豪華なハンバーガーは時間がかかるので) しばらく話します。
|
||||
|
||||
テーブルで待っている間、好きな人がどれだけ素敵で、かわいくて、頭が良いかを眺めて時間を過ごせます ✨😍✨。
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
|
||||
|
||||
時々カウンターの表示を見て、自分の番号になっているか確認します。
|
||||
|
||||
やがてあなたの番になります。カウンターに行き、ハンバーガーを受け取り、テーブルに戻ります。
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
|
||||
|
||||
あなたと好きな人はハンバーガーを食べて、楽しい時間を過ごします。✨
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
|
||||
|
||||
/// info | 情報
|
||||
|
||||
美しいイラストは <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a> によるものです。🎨
|
||||
|
||||
///
|
||||
|
||||
---
|
||||
|
||||
上記のストーリーで、あなたがコンピュータ/プログラム🤖だと想像してみてください。
|
||||
この物語で、あなた自身がコンピュータ/プログラム 🤖 だと想像してみてください。
|
||||
|
||||
列にいる間、あなたはアイドル状態です😴。何も「生産的」なことをせず、ただ自分の番を待っています。しかし、レジ係💁は注文を受け取るだけなので (商品の準備をしているわけではない)、列は高速です。したがって、何も問題ありません。
|
||||
列にいる間は、何も「生産的」なことをせず、自分の番を待つだけのアイドル状態 😴 です。ただしレジ係は注文を取るだけ (作りはしない) なので列は速く進み、問題ありません。
|
||||
|
||||
それから、あなたの番になったら、実に「生産的な」作業を行います🤓、メニューを確認し、欲しいものを決め、好きな人😍の欲しいものを聞き、料金を支払い💸、現金またはカードを正しく渡したか確認し、正しく清算されたことを確認し、注文が正しく通っているかなどを確認します。
|
||||
あなたの番になると、実際に「生産的」な作業をします。メニューを見て注文を決め、好きな人の分も確認し、支払い、正しい紙幣/カードを渡したか、正しく決済されたか、注文内容が正しいかなどを確認します。
|
||||
|
||||
しかし、ハンバーガー🍔をまだできていないので、ハンバーガーの準備ができるまで待機🕙する必要があるため、レジ係💁との作業は「一時停止⏸」になります。
|
||||
しかし、ハンバーガーはまだ出来上がっていないので、レジ係とのやり取りは「一時停止」⏸ になります。ハンバーガーができるまで待つ 🕙 必要があるからです。
|
||||
|
||||
しかし、カウンターから離れて、番号札を持ってテーブルに座っているときは、注意を好きな人😍に切り替えて🔀、その上で「仕事⏯🤓」を行なえます。その後、好きな人😍といちゃつくかのような、非常に「生産的な🤓」ことを再び行います。
|
||||
ただし、番号札を持ってカウンターから離れテーブルに座れば、注意を好きな人に切り替え 🔀、「その作業」⏯ 🤓 に取り組めます。好きな人といちゃつくという、とても「生産的」🤓 なことがまたできます。
|
||||
|
||||
次に、レジ係💁は、「ハンバーガーの準備ができました🍔」と言って、カウンターのディスプレイに番号を表示しますが、表示番号があなたの番号に変わっても、すぐに狂ったように飛んで行くようなことはありません。あなたは自分の番号札を持っていって、他の人も自分の番号札があるので、あなたのハンバーガー🍔を盗む人がいないことは知っています。
|
||||
レジ係 💁 がカウンターの表示にあなたの番号を出して「ハンバーガーができました」と知らせても、あなたは表示が切り替わった瞬間に飛び跳ねたりしません。自分の番号札があり、他の人にもそれぞれ番号札があるので、ハンバーガーを盗られることはないと知っているからです。
|
||||
|
||||
なので、あなたは好きな人😍が話し終えるのを待って (現在の仕事⏯ / 処理中のタスクを終了します🤓)、優しく微笑んで、ハンバーガーを貰ってくるねと言います⏸。
|
||||
だから、好きな人の話が終わるのを待ち (現在の作業 ⏯ / 処理中のタスクを完了し 🤓)、微笑んで「ハンバーガー取ってくるね」と言います ⏸。
|
||||
|
||||
次に、カウンターへ、いまから完了する最初のタスク⏯へ向かい、ハンバーガー🍔を受け取り、感謝の意を表して、テーブルに持っていきます。これで、カウンターとのやり取りのステップ/タスクが完了しました⏹。これにより、「ハンバーガーを食べる🔀⏯」という新しいタスクが作成されます。しかし、前の「ハンバーガーを取得する」というタスクは終了しました⏹。
|
||||
それからカウンターへ行き 🔀、いま完了した初期のタスク ⏯ に戻って、ハンバーガーを受け取り、礼を言ってテーブルに持っていきます。これでカウンターとのやり取りというステップ/タスクは完了 ⏹ です。その結果として「ハンバーガーを食べる」🔀 ⏯ という新しいタスクが生まれますが、先の「ハンバーガーを受け取る」タスクは完了 ⏹ しています。
|
||||
|
||||
### 並列ハンバーガー
|
||||
### 並列ハンバーガー { #parallel-burgers }
|
||||
|
||||
これらが「並行ハンバーガー」ではなく、「並列ハンバーガー」であるとしましょう。
|
||||
今度は、これが「並行ハンバーガー」ではなく「並列ハンバーガー」だと想像しましょう。
|
||||
|
||||
あなたは好きな人😍と並列ファストフード🍔を買おうとしています。
|
||||
あなたは好きな人と「並列」ファストフードを買いに行きます。
|
||||
|
||||
列に並んでいますが、何人かの料理人兼、レジ係 (8人としましょう) 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳があなたの前にいる人達の注文を受けつけています。
|
||||
複数のレジ係 (例えば 8 人) が同時に料理人でもあり、前の人たちの注文を受けています。
|
||||
|
||||
8人のレジ係がそれぞれ自分で注文を受けるや否や、次の注文を受ける前にハンバーガーを準備するので、あなたの前の人達はカウンターを離れずに、ハンバーガー🍔ができるのを待っています🕙。
|
||||
8 人のレジ係はそれぞれ、次の注文を取る前にすぐに調理に取りかかるため、あなたの前の人たちはカウンターを離れず、ハンバーガーができるのを待っています。
|
||||
|
||||
それからいよいよあなたの番になり、好きな人😍と自分のために、2つの非常に豪華なハンバーガー🍔を注文します。
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
|
||||
|
||||
料金を支払います💸。
|
||||
ようやくあなたの番になり、好きな人と自分のために豪華なハンバーガーを 2 つ注文します。
|
||||
|
||||
レジ係はキッチンに行きます👨🍳。
|
||||
支払いをします 💸。
|
||||
|
||||
あなたはカウンターの前に立って待ちます🕙。番号札がないので誰もあなたよりも先にハンバーガー🍔を取らないようにします。
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
|
||||
|
||||
あなたと好きな人😍は忙しいので、誰もあなたの前に来させませんし、あなたのハンバーガーが到着したとき🕙に誰にも取ることを許しません。あなたは好きな人に注意を払えません😞。
|
||||
レジ係はキッチンに向かいます。
|
||||
|
||||
これは「同期」作業であり、レジ係/料理人👨🍳と「同期」します。レジ係/料理人👨🍳がハンバーガー🍔を完成させてあなたに渡すまで待つ🕙必要があり、ちょうどその完成の瞬間にそこにいる必要があります。そうでなければ、他の誰かに取られるかもしれません。
|
||||
番号札がないため、他の誰かに先に取られないよう、カウンターの前で立って待ちます 🕙。
|
||||
|
||||
その後、カウンターの前で長い時間待ってから🕙、ついにレジ係/料理人👨🍳がハンバーガー🍔を渡しに戻ってきます。
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
|
||||
|
||||
ハンバーガー🍔を取り、好きな人😍とテーブルに行きます。
|
||||
あなたと好きな人は、誰にも割り込まれずハンバーガーが来たらすぐ受け取れるよう見張っているので、好きな人に注意を向けられません。😞
|
||||
|
||||
ただ食べるだけ、それでおしまいです。🍔⏹。
|
||||
これは「同期」的な作業です。レジ係/料理人 👨🍳 と「同期」しています。レジ係/料理人 👨🍳 がハンバーガーを作り終えて手渡すその瞬間に、待って 🕙 その場にいなければなりません。そうでないと他の誰かに取られるかもしれません。
|
||||
|
||||
ほとんどの時間、カウンターの前で待つのに費やされていたので🕙、あまり話したりいちゃつくことはありませんでした😞。
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
|
||||
|
||||
長い時間 🕙 カウンター前で待った後、ようやくレジ係/料理人 👨🍳 がハンバーガーを持って戻ってきます。
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
|
||||
|
||||
ハンバーガーを受け取り、好きな人とテーブルに行きます。
|
||||
|
||||
食べて、おしまいです。⏹
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
|
||||
|
||||
ほとんどの時間をカウンター前で待つ 🕙 のに費やしたため、あまり話したり、いちゃついたりできませんでした。😞
|
||||
|
||||
/// info | 情報
|
||||
|
||||
美しいイラストは <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a> によるものです。🎨
|
||||
|
||||
///
|
||||
|
||||
---
|
||||
|
||||
この並列ハンバーガーのシナリオでは、あなたは2つのプロセッサを備えたコンピュータ/プログラム🤖 (あなたとあなたの好きな人😍) であり、両方とも待機🕙していて、彼らは「カウンターで待機🕙」することに専念しています⏯。
|
||||
この「並列ハンバーガー」のシナリオでは、あなたは 2 つのプロセッサ (あなたと好きな人) を持つコンピュータ/プログラム 🤖 で、どちらも長い間 🕙「カウンターでの待機」に注意 ⏯ を専念しています。
|
||||
|
||||
ファストフード店には8つのプロセッサ (レジ係/料理人) 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳があります。一方、並行ハンバーガー店には2人 (レジ係と料理人) 💁👨🍳しかいなかったかもしれません。
|
||||
ファストフード店には 8 個のプロセッサ (レジ係/料理人) があります。一方、並行ハンバーガーの店には (レジ係 1、人、料理人 1 人の) 2 個しかなかったかもしれません。
|
||||
|
||||
しかし、それでも、最終的な体験は最高ではありません😞。
|
||||
それでも、最終的な体験は最良とは言えません。😞
|
||||
|
||||
---
|
||||
|
||||
これは、ハンバーガー🍔の話と同等な話になります。
|
||||
これはハンバーガーにおける並列版の物語です。🍔
|
||||
|
||||
より「現実的な」例として、銀行を想像してみてください。
|
||||
|
||||
最近まで、ほとんどの銀行は複数の窓口👨💼👨💼👨💼👨💼に、行列🕙🕙🕙🕙🕙🕙🕙🕙ができていました。
|
||||
つい最近まで、ほとんどの銀行には複数の窓口係 👨💼👨💼👨💼👨💼 と長い行列 🕙🕙🕙🕙🕙🕙🕙🕙 がありました。
|
||||
|
||||
すべての窓口で、次々と、一人の客とすべての作業を行います👨💼⏯.
|
||||
各窓口係が、一人ずつ、すべての作業を順番に行います 👨💼⏯。
|
||||
|
||||
その上、長時間、列に並ばなければいけません🕙。そうしないと、順番が回ってきません。
|
||||
そして、長時間 🕙 行列で待たなければ順番を失います。
|
||||
|
||||
銀行🏦での用事にあなたの好きな人😍を連れて行きたくはないでしょう。
|
||||
銀行の用事 🏦 に、好きな人 😍 を連れて行きたいとは思わないでしょう。
|
||||
|
||||
### ハンバーガーのまとめ
|
||||
### ハンバーガーのまとめ { #burger-conclusion }
|
||||
|
||||
この「好きな人とのファストフードハンバーガー」のシナリオでは、待機🕙が多いため、並行システム⏸🔀⏯を使用する方がはるかに理にかなっています。
|
||||
この「好きな人とファストフード」のシナリオでは、待ち時間 🕙 が多いため、並行システム ⏸🔀⏯ を使う方がはるかに理にかなっています。
|
||||
|
||||
これは、ほとんどのWebアプリケーションに当てはまります。
|
||||
これは、ほとんどの Web アプリケーションにも当てはまります。
|
||||
|
||||
多くのユーザーがいますが、サーバーは、あまり強くない回線でのリクエストの送信を待機🕙しています。
|
||||
とても多くのユーザーがいますが、サーバは彼らのあまり速くない回線からリクエストが届くのを待ち 🕙、
|
||||
|
||||
そして、レスポンスが返ってくるのをもう一度待機🕙します。
|
||||
その後、レスポンスが戻ってくるのをまた待ちます 🕙。
|
||||
|
||||
この「待機🕙」はマイクロ秒単位ですが、それでも、すべて合算すると、最終的にはかなり待機することになります。
|
||||
この「待ち」🕙 はマイクロ秒単位で測られますが、すべてを合計すると、結局かなりの待ちになります。
|
||||
|
||||
これが、Web APIへの非同期⏸🔀⏯コードの利用が理にかなっている理由です。
|
||||
だからこそ、Web API には非同期 ⏸🔀⏯ コードを使うのが理にかなっています。
|
||||
|
||||
ほとんどの既存の人気のあるPythonフレームワーク (FlaskやDjangoを含む) は、Pythonの新しい非同期機能ができる前に作成されました。したがって、それらをデプロイする方法は、並列実行と、新機能ほど強力ではない古い形式の非同期実行をサポートします。
|
||||
これが、NodeJS を人気にした要因 (NodeJS 自体は並列ではありません) であり、プログラミング言語としての Go の強みでもあります。
|
||||
|
||||
しかし、WebSocketのサポートを追加するために、非同期Web Python (ASGI) の主な仕様はDjangoで開発されました。
|
||||
そして、それが **FastAPI** で得られるパフォーマンスの水準です。
|
||||
|
||||
そのような非同期性がNodeJSを人気にした理由です (NodeJSは並列ではありませんが)。そして、プログラミング言語としてのGoの強みでもあります。
|
||||
さらに、並列性と非同期性を同時に活用できるため、テストされた多くの NodeJS フレームワークより高い性能を発揮し、C に近いコンパイル言語である Go と同等の性能になります <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(すべて Starlette のおかげです)</a>。
|
||||
|
||||
そして、それは**FastAPI**で得られるパフォーマンスと同じレベルです。
|
||||
### 並行処理は並列処理より優れている? { #is-concurrency-better-than-parallelism }
|
||||
|
||||
また、並列処理と非同期処理を同時に実行できるため、テスト済みのほとんどのNodeJSフレームワークよりも高く、Goと同等のパフォーマンスが得られます。Goは、Cに近いコンパイル言語です <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(Starletteに感謝します)</a>。
|
||||
いいえ!それがこの話の教訓ではありません。
|
||||
|
||||
### 並行は並列よりも優れていますか?
|
||||
並行処理は並列処理とは異なります。そして多くの待ち時間を伴う**特定の**シナリオでは優れています。そのため、一般に Web アプリ開発では並列処理よりはるかに適しています。しかし、すべてに対して最良というわけではありません。
|
||||
|
||||
いや!それはこの話の教訓ではありません。
|
||||
バランスを取るために、次の短い物語を想像してください。
|
||||
|
||||
並行処理は並列処理とは異なります。多くの待機を伴う**特定の**シナリオに適しています。そのため、一般に、Webアプリケーション開発では並列処理よりもはるかに優れています。しかし、すべてに対してより良いというわけではありません。
|
||||
> 大きくて汚れた家を掃除しなければならない。
|
||||
|
||||
なので、バランスをとるために、次の物語を想像して下さい:
|
||||
|
||||
> あなたは大きくて汚れた家を掃除する必要があります。
|
||||
|
||||
*はい、以上です*。
|
||||
*はい、これで物語は全部です*。
|
||||
|
||||
---
|
||||
|
||||
待機🕙せず、家の中の複数の場所でたくさんの仕事をするだけです。
|
||||
どこにも待ち 🕙 はなく、家の複数箇所で大量の作業があるだけです。
|
||||
|
||||
あなたはハンバーガーの例のように、最初はリビングルーム、次にキッチンのように順番にやっていくことができますが、何かを待機🕙しているわけではなく、ただひたすらに掃除をするだけで、順番は何にも影響しません。
|
||||
ハンバーガーの例のように順番を決めて、まずリビング、次にキッチン、と進めてもよいのですが、何かを待つ 🕙 わけではなく、ひたすら掃除するだけなので、順番は何も影響しません。
|
||||
|
||||
順番の有無に関係なく (並行に) 同じ時間がかかり、同じ量の作業が行われることになるでしょう。
|
||||
順番の有無 (並行性の有無) に関係なく、終了までに同じ時間がかかり、同じ作業量をこなすことになります。
|
||||
|
||||
しかし、この場合、8人の元レジ係/料理人/現役清掃員👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳を手配できて、それぞれ (さらにあなたも) が家の別々の場所を掃除できれば、追加の助けを借りて、すべての作業を**並列**に行い、はるかに早く終了できるでしょう。
|
||||
しかしこの場合、8 人の元レジ係/料理人/現清掃員を連れてきて、それぞれ (あなたも加えて) 家の別々のエリアを掃除できれば、**並列** に作業でき、より早く終えられます。
|
||||
|
||||
このシナリオでは、清掃員 (あなたを含む) のそれぞれがプロセッサとなり、それぞれの役割を果たします。
|
||||
このシナリオでは、各清掃員 (あなたを含む) がプロセッサであり、それぞれが自分の役割を果たします。
|
||||
|
||||
また、実行時間のほとんどは (待機ではなく) 実際の作業に費やされ、コンピュータでの作業は<abbr title="Central Processing Unit">CPU</abbr>によって行われます。これらの問題は「CPUバウンド」と言います。
|
||||
そして実行時間の大半は (待ちではなく) 実作業が占め、コンピュータでの作業は <abbr title="Central Processing Unit - 中央処理装置">CPU</abbr> によって行われます。これらの問題は「CPU バウンド」と呼ばれます。
|
||||
|
||||
---
|
||||
|
||||
CPUバウンド操作の一般的な例は、複雑な数学処理が必要なものです。
|
||||
CPU バウンドな操作の一般的な例は、複雑な数値処理が必要なものです。
|
||||
|
||||
例えば:
|
||||
|
||||
* **オーディオ** や **画像処理**。
|
||||
* **コンピュータビジョン**: 画像は数百万のピクセルで構成され、各ピクセルには3つの値/色があり、通常、これらのピクセルで何かを同時に計算する必要がある処理。
|
||||
* **機械学習**: 通常、多くの「行列」と「ベクトル」の乗算が必要です。巨大なスプレッドシートに数字を入れて、それを同時に全部掛け合わせることを考えてみてください。
|
||||
* **ディープラーニング**: これは機械学習のサブフィールドであるため、同じことが当てはまります。乗算する数字がある単一のスプレッドシートではなく、それらの膨大な集合で、多くの場合、それらのモデルを構築および/または使用するために特別なプロセッサを使用します。
|
||||
* **コンピュータビジョン**: 画像は数百万のピクセルで構成され、各ピクセルには 3 つの値/色があり、通常、それらのピクセル上で同時に何かを計算する必要があります。
|
||||
* **機械学習**: 多くの「行列」や「ベクトル」の乗算が必要になります。巨大なスプレッドシートに数字が入っていて、それらを同時にすべて掛け合わせることを想像してください。
|
||||
* **ディープラーニング**: 機械学習のサブフィールドなので同様です。掛け合わせる数字が 1 つのスプレッドシートではなく膨大な集合であり、多くの場合、それらのモデルを構築/利用するための特別なプロセッサを使います。
|
||||
|
||||
### 並行処理 + 並列処理: Web + 機械学習
|
||||
### 並行処理 + 並列処理: Web + 機械学習 { #concurrency-parallelism-web-machine-learning }
|
||||
|
||||
**FastAPI**を使用すると、Web開発で非常に一般的な並行処理 (NodeJSの主な魅力と同じもの) を利用できます。
|
||||
**FastAPI** では、Web 開発で非常に一般的な並行処理 (NodeJS の主な魅力と同じ) を活用できます。
|
||||
|
||||
ただし、機械学習システムのような **CPUバウンド** ワークロードに対して、並列処理とマルチプロセッシング (複数のプロセスが並列で実行される) の利点を活用することもできます。
|
||||
同時に、機械学習システムのような **CPU バウンド** なワークロードに対して、並列処理やマルチプロセッシング (複数プロセスの並列実行) の利点も活用できます。
|
||||
|
||||
さらに、Pythonが**データサイエンス**、機械学習、特にディープラーニングの主要言語であるという単純な事実により、FastAPIはデータサイエンス/機械学習のWeb APIおよびアプリケーション (他の多くのアプリケーションとの) に非常によく適合しています。
|
||||
さらに、Python が **データサイエンス**、機械学習、特にディープラーニングの主要言語であるという事実も相まって、FastAPI はデータサイエンス/機械学習の Web API やアプリケーション (ほか多数) に非常に適しています。
|
||||
|
||||
本番環境でこの並列処理を実現する方法については、[デプロイ](deployment/index.md){.internal-link target=_blank}に関するセクションを参照してください。
|
||||
本番環境でこの並列性を実現する方法は、[デプロイ](deployment/index.md){.internal-link target=_blank} のセクションを参照してください。
|
||||
|
||||
## `async` と `await`
|
||||
## `async` と `await` { #async-and-await }
|
||||
|
||||
現代的なバージョンのPythonには、非同期コードを定義する非常に直感的な方法があります。これにより、通常の「シーケンシャル」コードのように見え、適切なタイミングで「待機」します。
|
||||
モダンな Python には、非同期コードをとても直感的に定義する方法があります。これにより、通常の「シーケンシャル」なコードのように書けて、適切なタイミングで「待ち」を行ってくれます。
|
||||
|
||||
結果を返す前に待機する必要があり、これらの新しいPython機能をサポートする操作がある場合は、次のようにコーディングできます。
|
||||
結果を返す前に待ちが必要で、これらの新しい Python 機能をサポートしている操作がある場合、次のように書けます。
|
||||
|
||||
```Python
|
||||
burgers = await get_burgers(2)
|
||||
```
|
||||
|
||||
カギは `await` です。結果を `burgers`に保存する前に、`get_burgers(2)`の処理🕙の完了を待つ⏸必要があることをPythonに伝えます。これでPythonは、その間に (別のリクエストを受信するなど) 何か他のことができる🔀⏯ことを知ります。
|
||||
ここでの鍵は `await` です。`burgers` に結果を保存する前に、`get_burgers(2)` がやるべきことを終えるのを ⏸ 待つ 🕙 ように Python に伝えます。これにより Python は、その間に (別のリクエストを受け取るなど) ほかのことを 🔀 ⏯ できると分かります。
|
||||
|
||||
`await` が機能するためには、非同期処理をサポートする関数内にある必要があります。これは、`async def` で関数を宣言するだけでよいです:
|
||||
`await` が機能するには、この非同期性をサポートする関数の内部でなければなりません。そのためには `async def` で宣言します:
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def get_burgers(number: int):
|
||||
# ハンバーガーを作成するために非同期処理を実行
|
||||
# ハンバーガーを作るために非同期の処理を行う
|
||||
return burgers
|
||||
```
|
||||
|
||||
...`def` のかわりに:
|
||||
...`def` の代わりに:
|
||||
|
||||
```Python hl_lines="2"
|
||||
# 非同期ではない
|
||||
# これは非同期ではない
|
||||
def get_sequential_burgers(number: int):
|
||||
# ハンバーガーを作成するためにシーケンシャルな処理を実行
|
||||
# ハンバーガーを作るためにシーケンシャルな処理を行う
|
||||
return burgers
|
||||
```
|
||||
`async def` を使用すると、Pythonにその関数内で `await` 式 (その関数の実行を「一時停止⏸」し、結果が戻るまで他の何かを実行🔀する) を認識しなければならないと伝えることができます。
|
||||
|
||||
`async def` 関数を呼び出すときは、「await」しなければなりません。したがって、これは機能しません:
|
||||
`async def` を使うと、Python はその関数内で `await` 式に注意し、関数の実行を「一時停止」⏸ してほかのことをしに行き 🔀、戻ってくることができると分かります。
|
||||
|
||||
`async def` な関数を呼ぶときは「await」しなければなりません。したがって、次は動きません:
|
||||
|
||||
```Python
|
||||
# get_burgersはasync defで定義されているので動作しない
|
||||
# 動きません。get_burgers は async def で定義されています
|
||||
burgers = get_burgers(2)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
したがって、 `await` で呼び出すことができるライブラリを使用している場合は、次のように `async def` を使用して、それを使用する*path operation 関数*を作成する必要があります:
|
||||
そのため、`await` で呼べると謳っているライブラリを使っている場合は、それを使う *path operation 関数* を `async def` で作る必要があります。例えば:
|
||||
|
||||
```Python hl_lines="2-3"
|
||||
@app.get('/burgers')
|
||||
@@ -314,86 +349,96 @@ async def read_burgers():
|
||||
return burgers
|
||||
```
|
||||
|
||||
### より発展的な技術詳細
|
||||
### より発展的な技術詳細 { #more-technical-details }
|
||||
|
||||
`await` は `async def` で定義された関数内でのみ使用できることがわかったかと思います。
|
||||
`await` は `async def` で定義された関数の内部でしか使えないことに気づいたかもしれません。
|
||||
|
||||
しかし同時に、`async def` で定義された関数は「awaitされる」必要があります。なので、`async def` を持つ関数は、`async def` で定義された関数内でのみ呼び出せます。
|
||||
同時に、`async def` で定義された関数は「await」される必要があります。つまり、`async def` を持つ関数は、やはり `async def` で定義された関数の内部からしか呼べません。
|
||||
|
||||
では、このニワトリと卵の問題について、最初の `async` 関数をどのように呼び出すのでしょうか?
|
||||
では、ニワトリと卵の話のように、最初の `async` 関数はどう呼ぶのでしょうか?
|
||||
|
||||
**FastAPI**を使用している場合、その「最初の」関数が*path operation 関数*であり、FastAPIが正しく実行する方法を知っているので、心配する必要はありません。
|
||||
**FastAPI** を使っている場合は心配ありません。その「最初の」関数は *path operation 関数* で、FastAPI が適切に実行してくれます。
|
||||
|
||||
しかし、FastAPI以外で `async` / `await` を使用したい場合は、<a href="https://docs.python.org/3/library/asyncio-task.html#coroutine" class="external-link" target="_blank">公式Pythonドキュメントを参照して下さい</a>。
|
||||
しかし、FastAPI を使わずに `async` / `await` を使いたい場合もあります。
|
||||
|
||||
### 非同期コードの他の形式
|
||||
### 自分で async コードを書く { #write-your-own-async-code }
|
||||
|
||||
`async` と `await` を使用するスタイルは、この言語では比較的新しいものです。
|
||||
Starlette (**FastAPI** も) は <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> の上に構築されており、標準ライブラリの <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> と <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a> の両方に対応しています。
|
||||
|
||||
非同期コードの操作がはるかに簡単になります。
|
||||
特に、あなた自身のコード内で、より高度なパターンを必要とする発展的な並行処理のユースケースに対して、<a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> を直接使えます。
|
||||
|
||||
等価な (またはほとんど同一の) 構文が、最近のバージョンのJavaScript (ブラウザおよびNodeJS) にも最近組み込まれました。
|
||||
仮に FastAPI を使っていなくても、<a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> で独自の async アプリケーションを書けば、高い互換性と利点 (例: 構造化並行性) を得られます。
|
||||
|
||||
しかし、その前は、非同期コードの処理はかなり複雑で難解でした。
|
||||
私は AnyIO の上に薄い層として、型注釈を少し改善し、より良い**補完**や**インラインエラー**などを得るための別ライブラリも作りました。また、**理解**して**自分で async コードを書く**のに役立つフレンドリーなイントロ/チュートリアルもあります: <a href="https://asyncer.tiangolo.com/" class="external-link" target="_blank">Asyncer</a>。特に、**async コードと通常の** (ブロッキング/同期) **コードを組み合わせる**必要がある場合に有用です。
|
||||
|
||||
以前のバージョンのPythonでは、スレッドや<a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>が利用できました。しかし、コードは理解、デバック、そして、考察がはるかに複雑です。
|
||||
### 非同期コードの他の形式 { #other-forms-of-asynchronous-code }
|
||||
|
||||
以前のバージョンのNodeJS / ブラウザJavaScriptでは、「コールバック」を使用していました。これは、「コールバック地獄」につながります。
|
||||
`async` と `await` を使うこのスタイルは、言語としては比較的新しいものです。
|
||||
|
||||
## コルーチン
|
||||
しかし、これにより非同期コードの取り扱いは大幅に簡単になります。
|
||||
|
||||
**コルーチン**は、`async def` 関数によって返されるものを指す非常に洒落た用語です。これは、開始できて、いつか終了する関数のようなものであるが、内部に `await` があるときは内部的に一時停止⏸されることもあるものだとPythonは認識しています。
|
||||
同等 (ほぼ同一) の構文が最近の JavaScript (ブラウザと NodeJS) にも導入されました。
|
||||
|
||||
`async` と `await` を用いた非同期コードを使用するすべての機能は、「コルーチン」を使用するものとして何度もまとめられています。Goの主要機能である「ゴルーチン」に相当します。
|
||||
それ以前は、非同期コードの扱いはかなり複雑で難解でした。
|
||||
|
||||
## まとめ
|
||||
以前の Python ではスレッドや <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a> を使えましたが、コードの理解・デバッグ・思考がはるかに難しくなります。
|
||||
|
||||
上述したフレーズを見てみましょう:
|
||||
以前の NodeJS / ブラウザ JavaScript では「コールバック」を使っており、「コールバック地獄」を招きました。
|
||||
|
||||
> 現代版のPythonは「**非同期コード**」を、「**コルーチン**」と称されるものを利用してサポートしています。これは **`async` と `await`** 構文を用います。
|
||||
## コルーチン { #coroutines }
|
||||
|
||||
今では、この意味がより理解できるはずです。✨
|
||||
**コルーチン**は、`async def` 関数が返すものを指す、ちょっと洒落た用語です。Python はそれを、開始できていつか終了する関数のようなものとして扱いますが、内部に `await` があるたびに内部的に一時停止 ⏸ するかもしれないものとして認識します。
|
||||
|
||||
(Starletteを介して) FastAPIに力を与えて、印象的なパフォーマンスを実現しているものはこれがすべてです。
|
||||
`async` と `await` を用いた非同期コードの機能全体は、しばしば「コルーチンを使う」と要約されます。これは Go の主要機能「Goroutines」に相当します。
|
||||
|
||||
## 非常に発展的な技術的詳細
|
||||
## まとめ { #conclusion }
|
||||
|
||||
上のフレーズをもう一度見てみましょう:
|
||||
|
||||
> モダンな Python は **「非同期コード」** を **「コルーチン」** と呼ばれる仕組みでサポートしており、構文は **`async` と `await`** です。
|
||||
|
||||
今なら、より意味が分かるはずです。✨
|
||||
|
||||
これらすべてが (Starlette を通じて) FastAPI を支え、印象的なパフォーマンスを実現しています。
|
||||
|
||||
## 非常に発展的な技術的詳細 { #very-technical-details }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
恐らくスキップしても良いでしょう。
|
||||
おそらく読み飛ばしても大丈夫です。
|
||||
|
||||
この部分は**FastAPI**の仕組みに関する非常に技術的な詳細です。
|
||||
これは **FastAPI** の内部動作に関する、とても技術的な詳細です。
|
||||
|
||||
かなりの技術知識 (コルーチン、スレッド、ブロッキングなど) があり、FastAPIが `async def` と通常の `def` をどのように処理するか知りたい場合は、先に進んでください。
|
||||
(コルーチン、スレッド、ブロッキング等の) 技術知識があり、FastAPI が `async def` と通常の `def` をどう扱うかに興味がある場合は、読み進めてください。
|
||||
|
||||
///
|
||||
|
||||
### Path operation 関数
|
||||
### Path operation 関数 { #path-operation-functions }
|
||||
|
||||
*path operation 関数*を `async def` の代わりに通常の `def` で宣言すると、(サーバーをブロックするので) 直接呼び出す代わりに外部スレッドプール (awaitされる) で実行されます。
|
||||
*path operation 関数* を `async def` ではなく通常の `def` で宣言した場合、(サーバをブロックしてしまうため) 直接呼び出されるのではなく、外部のスレッドプールで実行され、それを待機します。
|
||||
|
||||
上記の方法と違った方法の別の非同期フレームワークから来ており、小さなパフォーマンス向上 (約100ナノ秒) のために通常の `def` を使用して些細な演算のみ行う *path operation 関数* を定義するのに慣れている場合は、**FastAPI**ではまったく逆の効果になることに注意してください。このような場合、*path operation 関数* がブロッキング<abbr title="入力/出力: ディスクの読み取りまたは書き込み、ネットワーク通信。">I/O</abbr>を実行しないのであれば、`async def` の使用をお勧めします。
|
||||
上記とは異なる動作の別の非同期フレームワークから来ており、ほんのわずかなパフォーマンス向上 (約 100 ナノ秒) を狙って、計算のみの些細な *path operation 関数* を素の `def` で定義することに慣れている場合、**FastAPI** では効果がまったく逆になる点に注意してください。これらの場合、*path operation 関数* がブロッキングな <abbr title="Input/Output - 入出力: ディスクの読み取りまたは書き込み、ネットワーク通信。">I/O</abbr> を行うコードを使っていない限り、`async def` を使った方が良いです。
|
||||
|
||||
それでも、どちらの状況でも、**FastAPI**が過去のフレームワークよりも (またはそれに匹敵するほど) [高速になる](index.md#_10){.internal-link target=_blank}可能性があります。
|
||||
それでも、どちらの状況でも、**FastAPI** はあなたが以前使っていたフレームワークよりも (少なくとも同等に) [高速である](index.md#performance){.internal-link target=_blank} 可能性が高いです。
|
||||
|
||||
### 依存関係
|
||||
### 依存関係 { #dependencies }
|
||||
|
||||
依存関係についても同様です。依存関係が `async def` ではなく標準の `def` 関数である場合、外部スレッドプールで実行されます。
|
||||
[依存関係](tutorial/dependencies/index.md){.internal-link target=_blank} についても同様です。依存関係が `async def` ではなく標準の `def` 関数である場合、外部のスレッドプールで実行されます。
|
||||
|
||||
### サブ依存関係
|
||||
### サブ依存関係 { #sub-dependencies }
|
||||
|
||||
(関数定義のパラメーターとして) 相互に必要な複数の依存関係とサブ依存関係を設定できます。一部は `async def` で作成され、他の一部は通常の `def` で作成されます。それでも動作し、通常の `def`で作成されたものは、「awaitされる」代わりに (スレッドプールから) 外部スレッドで呼び出されます。
|
||||
複数の依存関係や [サブ依存関係](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} を (関数定義のパラメータとして) 相互に要求させられます。その一部は `async def`、他は通常の `def` で作られていても動作します。通常の `def` で作られたものは「await」される代わりに、外部スレッドプールからスレッド上で呼び出されます。
|
||||
|
||||
### その他のユーティリティ関数
|
||||
### その他のユーティリティ関数 { #other-utility-functions }
|
||||
|
||||
あなたが直接呼び出すユーティリティ関数は通常の `def` または `async def` で作成でき、FastAPIは呼び出す方法に影響を与えません。
|
||||
あなたが直接呼び出すユーティリティ関数は、通常の `def` でも `async def` でも構いません。FastAPI はその呼び出し方に影響を与えません。
|
||||
|
||||
これは、FastAPIが呼び出す関数と対照的です: *path operation 関数*と依存関係。
|
||||
これは、FastAPI があなたの代わりに呼び出す関数 (すなわち *path operation 関数* と依存関係) とは対照的です。
|
||||
|
||||
ユーティリティ関数が `def` を使用した通常の関数である場合、スレッドプールではなく直接 (コードで記述したとおりに) 呼び出されます。関数が `async def` を使用して作成されている場合は、呼び出す際に `await` する必要があります。
|
||||
ユーティリティ関数が `def` の通常関数であれば、(あなたのコードに書いたとおりに) 直接呼び出され、スレッドプールでは実行されません。関数が `async def` で作られている場合は、その関数を呼ぶときに `await` すべきです。
|
||||
|
||||
---
|
||||
|
||||
繰り返しになりますが、これらは非常に技術的な詳細であり、検索して辿り着いた場合は役立つでしょう。
|
||||
繰り返しになりますが、これらは非常に技術的な詳細で、該当事項を検索してここにたどり着いた場合には役立つでしょう。
|
||||
|
||||
それ以外の場合は、上記のセクションのガイドラインで問題ないはずです: <a href="#_1">急いでいますか?</a>。
|
||||
それ以外の場合は、上のセクションのガイドラインに従えば十分です: <a href="#in-a-hurry">急いでいますか?</a>。
|
||||
|
||||
+18
-18
@@ -1,34 +1,34 @@
|
||||
# ベンチマーク
|
||||
# ベンチマーク { #benchmarks }
|
||||
|
||||
TechEmpowerの独立したベンチマークでは、Uvicornの下で動作する**FastAPI**アプリケーションは、<a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">利用可能な最速のPythonフレームワークの1つ</a>であり、下回っているのはStarletteとUvicorn自体 (FastAPIによって内部で使用される) のみだと示されています。
|
||||
TechEmpowerの独立したベンチマークでは、Uvicornの下で動作する**FastAPI**アプリケーションは、<a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">利用可能な最速のPythonフレームワークの1つ</a>であり、下回っているのはStarletteとUvicorn自体(FastAPIによって内部で使用される)のみだと示されています。
|
||||
|
||||
ただし、ベンチマークを確認し、比較する際には下記の内容に気を付けてください。
|
||||
|
||||
## ベンチマークと速度
|
||||
## ベンチマークと速度 { #benchmarks-and-speed }
|
||||
|
||||
ベンチマークを確認する時、異なるツールを同等なものと比較するのが一般的です。
|
||||
ベンチマークを確認する時、異なるタイプの複数のツールが同等のものとして比較されているのを目にするのが一般的です。
|
||||
|
||||
具体的には、Uvicorn、Starlette、FastAPIを (他の多くのツールと) 比較しました。
|
||||
具体的には、Uvicorn、Starlette、FastAPIを(他の多くのツールの中で)まとめて比較しているのを目にすることがあります。
|
||||
|
||||
ツールで解決する問題がシンプルなほど、パフォーマンスが向上します。また、ほとんどのベンチマークは、ツールから提供される追加機能をテストしていません。
|
||||
|
||||
階層関係はこのようになります。
|
||||
|
||||
* **Uvicorn**: ASGIサーバー
|
||||
* **Starlette**: (Uvicornを使用) WEBマイクロフレームワーク
|
||||
* **FastAPI**: (Starletteを使用) データバリデーションなどの、APIを構築する追加機能を備えたAPIマイクロフレームワーク
|
||||
* **Starlette**: (Uvicornを使用)webマイクロフレームワーク
|
||||
* **FastAPI**: (Starletteを使用)データバリデーションなど、APIを構築するためのいくつかの追加機能を備えたAPIマイクロフレームワーク
|
||||
|
||||
* **Uvicorn**:
|
||||
* サーバー自体に余分なコードが少ないので、最高のパフォーマンスが得られます。
|
||||
* Uvicornにアプリケーションを直接書くことはできません。つまり、あなたのコードには、Starlette (または** FastAPI **) が提供するコードを、多かれ少なかれ含める必要があります。そうすると、最終的なアプリケーションは、フレームワークを使用してアプリのコードとバグを最小限に抑えた場合と同じオーバーヘッドになります。
|
||||
* もしUvicornを比較する場合は、Daphne、Hypercorn、uWSGIなどのアプリケーションサーバーと比較してください。
|
||||
* サーバー自体以外に余分なコードがあまりないため、最高のパフォーマンスになります。
|
||||
* Uvicornにアプリケーションを直接書くことはないでしょう。それは、あなたのコードに、Starlette(または**FastAPI**)が提供するコードを、少なくとも多かれ少なかれ含める必要があるということです。そして、もしそうした場合、最終的なアプリケーションは、フレームワークを使用してアプリのコードとバグを最小限に抑えた場合と同じオーバーヘッドになります。
|
||||
* Uvicornを比較する場合は、Daphne、Hypercorn、uWSGIなどのアプリケーションサーバーと比較してください。
|
||||
* **Starlette**:
|
||||
* Uvicornに次ぐ性能を持つでしょう。実際、StarletteはUvicornを使用しています。だから、より多くのコードを実行する必要があり、Uvicornよりも「遅く」なってしまうだけなのです。
|
||||
* しかし、パスベースのルーティングなどのシンプルなWEBアプリケーションを構築する機能を提供します。
|
||||
* もしStarletteを比較する場合は、Sanic、Flask、DjangoなどのWEBフレームワーク (もしくはマイクロフレームワーク) と比較してください。
|
||||
* Uvicornに次ぐ性能になるでしょう。実際、Starletteは実行にUvicornを使用しています。そのため、おそらく、より多くのコードを実行しなければならない分だけ、Uvicornより「遅く」なるだけです。
|
||||
* しかし、パスに基づくルーティングなどを使って、シンプルなwebアプリケーションを構築するためのツールを提供します。
|
||||
* Starletteを比較する場合は、Sanic、Flask、Djangoなどのwebフレームワーク(またはマイクロフレームワーク)と比較してください。
|
||||
* **FastAPI**:
|
||||
* StarletteがUvicornを使っているのと同じで、**FastAPI**はStarletteを使っており、それより速くできません。
|
||||
* FastAPIはStarletteの上にさらに多くの機能を提供します。データの検証やシリアライゼーションなど、APIを構築する際に常に必要な機能です。また、それを使用することで、自動ドキュメント化を無料で取得できます (ドキュメントは実行中のアプリケーションにオーバーヘッドを追加せず、起動時に生成されます) 。
|
||||
* FastAPIを使用せず、直接Starlette (またはSanic, Flask, Responderなど) を使用した場合、データの検証とシリアライズをすべて自分で実装する必要があります。そのため、最終的なアプリケーションはFastAPIを使用して構築した場合と同じオーバーヘッドが発生します。そして、多くの場合、このデータ検証とシリアライズは、アプリケーションのコードの中で最大の記述量になります。
|
||||
* FastAPIを使用することで、開発時間、バグ、コード行数を節約でき、使用しない場合 (あなたが全ての機能を実装し直した場合) と同じかそれ以上のパフォーマンスを得られます。
|
||||
* もしFastAPIを比較する場合は、Flask-apispec、NestJS、Moltenなどのデータ検証や、シリアライズの機能を提供するWEBフレームワーク (や機能のセット) と比較してください。これらはデータの自動検証や、シリアライズ、ドキュメント化が統合されたフレームワークです。
|
||||
* StarletteがUvicornを使用しており、それより速くできないのと同じように、**FastAPI**はStarletteを使用しているため、それより速くできません。
|
||||
* FastAPIはStarletteの上に、より多くの機能を提供します。データバリデーションやシリアライゼーションのように、APIを構築する際にほとんど常に必要な機能です。また、それを使用することで、自動ドキュメント化を無料で利用できます(自動ドキュメントは実行中のアプリケーションにオーバーヘッドを追加せず、起動時に生成されます)。
|
||||
* FastAPIを使用せず、Starletteを直接(またはSanic、Flask、Responderなど別のツールを)使用した場合、データバリデーションとシリアライゼーションをすべて自分で実装する必要があります。そのため、最終的なアプリケーションはFastAPIを使用して構築した場合と同じオーバーヘッドが発生します。そして多くの場合、このデータバリデーションとシリアライゼーションは、アプリケーションで書かれるコードの大部分になります。
|
||||
* そのため、FastAPIを使用することで、開発時間、バグ、コード行数を節約でき、使用しない場合(あなたがそれをすべて自分のコードで実装する必要があるため)と比べて、同じパフォーマンス(またはそれ以上)を得られる可能性があります。
|
||||
* FastAPIを比較する場合は、Flask-apispec、NestJS、Moltenなど、データバリデーション、シリアライゼーション、ドキュメント化を提供するwebアプリケーションフレームワーク(またはツール群)と比較してください。自動データバリデーション、シリアライゼーション、ドキュメント化が統合されたフレームワークです。
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# クラウドプロバイダへの FastAPI デプロイ { #deploy-fastapi-on-cloud-providers }
|
||||
|
||||
FastAPI アプリケーションは、実質的にどのようなクラウドプロバイダでもデプロイできます。
|
||||
|
||||
多くの場合、主要なクラウドプロバイダは FastAPI をデプロイするためのガイドを提供しています。
|
||||
|
||||
## FastAPI Cloud { #fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** は、**FastAPI** の作者と同じチームによって作られています。
|
||||
|
||||
API の**構築**、**デプロイ**、**アクセス**までのプロセスを、最小限の手間で効率化します。
|
||||
|
||||
FastAPI でアプリを開発するときと同じ**開発者体験**を、クラウドへの**デプロイ**にももたらします。🎉
|
||||
|
||||
FastAPI Cloud は、*FastAPI and friends* オープンソースプロジェクトの主要なスポンサーかつ資金提供元です。✨
|
||||
|
||||
## クラウドプロバイダ - スポンサー { #cloud-providers-sponsors }
|
||||
|
||||
他にもいくつかのクラウドプロバイダが ✨ [**FastAPI をスポンサーしています**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨。🙇
|
||||
|
||||
それらのガイドを参考にし、サービスを試してみるのもよいでしょう:
|
||||
|
||||
* <a href="https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi" class="external-link" target="_blank">Render</a>
|
||||
* <a href="https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi" class="external-link" target="_blank">Railway</a>
|
||||
@@ -1,4 +1,4 @@
|
||||
# デプロイメントのコンセプト
|
||||
# デプロイメントのコンセプト { #deployments-concepts }
|
||||
|
||||
**FastAPI**を用いたアプリケーションをデプロイするとき、もしくはどのようなタイプのWeb APIであっても、おそらく気になるコンセプトがいくつかあります。
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* メモリー
|
||||
* メモリ
|
||||
* 開始前の事前のステップ
|
||||
|
||||
これらが**デプロイメント**にどのような影響を与えるかを見ていきましょう。
|
||||
|
||||
最終的な目的は、**安全な方法で**APIクライアントに**サービスを提供**し、**中断を回避**するだけでなく、**計算リソース**(例えばリモートサーバー/仮想マシン)を可能な限り効率的に使用することです。🚀
|
||||
最終的な目的は、**安全な方法で**APIクライアントに**サービスを提供**し、**中断を回避**するだけでなく、**計算リソース**(例えばリモートサーバー/仮想マシン)を可能な限り効率的に使用することです。 🚀
|
||||
|
||||
この章では前述した**コンセプト**についてそれぞれ説明します。
|
||||
|
||||
@@ -27,16 +27,15 @@
|
||||
|
||||
しかし、今はこれらの重要な**コンセプトに基づくアイデア**を確認しましょう。これらのコンセプトは、他のどのタイプのWeb APIにも当てはまります。💡
|
||||
|
||||
## セキュリティ - HTTPS
|
||||
## セキュリティ - HTTPS { #security-https }
|
||||
|
||||
<!-- NOTE: https.md written in Japanese does not exist, so it redirects to English one -->
|
||||
[前チャプターのHTTPSについて](https.md){.internal-link target=_blank}では、HTTPSがどのようにAPIを暗号化するのかについて学びました。
|
||||
|
||||
通常、アプリケーションサーバにとって**外部の**コンポーネントである**TLS Termination Proxy**によって提供されることが一般的です。このプロキシは通信の暗号化を担当します。
|
||||
|
||||
さらにセキュアな通信において、HTTPS証明書の定期的な更新を行いますが、これはTLS Termination Proxyと同じコンポーネントが担当することもあれば、別のコンポーネントが担当することもあります。
|
||||
さらに、HTTPS証明書の更新を担当するものが必要で、同じコンポーネントが担当することもあれば、別のコンポーネントが担当することもあります。
|
||||
|
||||
### HTTPS 用ツールの例
|
||||
### HTTPS 用ツールの例 { #example-tools-for-https }
|
||||
TLS Termination Proxyとして使用できるツールには以下のようなものがあります:
|
||||
|
||||
* Traefik
|
||||
@@ -59,11 +58,11 @@ TLS Termination Proxyとして使用できるツールには以下のような
|
||||
|
||||
次に考慮すべきコンセプトは、実際のAPIを実行するプログラム(例:Uvicorn)に関連するものすべてです。
|
||||
|
||||
## プログラム と プロセス
|
||||
## プログラム と プロセス { #program-and-process }
|
||||
|
||||
私たちは「**プロセス**」という言葉についてたくさん話すので、その意味や「**プログラム**」という言葉との違いを明確にしておくと便利です。
|
||||
|
||||
### プログラムとは何か
|
||||
### プログラムとは何か { #what-is-a-program }
|
||||
|
||||
**プログラム**という言葉は、一般的にいろいろなものを表現するのに使われます:
|
||||
|
||||
@@ -71,7 +70,7 @@ TLS Termination Proxyとして使用できるツールには以下のような
|
||||
* OSによって実行することができるファイル(例: `python`, `python.exe` or `uvicorn`)
|
||||
* OS上で**実行**している間、CPUを使用し、メモリ上に何かを保存する特定のプログラム(**プロセス**とも呼ばれる)
|
||||
|
||||
### プロセスとは何か
|
||||
### プロセスとは何か { #what-is-a-process }
|
||||
|
||||
**プロセス**という言葉は通常、より具体的な意味で使われ、OSで実行されているものだけを指します(先ほどの最後の説明のように):
|
||||
|
||||
@@ -92,27 +91,29 @@ OSの「タスク・マネージャー」や「システム・モニター」(
|
||||
|
||||
さて、**プロセス**と**プログラム**という用語の違いを確認したところで、デプロイメントについて話を続けます。
|
||||
|
||||
## 起動時の実行
|
||||
## 起動時の実行 { #running-on-startup }
|
||||
|
||||
ほとんどの場合、Web APIを作成するときは、クライアントがいつでもアクセスできるように、**常に**中断されることなく**実行される**ことを望みます。もちろん、特定の状況でのみ実行させたい特別な理由がある場合は別ですが、その時間のほとんどは、常に実行され、**利用可能**であることを望みます。
|
||||
|
||||
### リモートサーバー上での実行
|
||||
### リモートサーバー上での実行 { #in-a-remote-server }
|
||||
|
||||
リモートサーバー(クラウドサーバー、仮想マシンなど)をセットアップするときにできる最も簡単なことは、ローカルで開発するときと同じように、Uvicorn(または同様のもの)を手動で実行することです。 この方法は**開発中**には役に立つと思われます。
|
||||
リモートサーバー(クラウドサーバー、仮想マシンなど)をセットアップするときにできる最も簡単なことは、ローカルで開発するときと同じように、`fastapi run`(Uvicornを使用します)や同様のものを手動で実行することです。
|
||||
|
||||
そしてこれは動作し、**開発中**には役に立つでしょう。
|
||||
|
||||
しかし、サーバーへの接続が切れた場合、**実行中のプロセス**はおそらくダウンしてしまうでしょう。
|
||||
|
||||
そしてサーバーが再起動された場合(アップデートやクラウドプロバイダーからのマイグレーションの後など)、おそらくあなたはそれに**気づかないでしょう**。そのため、プロセスを手動で再起動しなければならないことすら気づかないでしょう。つまり、APIはダウンしたままなのです。😱
|
||||
|
||||
### 起動時に自動的に実行
|
||||
### 起動時に自動的に実行 { #run-automatically-on-startup }
|
||||
|
||||
一般的に、サーバープログラム(Uvicornなど)はサーバー起動時に自動的に開始され、**人の介入**を必要とせずに、APIと一緒にプロセスが常に実行されるようにしたいと思われます(UvicornがFastAPIアプリを実行するなど)。
|
||||
|
||||
### 別のプログラムの用意
|
||||
### 別のプログラムの用意 { #separate-program }
|
||||
|
||||
これを実現するために、通常は**別のプログラム**を用意し、起動時にアプリケーションが実行されるようにします。そして多くの場合、他のコンポーネントやアプリケーション、例えばデータベースも実行されるようにします。
|
||||
|
||||
### 起動時に実行するツールの例
|
||||
### 起動時に実行するツールの例 { #example-tools-to-run-at-startup }
|
||||
|
||||
実行するツールの例をいくつか挙げます:
|
||||
|
||||
@@ -127,31 +128,33 @@ OSの「タスク・マネージャー」や「システム・モニター」(
|
||||
|
||||
次の章で、より具体的な例を挙げていきます。
|
||||
|
||||
## 再起動
|
||||
## 再起動 { #restarts }
|
||||
|
||||
起動時にアプリケーションが実行されることを確認するのと同様に、失敗後にアプリケーションが**再起動**されることも確認したいと思われます。
|
||||
|
||||
### 我々は間違いを犯す
|
||||
### 我々は間違いを犯す { #we-make-mistakes }
|
||||
|
||||
私たち人間は常に**間違い**を犯します。ソフトウェアには、ほとんど常に**バグ**があらゆる箇所に隠されています。🐛
|
||||
|
||||
### 小さなエラーは自動的に処理される
|
||||
そして私たち開発者は、それらのバグを見つけたり新しい機能を実装したりしながらコードを改善し続けます(新しいバグも追加してしまうかもしれません😅)。
|
||||
|
||||
### 小さなエラーは自動的に処理される { #small-errors-automatically-handled }
|
||||
|
||||
FastAPIでWeb APIを構築する際に、コードにエラーがある場合、FastAPIは通常、エラーを引き起こした単一のリクエストにエラーを含めます。🛡
|
||||
|
||||
クライアントはそのリクエストに対して**500 Internal Server Error**を受け取りますが、アプリケーションは完全にクラッシュするのではなく、次のリクエストのために動作を続けます。
|
||||
|
||||
### 重大なエラー - クラッシュ
|
||||
### 重大なエラー - クラッシュ { #bigger-errors-crashes }
|
||||
|
||||
しかしながら、**アプリケーション全体をクラッシュさせるようなコードを書いて**UvicornとPythonをクラッシュさせるようなケースもあるかもしれません。💥
|
||||
|
||||
それでも、ある箇所でエラーが発生したからといって、アプリケーションを停止させたままにしたくないでしょう。 少なくとも壊れていない*パスオペレーション*については、**実行し続けたい**はずです。
|
||||
それでも、ある箇所でエラーが発生したからといって、アプリケーションを停止させたままにしたくないでしょう。 少なくとも壊れていない*path operation*については、**実行し続けたい**はずです。
|
||||
|
||||
### クラッシュ後の再起動
|
||||
### クラッシュ後の再起動 { #restart-after-crash }
|
||||
|
||||
しかし、実行中の**プロセス**をクラッシュさせるような本当にひどいエラーの場合、少なくとも2〜3回ほどプロセスを**再起動**させる外部コンポーネントが必要でしょう。
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
...とはいえ、アプリケーション全体が**すぐにクラッシュする**のであれば、いつまでも再起動し続けるのは意味がないでしょう。しかし、その場合はおそらく開発中か少なくともデプロイ直後に気づくと思われます。
|
||||
|
||||
@@ -161,7 +164,7 @@ FastAPIでWeb APIを構築する際に、コードにエラーがある場合、
|
||||
|
||||
あなたはおそらく**外部コンポーネント**がアプリケーションの再起動を担当することを望むと考えます。 なぜなら、その時点でUvicornとPythonを使った同じアプリケーションはすでにクラッシュしており、同じアプリケーションの同じコードに対して何もできないためです。
|
||||
|
||||
### 自動的に再起動するツールの例
|
||||
### 自動的に再起動するツールの例 { #example-tools-to-restart-automatically }
|
||||
|
||||
ほとんどの場合、前述した**起動時にプログラムを実行する**ために使用されるツールは、自動で**再起動**することにも利用されます。
|
||||
|
||||
@@ -176,20 +179,19 @@ FastAPIでWeb APIを構築する際に、コードにエラーがある場合、
|
||||
* クラウドプロバイダーがサービスの一部として内部的に処理
|
||||
* そのほか...
|
||||
|
||||
## レプリケーション - プロセスとメモリー
|
||||
## レプリケーション - プロセスとメモリ { #replication-processes-and-memory }
|
||||
|
||||
FastAPI アプリケーションでは、Uvicorn のようなサーバープログラムを使用し、**1つのプロセス**で1度に複数のクライアントに同時に対応できます。
|
||||
FastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コマンドのようなサーバープログラムを使用し、**1つのプロセス**で1度に複数のクライアントに同時に対応できます。
|
||||
|
||||
しかし、多くの場合、複数のワーカー・プロセスを同時に実行したいと考えるでしょう。
|
||||
|
||||
### 複数のプロセス - Worker
|
||||
### 複数のプロセス - Worker { #multiple-processes-workers }
|
||||
|
||||
クライアントの数が単一のプロセスで処理できる数を超えており(たとえば仮想マシンがそれほど大きくない場合)、かつサーバーの CPU に**複数のコア**がある場合、同じアプリケーションで同時に**複数のプロセス**を実行させ、すべてのリクエストを分散させることができます。
|
||||
|
||||
同じAPIプログラムの**複数のプロセス**を実行する場合、それらは一般的に**Worker/ワーカー**と呼ばれます。
|
||||
|
||||
### ワーカー・プロセス と ポート
|
||||
<!-- NOTE: https.md written in Japanese does not exist, so it redirects to English one -->
|
||||
### ワーカー・プロセス と ポート { #worker-processes-and-ports }
|
||||
|
||||
[HTTPSについて](https.md){.internal-link target=_blank}のドキュメントで、1つのサーバーで1つのポートとIPアドレスの組み合わせでリッスンできるのは1つのプロセスだけであることを覚えていますでしょうか?
|
||||
|
||||
@@ -197,13 +199,13 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
|
||||
|
||||
そのため、**複数のプロセス**を同時に持つには**ポートでリッスンしている単一のプロセス**が必要であり、それが何らかの方法で各ワーカー・プロセスに通信を送信することが求められます。
|
||||
|
||||
### プロセスあたりのメモリー
|
||||
### プロセスあたりのメモリ { #memory-per-process }
|
||||
|
||||
さて、プログラムがメモリにロードする際には、例えば機械学習モデルや大きなファイルの内容を変数に入れたりする場合では、**サーバーのメモリ(RAM)**を少し消費します。
|
||||
|
||||
そして複数のプロセスは通常、**メモリを共有しません**。これは、実行中の各プロセスがそれぞれ独自の変数やメモリ等を持っていることを意味します。つまり、コード内で大量のメモリを消費している場合、**各プロセス**は同等の量のメモリを消費することになります。
|
||||
|
||||
### サーバーメモリー
|
||||
### サーバーメモリ { #server-memory }
|
||||
|
||||
例えば、あなたのコードが **1GBのサイズの機械学習モデル**をロードする場合、APIで1つのプロセスを実行すると、少なくとも1GBのRAMを消費します。
|
||||
|
||||
@@ -211,7 +213,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
|
||||
|
||||
リモートサーバーや仮想マシンのRAMが3GBしかない場合、4GB以上のRAMをロードしようとすると問題が発生します。🚨
|
||||
|
||||
### 複数プロセス - 例
|
||||
### 複数プロセス - 例 { #multiple-processes-an-example }
|
||||
|
||||
この例では、2つの**ワーカー・プロセス**を起動し制御する**マネージャー・ プロセス**があります。
|
||||
|
||||
@@ -227,7 +229,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
|
||||
|
||||
毎回同程度の計算を行うAPIがあり、多くのクライアントがいるのであれば、**CPU使用率**もおそらく**安定**するでしょう(常に急激に上下するのではなく)。
|
||||
|
||||
### レプリケーション・ツールと戦略の例
|
||||
### レプリケーション・ツールと戦略の例 { #examples-of-replication-tools-and-strategies }
|
||||
|
||||
これを実現するにはいくつかのアプローチがありますが、具体的な戦略については次の章(Dockerやコンテナの章など)で詳しく説明します。
|
||||
|
||||
@@ -237,25 +239,22 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
|
||||
|
||||
考えられる組み合わせと戦略をいくつか紹介します:
|
||||
|
||||
* **Gunicorn**が**Uvicornワーカー**を管理
|
||||
* Gunicornは**IP**と**ポート**をリッスンする**プロセスマネージャ**で、レプリケーションは**複数のUvicornワーカー・プロセス**を持つことによって行われる。
|
||||
* **Uvicorn**が**Uvicornワーカー**を管理
|
||||
* `--workers` を指定した **Uvicorn**
|
||||
* 1つのUvicornの**プロセスマネージャー**が**IP**と**ポート**をリッスンし、**複数のUvicornワーカー・プロセス**を起動する。
|
||||
* **Kubernetes**やその他の分散**コンテナ・システム**
|
||||
* **Kubernetes**レイヤーの何かが**IP**と**ポート**をリッスンする。レプリケーションは、**複数のコンテナ**にそれぞれ**1つのUvicornプロセス**を実行させることで行われる。
|
||||
* **クラウド・サービス**によるレプリケーション
|
||||
* クラウド・サービスはおそらく**あなたのためにレプリケーションを処理**します。**実行するプロセス**や使用する**コンテナイメージ**を定義できるかもしれませんが、いずれにせよ、それはおそらく**単一のUvicornプロセス**であり、クラウドサービスはそのレプリケーションを担当するでしょう。
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
これらの**コンテナ**やDockerそしてKubernetesに関する項目が、まだあまり意味をなしていなくても心配しないでください。
|
||||
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
|
||||
|
||||
コンテナ・イメージ、Docker、Kubernetesなどについては、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
コンテナ・イメージ、Docker、Kubernetesなどについては、将来の章で詳しく説明します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
## 開始前の事前のステップ
|
||||
## 開始前の事前のステップ { #previous-steps-before-starting }
|
||||
|
||||
アプリケーションを**開始する前**に、いくつかのステップを実行したい場合が多くあります。
|
||||
|
||||
@@ -271,7 +270,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
|
||||
|
||||
もちろん、事前のステップを何度も実行しても問題がない場合もあり、その際は対処がかなり楽になります。
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
また、セットアップによっては、アプリケーションを開始する前の**事前のステップ**が必要ない場合もあることを覚えておいてください。
|
||||
|
||||
@@ -279,7 +278,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
|
||||
|
||||
///
|
||||
|
||||
### 事前ステップの戦略例
|
||||
### 事前ステップの戦略例 { #examples-of-previous-steps-strategies }
|
||||
|
||||
これは**システムを**デプロイする方法に**大きく依存**するだろうし、おそらくプログラムの起動方法や再起動の処理などにも関係してくるでしょう。
|
||||
|
||||
@@ -289,14 +288,13 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
|
||||
* 事前のステップを実行し、アプリケーションを起動するbashスクリプト
|
||||
* 利用するbashスクリプトを起動/再起動したり、エラーを検出したりする方法は以前として必要になるでしょう。
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
|
||||
コンテナを使った具体的な例については、次の章で紹介します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
コンテナを使った具体的な例については、将来の章で紹介します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
## リソースの利用
|
||||
## リソースの利用 { #resource-utilization }
|
||||
|
||||
あなたのサーバーは**リソース**であり、プログラムを実行しCPUの計算時間や利用可能なRAMメモリを消費または**利用**することができます。
|
||||
|
||||
@@ -319,7 +317,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
|
||||
|
||||
`htop`のような単純なツールを使って、サーバーで使用されているCPUやRAM、あるいは各プロセスで使用されている量を見ることができます。あるいは、より複雑な監視ツールを使って、サーバに分散して使用することもできます。
|
||||
|
||||
## まとめ
|
||||
## まとめ { #recap }
|
||||
|
||||
アプリケーションのデプロイ方法を決定する際に、考慮すべきであろう主要なコンセプトのいくつかを紹介していきました:
|
||||
|
||||
@@ -327,7 +325,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* メモリー
|
||||
* メモリ
|
||||
* 開始前の事前ステップ
|
||||
|
||||
これらの考え方とその適用方法を理解することで、デプロイメントを設定したり調整したりする際に必要な直感的な判断ができるようになるはずです。🤓
|
||||
|
||||
+161
-285
@@ -1,23 +1,20 @@
|
||||
# コンテナ内のFastAPI - Docker
|
||||
# コンテナ内のFastAPI - Docker { #fastapi-in-containers-docker }
|
||||
|
||||
FastAPIアプリケーションをデプロイする場合、一般的なアプローチは**Linuxコンテナ・イメージ**をビルドすることです。
|
||||
|
||||
基本的には <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>を用いて行われます。生成されたコンテナ・イメージは、いくつかの方法のいずれかでデプロイできます。
|
||||
FastAPIアプリケーションをデプロイする場合、一般的なアプローチは**Linuxコンテナ・イメージ**をビルドすることです。基本的には <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>を用いて行われます。生成されたコンテナ・イメージは、いくつかの方法のいずれかでデプロイできます。
|
||||
|
||||
Linuxコンテナの使用には、**セキュリティ**、**反復可能性(レプリカビリティ)**、**シンプリシティ**など、いくつかの利点があります。
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
TODO: なぜか遷移できない
|
||||
お急ぎで、すでにこれらの情報をご存じですか? [以下の`Dockerfile`の箇所👇](#build-a-docker-image-for-fastapi)へジャンプしてください。
|
||||
|
||||
///
|
||||
|
||||
<details>
|
||||
<summary>Dockerfile プレビュー 👀</summary>
|
||||
<summary>Dockerfile Preview 👀</summary>
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.9
|
||||
FROM python:3.14
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
@@ -27,15 +24,15 @@ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
COPY ./app /code/app
|
||||
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
|
||||
# If running behind a proxy like Nginx or Traefik add --proxy-headers
|
||||
# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
|
||||
# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## コンテナとは何か
|
||||
## コンテナとは何か { #what-is-a-container }
|
||||
|
||||
コンテナ(主にLinuxコンテナ)は、同じシステム内の他のコンテナ(他のアプリケーションやコンポーネント)から隔離された状態を保ちながら、すべての依存関係や必要なファイルを含むアプリケーションをパッケージ化する非常に**軽量**な方法です。
|
||||
|
||||
@@ -45,7 +42,7 @@ Linuxコンテナは、ホスト(マシン、仮想マシン、クラウドサ
|
||||
|
||||
コンテナはまた、独自の**分離された**実行プロセス(通常は1つのプロセスのみ)や、ファイルシステム、ネットワークを持ちます。 このことはデプロイ、セキュリティ、開発などを簡素化させます。
|
||||
|
||||
## コンテナ・イメージとは何か
|
||||
## コンテナ・イメージとは何か { #what-is-a-container-image }
|
||||
|
||||
**コンテナ**は、**コンテナ・イメージ**から実行されます。
|
||||
|
||||
@@ -53,23 +50,17 @@ Linuxコンテナは、ホスト(マシン、仮想マシン、クラウドサ
|
||||
|
||||
保存された静的コンテンツである「**コンテナイメージ**」とは対照的に、「**コンテナ**」は通常、実行中のインスタンス、つまり**実行**されているものを指します。
|
||||
|
||||
**コンテナ**が起動され実行されるとき(**コンテナイメージ**から起動されるとき)、ファイルや環境変数などが作成されたり変更されたりする可能性があります。
|
||||
|
||||
これらの変更はそのコンテナ内にのみ存在しますが、基盤となるコンテナ・イメージには残りません(ディスクに保存されません)。
|
||||
**コンテナ**が起動され実行されるとき(**コンテナイメージ**から起動されるとき)、ファイルや環境変数などが作成されたり変更されたりする可能性があります。これらの変更はそのコンテナ内にのみ存在しますが、基盤となるコンテナ・イメージには残りません(ディスクに保存されません)。
|
||||
|
||||
コンテナイメージは **プログラム** ファイルやその内容、例えば `python` と `main.py` ファイルに匹敵します。
|
||||
|
||||
そして、**コンテナ**自体は(**コンテナイメージ**とは対照的に)イメージをもとにした実際の実行中のインスタンスであり、**プロセス**に匹敵します。
|
||||
そして、**コンテナ**自体は(**コンテナイメージ**とは対照的に)イメージをもとにした実際の実行中のインスタンスであり、**プロセス**に匹敵します。実際、コンテナが実行されているのは、**プロセスが実行されている**ときだけです(通常は単一のプロセスだけです)。 コンテナ内で実行中のプロセスがない場合、コンテナは停止します。
|
||||
|
||||
実際、コンテナが実行されているのは、**プロセスが実行されている**ときだけです(通常は単一のプロセスだけです)。 コンテナ内で実行中のプロセスがない場合、コンテナは停止します。
|
||||
|
||||
## コンテナ・イメージ
|
||||
## コンテナ・イメージ { #container-images }
|
||||
|
||||
Dockerは、**コンテナ・イメージ**と**コンテナ**を作成・管理するための主要なツールの1つです。
|
||||
|
||||
そして、DockerにはDockerイメージ(コンテナ)を共有する<a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a>というものがあります。
|
||||
|
||||
Docker Hubは 多くのツールや環境、データベース、アプリケーションに対応している予め作成された**公式のコンテナ・イメージ**をパブリックに提供しています。
|
||||
そして、多くのツールや環境、データベース、アプリケーションに対応している予め作成された**公式のコンテナ・イメージ**をパブリックに提供している<a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a>というものがあります。
|
||||
|
||||
例えば、公式イメージの1つに<a href="https://hub.docker.com/_/python" class="external-link" target="_blank">Python Image</a>があります。
|
||||
|
||||
@@ -88,7 +79,7 @@ Docker Hubは 多くのツールや環境、データベース、アプリケー
|
||||
|
||||
すべてのコンテナ管理システム(DockerやKubernetesなど)には、こうしたネットワーキング機能が統合されています。
|
||||
|
||||
## コンテナとプロセス
|
||||
## コンテナとプロセス { #containers-and-processes }
|
||||
|
||||
通常、**コンテナ・イメージ**はそのメタデータに**コンテナ**の起動時に実行されるデフォルトのプログラムまたはコマンドと、そのプログラムに渡されるパラメータを含みます。コマンドラインでの操作とよく似ています。
|
||||
|
||||
@@ -100,7 +91,7 @@ Docker Hubは 多くのツールや環境、データベース、アプリケー
|
||||
|
||||
しかし、**少なくとも1つの実行中のプロセス**がなければ、実行中のコンテナを持つことはできないです。メイン・プロセスが停止すれば、コンテナも停止します。
|
||||
|
||||
## Build a Docker Image for FastAPI
|
||||
## FastAPI用のDockerイメージをビルドする { #build-a-docker-image-for-fastapi }
|
||||
|
||||
ということで、何か作りましょう!🚀
|
||||
|
||||
@@ -112,7 +103,7 @@ FastAPI用の**Dockerイメージ**を、**公式Python**イメージに基づ
|
||||
* **Raspberry Pi**で実行する場合
|
||||
* コンテナ・イメージを実行してくれるクラウド・サービスなどを利用する場合
|
||||
|
||||
### パッケージ要件(package requirements)
|
||||
### パッケージ要件 { #package-requirements }
|
||||
|
||||
アプリケーションの**パッケージ要件**は通常、何らかのファイルに記述されているはずです。
|
||||
|
||||
@@ -125,9 +116,8 @@ FastAPI用の**Dockerイメージ**を、**公式Python**イメージに基づ
|
||||
例えば、`requirements.txt` は次のようになります:
|
||||
|
||||
```
|
||||
fastapi>=0.68.0,<0.69.0
|
||||
pydantic>=1.8.0,<2.0.0
|
||||
uvicorn>=0.15.0,<0.16.0
|
||||
fastapi[standard]>=0.113.0,<0.114.0
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
```
|
||||
|
||||
そして通常、例えば `pip` を使ってこれらのパッケージの依存関係をインストールします:
|
||||
@@ -137,28 +127,24 @@ uvicorn>=0.15.0,<0.16.0
|
||||
```console
|
||||
$ pip install -r requirements.txt
|
||||
---> 100%
|
||||
Successfully installed fastapi pydantic uvicorn
|
||||
Successfully installed fastapi pydantic
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// info
|
||||
/// info | 情報
|
||||
|
||||
パッケージの依存関係を定義しインストールするためのフォーマットやツールは他にもあります。
|
||||
|
||||
Poetryを使った例は、後述するセクションでご紹介します。👇
|
||||
|
||||
///
|
||||
|
||||
### **FastAPI**コードを作成する
|
||||
### **FastAPI**コードを作成する { #create-the-fastapi-code }
|
||||
|
||||
* `app` ディレクトリを作成し、その中に入ります
|
||||
* 空のファイル `__init__.py` を作成します
|
||||
* `main.py` ファイルを作成します:
|
||||
* `app` ディレクトリを作成し、その中に入ります。
|
||||
* 空のファイル `__init__.py` を作成します。
|
||||
* 次の内容で `main.py` ファイルを作成します:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -170,32 +156,32 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
### Dockerfile
|
||||
### Dockerfile { #dockerfile }
|
||||
|
||||
同じプロジェクト・ディレクトリに`Dockerfile`というファイルを作成します:
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
# (1)
|
||||
FROM python:3.9
|
||||
# (1)!
|
||||
FROM python:3.14
|
||||
|
||||
# (2)
|
||||
# (2)!
|
||||
WORKDIR /code
|
||||
|
||||
# (3)
|
||||
# (3)!
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
# (4)
|
||||
# (4)!
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (5)
|
||||
# (5)!
|
||||
COPY ./app /code/app
|
||||
|
||||
# (6)
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
# (6)!
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
1. 公式のPythonベースイメージから始めます
|
||||
@@ -211,9 +197,10 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
このファイルは**頻繁には変更されない**ので、Dockerはこのステップではそれを検知し**キャッシュ**を使用し、次のステップでもキャッシュを有効にします。
|
||||
|
||||
4. 要件ファイルにあるパッケージの依存関係をインストールします
|
||||
|
||||
`--no-cache-dir` オプションはダウンロードしたパッケージをローカルに保存しないように `pip` に指示します。これは、同じパッケージをインストールするために `pip` を再度実行する場合にのみ有効ですが、コンテナで作業する場合はそうではないです。
|
||||
|
||||
/// note
|
||||
/// note | 備考
|
||||
|
||||
`--no-cache-dir`は`pip`に関連しているだけで、Dockerやコンテナとは何の関係もないです。
|
||||
|
||||
@@ -225,26 +212,56 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
||||
このステップでキャッシュを使用すると、開発中にイメージを何度もビルドする際に、**毎回**すべての依存関係を**ダウンロードしてインストールする**代わりに多くの**時間**を**節約**できます。
|
||||
|
||||
5. ./app` ディレクトリを `/code` ディレクトリの中にコピーする。
|
||||
5. `./app` ディレクトリを `/code` ディレクトリの中にコピーする。
|
||||
|
||||
これには**最も頻繁に変更される**すべてのコードが含まれているため、Dockerの**キャッシュ**は**これ以降のステップ**に簡単に使用されることはありません。
|
||||
|
||||
そのため、コンテナイメージのビルド時間を最適化するために、`Dockerfile`の **最後** にこれを置くことが重要です。
|
||||
|
||||
6. `uvicorn`サーバーを実行するための**コマンド**を設定します
|
||||
6. 内部でUvicornを使用する `fastapi run` を使うための**コマンド**を設定します
|
||||
|
||||
`CMD` は文字列のリストを取り、それぞれの文字列はスペースで区切られたコマンドラインに入力するものです。
|
||||
|
||||
このコマンドは **現在の作業ディレクトリ**から実行され、上記の `WORKDIR /code` にて設定した `/code` ディレクトリと同じです。
|
||||
|
||||
そのためプログラムは `/code` で開始しその中にあなたのコードがある `./app` ディレクトリがあるので、**Uvicorn** は `app.main` から `app` を参照し、**インポート** することができます。
|
||||
/// tip | 豆知識
|
||||
|
||||
/// tip
|
||||
|
||||
コード内の"+"の吹き出しをクリックして、各行が何をするのかをレビューしてください。👆
|
||||
コード内の各番号バブルをクリックして、各行が何をするのかをレビューしてください。👆
|
||||
|
||||
///
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
以下で説明する通り、`CMD` 命令は**常に** **exec形式**を使用してください。
|
||||
|
||||
///
|
||||
|
||||
#### `CMD` を使う - Exec形式 { #use-cmd-exec-form }
|
||||
|
||||
Docker命令 <a href="https://docs.docker.com/reference/dockerfile/#cmd" class="external-link" target="_blank">`CMD`</a> は2つの形式で書けます:
|
||||
|
||||
✅ **Exec** 形式:
|
||||
|
||||
```Dockerfile
|
||||
# ✅ Do this
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
⛔️ **Shell** 形式:
|
||||
|
||||
```Dockerfile
|
||||
# ⛔️ Don't do this
|
||||
CMD fastapi run app/main.py --port 80
|
||||
```
|
||||
|
||||
FastAPIが正常にシャットダウンでき、[lifespan events](../advanced/events.md){.internal-link target=_blank}がトリガーされるように、常に **exec** 形式を使用してください。
|
||||
|
||||
詳しくは、<a href="https://docs.docker.com/reference/dockerfile/#shell-and-exec-form" class="external-link" target="_blank">shell形式とexec形式に関するDockerドキュメント</a>をご覧ください。
|
||||
|
||||
これは `docker compose` を使用する場合にかなり目立つことがあります。より技術的な詳細は、このDocker ComposeのFAQセクションをご覧ください:<a href="https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop" class="external-link" target="_blank">Why do my services take 10 seconds to recreate or stop?</a>。
|
||||
|
||||
#### ディレクトリ構造 { #directory-structure }
|
||||
|
||||
これで、次のようなディレクトリ構造になるはずです:
|
||||
|
||||
```
|
||||
@@ -256,17 +273,15 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
#### TLS Termination Proxyの裏側
|
||||
#### TLS Termination Proxyの裏側 { #behind-a-tls-termination-proxy }
|
||||
|
||||
Nginx や Traefik のような TLS Termination Proxy (ロードバランサ) の後ろでコンテナを動かしている場合は、`--proxy-headers`オプションを追加します。
|
||||
|
||||
このオプションは、Uvicornにプロキシ経由でHTTPSで動作しているアプリケーションに対して、送信されるヘッダを信頼するよう指示します。
|
||||
Nginx や Traefik のような TLS Termination Proxy (ロードバランサ) の後ろでコンテナを動かしている場合は、`--proxy-headers`オプションを追加します。これにより、(FastAPI CLI経由で)Uvicornに対して、そのプロキシから送信されるヘッダを信頼し、アプリケーションがHTTPSの裏で実行されていることなどを示すよう指示します。
|
||||
|
||||
```Dockerfile
|
||||
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
|
||||
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
|
||||
```
|
||||
|
||||
#### Dockerキャッシュ
|
||||
#### Dockerキャッシュ { #docker-cache }
|
||||
|
||||
この`Dockerfile`には重要なトリックがあり、まず**依存関係だけのファイル**をコピーします。その理由を説明します。
|
||||
|
||||
@@ -300,11 +315,11 @@ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
COPY ./app /code/app
|
||||
```
|
||||
|
||||
### Dockerイメージをビルドする
|
||||
### Dockerイメージをビルドする { #build-the-docker-image }
|
||||
|
||||
すべてのファイルが揃ったので、コンテナ・イメージをビルドしましょう。
|
||||
|
||||
* プロジェクトディレクトリに移動します(`Dockerfile`がある場所で、`app`ディレクトリがあります)
|
||||
* プロジェクトディレクトリに移動します(`Dockerfile`がある場所で、`app`ディレクトリがあります)。
|
||||
* FastAPI イメージをビルドします:
|
||||
|
||||
<div class="termy">
|
||||
@@ -317,7 +332,7 @@ $ docker build -t myimage .
|
||||
|
||||
</div>
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
末尾の `.` に注目してほしいです。これは `./` と同じ意味です。 これはDockerにコンテナイメージのビルドに使用するディレクトリを指示します。
|
||||
|
||||
@@ -325,7 +340,7 @@ $ docker build -t myimage .
|
||||
|
||||
///
|
||||
|
||||
### Dockerコンテナの起動する
|
||||
### Dockerコンテナの起動する { #start-the-docker-container }
|
||||
|
||||
* イメージに基づいてコンテナを実行します:
|
||||
|
||||
@@ -337,7 +352,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage
|
||||
|
||||
</div>
|
||||
|
||||
## 確認する
|
||||
## 確認する { #check-it }
|
||||
|
||||
Dockerコンテナの<a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> や <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (またはそれに相当するDockerホストを使用したもの)といったURLで確認できるはずです。
|
||||
|
||||
@@ -347,7 +362,7 @@ Dockerコンテナの<a href="http://192.168.99.100/items/5?q=somequery" class="
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
## インタラクティブなAPIドキュメント
|
||||
## インタラクティブなAPIドキュメント { #interactive-api-docs }
|
||||
|
||||
これらのURLにもアクセスできます: <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> や <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (またはそれに相当するDockerホストを使用したもの)
|
||||
|
||||
@@ -355,7 +370,7 @@ Dockerコンテナの<a href="http://192.168.99.100/items/5?q=somequery" class="
|
||||
|
||||

|
||||
|
||||
## 代替のAPIドキュメント
|
||||
## 代替のAPIドキュメント { #alternative-api-docs }
|
||||
|
||||
また、<a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> や <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (またはそれに相当するDockerホストを使用したもの)にもアクセスできます。
|
||||
|
||||
@@ -363,9 +378,10 @@ Dockerコンテナの<a href="http://192.168.99.100/items/5?q=somequery" class="
|
||||
|
||||

|
||||
|
||||
## 単一ファイルのFastAPIでDockerイメージをビルドする
|
||||
## 単一ファイルのFastAPIでDockerイメージをビルドする { #build-a-docker-image-with-a-single-file-fastapi }
|
||||
|
||||
FastAPI が単一のファイル、例えば `./app` ディレクトリのない `main.py` の場合、ファイル構造は次のようになります:
|
||||
|
||||
```
|
||||
.
|
||||
├── Dockerfile
|
||||
@@ -376,7 +392,7 @@ FastAPI が単一のファイル、例えば `./app` ディレクトリのない
|
||||
そうすれば、`Dockerfile`の中にファイルをコピーするために、対応するパスを変更するだけでよいです:
|
||||
|
||||
```{ .dockerfile .annotate hl_lines="10 13" }
|
||||
FROM python:3.9
|
||||
FROM python:3.14
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
@@ -384,43 +400,43 @@ COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (1)
|
||||
# (1)!
|
||||
COPY ./main.py /code/
|
||||
|
||||
# (2)
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
# (2)!
|
||||
CMD ["fastapi", "run", "main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
1. main.py`ファイルを `/code` ディレクトリに直接コピーします。
|
||||
1. `main.py`ファイルを `/code` ディレクトリに直接コピーします(`./app` ディレクトリなし)。
|
||||
|
||||
2. Uvicornを実行し、`main`から`app`オブジェクトをインポートするように指示します(`app.main`からインポートするのではなく)。
|
||||
2. 単一ファイル `main.py` 内のアプリケーションを配信するために `fastapi run` を使用します。
|
||||
|
||||
次にUvicornコマンドを調整して、`app.main` の代わりに新しいモジュール `main` を使用し、FastAPIオブジェクトである `app` をインポートします。
|
||||
`fastapi run` にファイルを渡すと、それがパッケージの一部ではなく単一ファイルであることを自動的に検出し、インポートしてFastAPIアプリを配信する方法を判断します。😎
|
||||
|
||||
## デプロイメントのコンセプト
|
||||
## デプロイメントのコンセプト { #deployment-concepts }
|
||||
|
||||
コンテナという観点から、[デプロイのコンセプト](concepts.md){.internal-link target=_blank}に共通するいくつかについて、もう一度説明しましょう。
|
||||
|
||||
コンテナは主に、アプリケーションの**ビルドとデプロイ**のプロセスを簡素化するためのツールですが、これらの**デプロイのコンセプト**を扱うための特定のアプローチを強制するものではないです。
|
||||
コンテナは主に、アプリケーションの**ビルドとデプロイ**のプロセスを簡素化するためのツールですが、これらの**デプロイのコンセプト**を扱うための特定のアプローチを強制するものではなく、いくつかの戦略があります。
|
||||
|
||||
**良いニュース**は、それぞれの異なる戦略には、すべてのデプロイメントのコンセプトをカバーする方法があるということです。🎉
|
||||
|
||||
これらの**デプロイメントのコンセプト**をコンテナの観点から見直してみましょう:
|
||||
|
||||
* セキュリティ - HTTPS
|
||||
* HTTPS
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* **レプリケーション(実行中のプロセス数)**
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* メモリ
|
||||
* 開始前の事前ステップ
|
||||
|
||||
## HTTPS
|
||||
## HTTPS { #https }
|
||||
|
||||
FastAPI アプリケーションの **コンテナ・イメージ**(および後で実行中の **コンテナ**)だけに焦点を当てると、通常、HTTPSは別のツールを用いて**外部で**処理されます。
|
||||
|
||||
例えば<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>のように、**HTTPS**と**証明書**の**自動**取得を扱う別のコンテナである可能性もあります。
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
TraefikはDockerやKubernetesなどと統合されているので、コンテナ用のHTTPSの設定や構成はとても簡単です。
|
||||
|
||||
@@ -428,7 +444,7 @@ TraefikはDockerやKubernetesなどと統合されているので、コンテナ
|
||||
|
||||
あるいは、(コンテナ内でアプリケーションを実行しながら)クラウド・プロバイダーがサービスの1つとしてHTTPSを処理することもできます。
|
||||
|
||||
## 起動時および再起動時の実行
|
||||
## 起動時および再起動時の実行 { #running-on-startup-and-restarts }
|
||||
|
||||
通常、コンテナの**起動と実行**を担当する別のツールがあります。
|
||||
|
||||
@@ -438,21 +454,21 @@ TraefikはDockerやKubernetesなどと統合されているので、コンテナ
|
||||
|
||||
コンテナを使わなければ、アプリケーションを起動時や再起動時に実行させるのは面倒で難しいかもしれません。しかし、**コンテナ**で作業する場合、ほとんどのケースでその機能はデフォルトで含まれています。✨
|
||||
|
||||
## レプリケーション - プロセス数
|
||||
## レプリケーション - プロセス数 { #replication-number-of-processes }
|
||||
|
||||
**Kubernetes** や Docker Swarm モード、Nomad、あるいは複数のマシン上で分散コンテナを管理するための同様の複雑なシステムを使ってマシンの<abbr title="何らかの方法で接続され、一緒に動作するように構成されたマシンのグループ">クラスター</abbr>を構成している場合、 各コンテナで(Workerを持つGunicornのような)**プロセスマネージャ**を使用する代わりに、**クラスター・レベル**で**レプリケーション**を処理したいと思うでしょう。
|
||||
**Kubernetes** や Docker Swarm モード、Nomad、あるいは複数のマシン上で分散コンテナを管理するための同様の複雑なシステムを使ってマシンの<dfn title="ある方法で接続され、連携して動作するように構成されたマシンの集まり">クラスタ</dfn>を構成している場合、 各コンテナで(Workerを持つUvicornのような)**プロセスマネージャ**を使用する代わりに、**クラスター・レベル**で**レプリケーション**を処理したいと思うでしょう。
|
||||
|
||||
Kubernetesのような分散コンテナ管理システムの1つは通常、入ってくるリクエストの**ロードバランシング**をサポートしながら、**コンテナのレプリケーション**を処理する統合された方法を持っています。このことはすべて**クラスタレベル**にてです。
|
||||
|
||||
そのような場合、UvicornワーカーでGunicornのようなものを実行するのではなく、[上記の説明](#dockerfile)のように**Dockerイメージをゼロから**ビルドし、依存関係をインストールして、**単一のUvicornプロセス**を実行したいでしょう。
|
||||
そのような場合、[上記の説明](#dockerfile)のように**Dockerイメージをゼロから**ビルドし、依存関係をインストールして、**単一のUvicornプロセス**を実行したいでしょう。複数のUvicornワーカーを使う代わりにです。
|
||||
|
||||
### ロードバランサー
|
||||
### ロードバランサー { #load-balancer }
|
||||
|
||||
コンテナを使用する場合、通常はメイン・ポート**でリスニング**しているコンポーネントがあるはずです。それはおそらく、**HTTPS**を処理するための**TLS Termination Proxy**でもある別のコンテナであったり、同様のツールであったりするでしょう。
|
||||
|
||||
このコンポーネントはリクエストの **負荷** を受け、 (うまくいけば) その負荷を**バランスよく** ワーカーに分配するので、一般に **ロードバランサ** とも呼ばれます。
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
HTTPSに使われるものと同じ**TLS Termination Proxy**コンポーネントは、おそらく**ロードバランサー**にもなるでしょう。
|
||||
|
||||
@@ -460,7 +476,7 @@ HTTPSに使われるものと同じ**TLS Termination Proxy**コンポーネン
|
||||
|
||||
そしてコンテナで作業する場合、コンテナの起動と管理に使用する同じシステムには、**ロードバランサー**(**TLS Termination Proxy**の可能性もある)から**ネットワーク通信**(HTTPリクエストなど)をアプリのあるコンテナ(複数可)に送信するための内部ツールが既にあるはずです。
|
||||
|
||||
### 1つのロードバランサー - 複数のワーカーコンテナー
|
||||
### 1つのロードバランサー - 複数のワーカーコンテナー { #one-load-balancer-multiple-worker-containers }
|
||||
|
||||
**Kubernetes**や同様の分散コンテナ管理システムで作業する場合、その内部のネットワーキングのメカニズムを使用することで、メインの**ポート**でリッスンしている単一の**ロードバランサー**が、アプリを実行している可能性のある**複数のコンテナ**に通信(リクエスト)を送信できるようになります。
|
||||
|
||||
@@ -470,56 +486,61 @@ HTTPSに使われるものと同じ**TLS Termination Proxy**コンポーネン
|
||||
|
||||
そして通常、この**ロードバランサー**は、クラスタ内の*他の*アプリケーション(例えば、異なるドメインや異なるURLパスのプレフィックスの配下)へのリクエストを処理することができ、その通信をクラスタ内で実行されている*他の*アプリケーションのための適切なコンテナに送信します。
|
||||
|
||||
### 1コンテナにつき1プロセス
|
||||
### 1コンテナにつき1プロセス { #one-process-per-container }
|
||||
|
||||
この種のシナリオでは、すでにクラスタ・レベルでレプリケーションを処理しているため、おそらくコンテナごとに**単一の(Uvicorn)プロセス**を持ちたいでしょう。
|
||||
|
||||
この場合、Uvicornワーカーを持つGunicornのようなプロセスマネージャーや、Uvicornワーカーを使うUvicornは**避けたい**でしょう。**コンテナごとにUvicornのプロセスは1つだけ**にしたいでしょう(おそらく複数のコンテナが必要でしょう)。
|
||||
この場合、例えばコマンドラインオプションの `--workers` で、コンテナ内に複数のワーカーを持つことは**避けたい**でしょう。**コンテナごとにUvicornのプロセスは1つだけ**にしたいでしょう(おそらく複数のコンテナが必要でしょう)。
|
||||
|
||||
(GunicornやUvicornがUvicornワーカーを管理するように)コンテナ内に別のプロセスマネージャーを持つことは、クラスターシステムですでに対処しているであろう**不要な複雑さ**を追加するだけです。
|
||||
(複数のワーカーの場合のように)コンテナ内に別のプロセスマネージャーを持つことは、クラスターシステムですでに対処しているであろう**不要な複雑さ**を追加するだけです。
|
||||
|
||||
### Containers with Multiple Processes and Special Cases
|
||||
### 複数プロセスのコンテナと特殊なケース { #containers-with-multiple-processes-and-special-cases }
|
||||
|
||||
もちろん、**特殊なケース**として、**Gunicornプロセスマネージャ**を持つ**コンテナ**内で複数の**Uvicornワーカープロセス**を起動させたい場合があります。
|
||||
もちろん、**特殊なケース**として、**コンテナ**内で複数の**Uvicornワーカープロセス**を起動させたい場合があります。
|
||||
|
||||
このような場合、**公式のDockerイメージ**を使用することができます。このイメージには、複数の**Uvicornワーカープロセス**を実行するプロセスマネージャとして**Gunicorn**が含まれており、現在のCPUコアに基づいてワーカーの数を自動的に調整するためのデフォルト設定がいくつか含まれています。詳しくは後述の[Gunicornによる公式Dockerイメージ - Uvicorn](#gunicorndocker-uvicorn)で説明します。
|
||||
そのような場合、`--workers` コマンドラインオプションを使って、実行したいワーカー数を設定できます:
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
FROM python:3.14
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
COPY ./app /code/app
|
||||
|
||||
# (1)!
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
|
||||
```
|
||||
|
||||
1. ここでは `--workers` コマンドラインオプションを使って、ワーカー数を4に設定しています。
|
||||
|
||||
以下は、それが理にかなっている場合の例です:
|
||||
|
||||
#### シンプルなアプリケーション
|
||||
#### シンプルなアプリ { #a-simple-app }
|
||||
|
||||
アプリケーションを**シンプル**な形で実行する場合、プロセス数の細かい調整が必要ない場合、自動化されたデフォルトを使用するだけで、コンテナ内にプロセスマネージャが必要かもしれません。例えば、公式Dockerイメージでシンプルな設定が可能です。
|
||||
アプリケーションが、クラスタではなく**単一サーバ**で実行できるほど**シンプル**である場合、コンテナ内にプロセスマネージャが欲しくなることがあります。
|
||||
|
||||
#### Docker Compose
|
||||
#### Docker Compose { #docker-compose }
|
||||
|
||||
Docker Composeで**シングルサーバ**(クラスタではない)にデプロイすることもできますので、共有ネットワークと**ロードバランシング**を維持しながら(Docker Composeで)コンテナのレプリケーションを管理する簡単な方法はないでしょう。
|
||||
Docker Composeで**単一サーバ**(クラスタではない)にデプロイすることもできますので、共有ネットワークと**ロードバランシング**を維持しながら(Docker Composeで)コンテナのレプリケーションを管理する簡単な方法はないでしょう。
|
||||
|
||||
その場合、**単一のコンテナ**で、**プロセスマネージャ**が内部で**複数のワーカープロセス**を起動するようにします。
|
||||
|
||||
#### Prometheusとその他の理由
|
||||
|
||||
また、**1つのコンテナ**に**1つのプロセス**を持たせるのではなく、**1つのコンテナ**に**複数のプロセス**を持たせる方が簡単だという**他の理由**もあるでしょう。
|
||||
|
||||
例えば、(セットアップにもよりますが)Prometheusエクスポーターのようなツールを同じコンテナ内に持つことができます。
|
||||
|
||||
この場合、**複数のコンテナ**があると、デフォルトでは、Prometheusが**メトリクスを**読みに来たとき、すべてのレプリケートされたコンテナの**蓄積されたメトリクス**を取得するのではなく、毎回**単一のコンテナ**(その特定のリクエストを処理したコンテナ)のものを取得することになります。
|
||||
|
||||
その場合、**複数のプロセス**を持つ**1つのコンテナ**を用意し、同じコンテナ上のローカルツール(例えばPrometheusエクスポーター)がすべての内部プロセスのPrometheusメトリクスを収集し、その1つのコンテナ上でそれらのメトリクスを公開する方がシンプルかもしれません。
|
||||
|
||||
---
|
||||
|
||||
重要なのは、盲目的に従わなければならない普遍のルールはないということです。
|
||||
|
||||
これらのアイデアは、**あなた自身のユースケース**を評価し、あなたのシステムに最適なアプローチを決定するために使用することができます:
|
||||
重要なのは、これらのどれも、盲目的に従わなければならない「**絶対的なルール**」ではないということです。これらのアイデアは、**あなた自身のユースケース**を評価し、あなたのシステムに最適なアプローチを決定するために使用できます。次の概念をどう管理するかを確認してください:
|
||||
|
||||
* セキュリティ - HTTPS
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* **レプリケーション(実行中のプロセス数)**
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* メモリ
|
||||
* 開始前の事前ステップ
|
||||
|
||||
## メモリー
|
||||
## メモリ { #memory }
|
||||
|
||||
コンテナごとに**単一のプロセスを実行する**と、それらのコンテナ(レプリケートされている場合は1つ以上)によって消費される多かれ少なかれ明確に定義された、安定し制限された量のメモリを持つことになります。
|
||||
|
||||
@@ -531,109 +552,47 @@ Docker Composeで**シングルサーバ**(クラスタではない)にデ
|
||||
|
||||
しかし、**多くのメモリを使用**している場合(たとえば**機械学習**モデルなど)、どれだけのメモリを消費しているかを確認し、**各マシンで実行するコンテナの数**を調整する必要があります(そしておそらくクラスタにマシンを追加します)。
|
||||
|
||||
**コンテナごとに複数のプロセス**を実行する場合(たとえば公式のDockerイメージで)、起動するプロセスの数が**利用可能なメモリ以上に消費しない**ようにする必要があります。
|
||||
**コンテナごとに複数のプロセス**を実行する場合、起動するプロセスの数が**利用可能なメモリ以上に消費しない**ようにする必要があります。
|
||||
|
||||
## 開始前の事前ステップとコンテナ
|
||||
## 開始前の事前ステップとコンテナ { #previous-steps-before-starting-and-containers }
|
||||
|
||||
コンテナ(DockerやKubernetesなど)を使っている場合、主に2つのアプローチがあります。
|
||||
|
||||
### 複数のコンテナ
|
||||
### 複数のコンテナ { #multiple-containers }
|
||||
|
||||
複数の**コンテナ**があり、おそらくそれぞれが**単一のプロセス**を実行している場合(**Kubernetes**クラスタなど)、レプリケートされたワーカーコンテナを実行する**前に**、単一のコンテナで**事前のステップ**の作業を行う**別のコンテナ**を持ちたいと思うでしょう。
|
||||
複数の**コンテナ**があり、おそらくそれぞれが**単一のプロセス**を実行している場合(例えば、**Kubernetes**クラスタなど)、レプリケートされたワーカーコンテナを実行する**前に**、単一のコンテナで**事前のステップ**の作業を行う**別のコンテナ**を持ちたいと思うでしょう。
|
||||
|
||||
/// info
|
||||
/// info | 情報
|
||||
|
||||
もしKubernetesを使用している場合, これはおそらく<a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init コンテナ</a>でしょう。
|
||||
もしKubernetesを使用している場合, これはおそらく<a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>でしょう。
|
||||
|
||||
///
|
||||
|
||||
ユースケースが事前のステップを**並列で複数回**実行するのに問題がない場合(例:データベースの準備チェック)、メインプロセスを開始する前に、それらのステップを各コンテナに入れることが可能です。
|
||||
ユースケースが事前のステップを**並列で複数回**実行するのに問題がない場合(例:データベースマイグレーションを実行するのではなく、データベースの準備ができたかをチェックするだけの場合)、メインプロセスを開始する直前に、それらのステップを各コンテナに入れることも可能です。
|
||||
|
||||
### 単一コンテナ
|
||||
### 単一コンテナ { #single-container }
|
||||
|
||||
単純なセットアップで、**単一のコンテナ**で複数の**ワーカー・プロセス**(または1つのプロセスのみ)を起動する場合、アプリでプロセスを開始する直前に、同じコンテナで事前のステップを実行できます。公式Dockerイメージは、内部的にこれをサポートしています。
|
||||
単純なセットアップで、**単一のコンテナ**で複数の**ワーカープロセス**(または1つのプロセスのみ)を起動する場合、アプリでプロセスを開始する直前に、同じコンテナで事前のステップを実行できます。
|
||||
|
||||
## Gunicornによる公式Dockerイメージ - Uvicorn
|
||||
### ベースDockerイメージ { #base-docker-image }
|
||||
|
||||
前の章で詳しく説明したように、Uvicornワーカーで動作するGunicornを含む公式のDockerイメージがあります: [Server Workers - Gunicorn と Uvicorn](server-workers.md){.internal-link target=_blank}で詳しく説明しています。
|
||||
以前は、公式のFastAPI Dockerイメージがありました:<a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>。しかし、現在は非推奨です。⛔️
|
||||
|
||||
このイメージは、主に上記で説明した状況で役に立つでしょう: [複数のプロセスと特殊なケースを持つコンテナ(Containers with Multiple Processes and Special Cases)](#containers-with-multiple-processes-and-special-cases)
|
||||
おそらく、このベースDockerイメージ(またはその他の類似のもの)は**使用しない**方がよいでしょう。
|
||||
|
||||
* <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
|
||||
すでに**Kubernetes**(または他のもの)を使用していて、複数の**コンテナ**で、クラスタレベルで**レプリケーション**を設定している場合。そのような場合は、上記で説明したように**ゼロから**イメージを構築する方がよいでしょう:[FastAPI用のDockerイメージをビルドする](#build-a-docker-image-for-fastapi)。
|
||||
|
||||
/// warning
|
||||
また、複数のワーカーが必要な場合は、単純に `--workers` コマンドラインオプションを使用できます。
|
||||
|
||||
このベースイメージや類似のイメージは**必要ない**可能性が高いので、[上記の: FastAPI用のDockerイメージをビルドする(Build a Docker Image for FastAPI)](#build-a-docker-image-for-fastapi)のようにゼロからイメージをビルドする方が良いでしょう。
|
||||
/// note | 技術詳細
|
||||
|
||||
このDockerイメージは、Uvicornが停止したワーカーの管理と再起動をサポートしていなかった頃に作成されたため、Uvicornと一緒にGunicornを使う必要がありました。これは、GunicornにUvicornワーカープロセスの管理と再起動をさせるだけのために、かなりの複雑さを追加していました。
|
||||
|
||||
しかし現在は、Uvicorn(および `fastapi` コマンド)が `--workers` をサポートしているため、自分でビルドする代わりにベースDockerイメージを使う理由はありません(コード量もだいたい同じです 😅)。
|
||||
|
||||
///
|
||||
|
||||
このイメージには、利用可能なCPUコアに基づいて**ワーカー・プロセスの数**を設定する**オートチューニング**メカニズムが含まれています。
|
||||
|
||||
これは**賢明なデフォルト**を備えていますが、**環境変数**や設定ファイルを使ってすべての設定を変更したり更新したりすることができます。
|
||||
|
||||
また、スクリプトで<a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#pre_start_path" class="external-link" target="_blank">**開始前の事前ステップ**</a>を実行することもサポートしている。
|
||||
|
||||
/// tip
|
||||
|
||||
すべての設定とオプションを見るには、Dockerイメージのページをご覧ください: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
|
||||
|
||||
///
|
||||
|
||||
### 公式Dockerイメージのプロセス数
|
||||
|
||||
このイメージの**プロセス数**は、利用可能なCPU**コア**から**自動的に計算**されます。
|
||||
|
||||
つまり、CPUから可能な限り**パフォーマンス**を**引き出そう**とします。
|
||||
|
||||
また、**環境変数**などを使った設定で調整することもできます。
|
||||
|
||||
しかし、プロセスの数はコンテナが実行しているCPUに依存するため、**消費されるメモリの量**もそれに依存することになります。
|
||||
|
||||
そのため、(機械学習モデルなどで)大量のメモリを消費するアプリケーションで、サーバーのCPUコアが多いが**メモリが少ない**場合、コンテナは利用可能なメモリよりも多くのメモリを使おうとすることになります。
|
||||
|
||||
その結果、パフォーマンスが大幅に低下する(あるいはクラッシュする)可能性があります。🚨
|
||||
|
||||
### Dockerfileを作成する
|
||||
|
||||
この画像に基づいて`Dockerfile`を作成する方法を以下に示します:
|
||||
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
|
||||
|
||||
COPY ./requirements.txt /app/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
||||
|
||||
COPY ./app /app
|
||||
```
|
||||
|
||||
### より大きなアプリケーション
|
||||
|
||||
[複数のファイルを持つ大きなアプリケーション](../tutorial/bigger-applications.md){.internal-link target=_blank}を作成するセクションに従った場合、`Dockerfile`は次のようになります:
|
||||
|
||||
```Dockerfile hl_lines="7"
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
|
||||
|
||||
COPY ./requirements.txt /app/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
||||
|
||||
COPY ./app /app/app
|
||||
```
|
||||
|
||||
### いつ使うのか
|
||||
|
||||
おそらく、**Kubernetes**(または他のもの)を使用していて、すでにクラスタレベルで複数の**コンテナ**で**レプリケーション**を設定している場合は、この公式ベースイメージ(または他の類似のもの)は**使用すべきではありません**。
|
||||
|
||||
そのような場合は、上記のように**ゼロから**イメージを構築する方がよいでしょう: [FastAPI用のDockerイメージをビルドする(Build a Docker Image for FastAPI)](#build-a-docker-image-for-fastapi) を参照してください。
|
||||
|
||||
このイメージは、主に上記の[複数のプロセスと特殊なケースを持つコンテナ(Containers with Multiple Processes and Special Cases)](#containers-with-multiple-processes-and-special-cases)で説明したような特殊なケースで役に立ちます。
|
||||
|
||||
例えば、アプリケーションが**シンプル**で、CPUに応じたデフォルトのプロセス数を設定すればうまくいく場合や、クラスタレベルでレプリケーションを手動で設定する手間を省きたい場合、アプリで複数のコンテナを実行しない場合などです。
|
||||
|
||||
または、**Docker Compose**でデプロイし、単一のサーバで実行している場合などです。
|
||||
|
||||
## コンテナ・イメージのデプロイ
|
||||
## コンテナ・イメージのデプロイ { #deploy-the-container-image }
|
||||
|
||||
コンテナ(Docker)イメージを手に入れた後、それをデプロイするにはいくつかの方法があります。
|
||||
|
||||
@@ -645,104 +604,21 @@ COPY ./app /app/app
|
||||
* Nomadのような別のツール
|
||||
* コンテナ・イメージをデプロイするクラウド・サービス
|
||||
|
||||
## Poetryを利用したDockerイメージ
|
||||
## `uv` を使ったDockerイメージ { #docker-image-with-uv }
|
||||
|
||||
もしプロジェクトの依存関係を管理するために<a href="https://python-poetry.org/" class="external-link" target="_blank">Poetry</a>を利用する場合、マルチステージビルドを使うと良いでしょう。
|
||||
<a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a> を使ってプロジェクトのインストールと管理をしている場合は、<a href="https://docs.astral.sh/uv/guides/integration/docker/" class="external-link" target="_blank">uv Docker guide</a>に従ってください。
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
# (1)
|
||||
FROM python:3.9 as requirements-stage
|
||||
|
||||
# (2)
|
||||
WORKDIR /tmp
|
||||
|
||||
# (3)
|
||||
RUN pip install poetry
|
||||
|
||||
# (4)
|
||||
COPY ./pyproject.toml ./poetry.lock* /tmp/
|
||||
|
||||
# (5)
|
||||
RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
|
||||
|
||||
# (6)
|
||||
FROM python:3.9
|
||||
|
||||
# (7)
|
||||
WORKDIR /code
|
||||
|
||||
# (8)
|
||||
COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt
|
||||
|
||||
# (9)
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
|
||||
# (10)
|
||||
COPY ./app /code/app
|
||||
|
||||
# (11)
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
1. これは最初のステージで、`requirements-stage`と名付けられます
|
||||
2. `/tmp` を現在の作業ディレクトリに設定します
|
||||
ここで `requirements.txt` というファイルを生成します。
|
||||
|
||||
3. このDockerステージにPoetryをインストールします
|
||||
|
||||
4. pyproject.toml`と`poetry.lock`ファイルを`/tmp` ディレクトリにコピーします
|
||||
|
||||
`./poetry.lock*`(末尾に`*`)を使用するため、そのファイルがまだ利用できない場合でもクラッシュすることはないです。
|
||||
5. requirements.txt`ファイルを生成します
|
||||
|
||||
6. これは最後のステージであり、ここにあるものはすべて最終的なコンテナ・イメージに保存されます
|
||||
7. 現在の作業ディレクトリを `/code` に設定します
|
||||
8. `requirements.txt`ファイルを `/code` ディレクトリにコピーします
|
||||
このファイルは前のDockerステージにしか存在しないため、`--from-requirements-stage`を使ってコピーします。
|
||||
9. 生成された `requirements.txt` ファイルにあるパッケージの依存関係をインストールします
|
||||
10. app` ディレクトリを `/code` ディレクトリにコピーします
|
||||
11. uvicorn` コマンドを実行して、`app.main` からインポートした `app` オブジェクトを使用するように指示します
|
||||
/// tip
|
||||
|
||||
"+"の吹き出しをクリックすると、それぞれの行が何をするのかを見ることができます
|
||||
|
||||
///
|
||||
|
||||
**Dockerステージ**は`Dockerfile`の一部で、**一時的なコンテナイメージ**として動作します。
|
||||
|
||||
最初のステージは **Poetryのインストール**と Poetry の `pyproject.toml` ファイルからプロジェクトの依存関係を含む**`requirements.txt`を生成**するためだけに使用されます。
|
||||
|
||||
この `requirements.txt` ファイルは後半の **次のステージ**で `pip` と共に使用されます。
|
||||
|
||||
最終的なコンテナイメージでは、**最終ステージ**のみが保存されます。前のステージは破棄されます。
|
||||
|
||||
Poetryを使用する場合、**Dockerマルチステージビルド**を使用することは理にかなっています。
|
||||
|
||||
なぜなら、最終的なコンテナイメージにPoetryとその依存関係がインストールされている必要はなく、**必要なのは**プロジェクトの依存関係をインストールするために生成された `requirements.txt` ファイルだけだからです。
|
||||
|
||||
そして次の(そして最終的な)ステージでは、前述とほぼ同じ方法でイメージをビルドします。
|
||||
|
||||
### TLS Termination Proxyの裏側 - Poetry
|
||||
|
||||
繰り返しになりますが、NginxやTraefikのようなTLS Termination Proxy(ロードバランサー)の後ろでコンテナを動かしている場合は、`--proxy-headers`オプションをコマンドに追加します:
|
||||
|
||||
```Dockerfile
|
||||
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
|
||||
```
|
||||
|
||||
## まとめ
|
||||
## まとめ { #recap }
|
||||
|
||||
コンテナ・システム(例えば**Docker**や**Kubernetes**など)を使えば、すべての**デプロイメントのコンセプト**を扱うのがかなり簡単になります:
|
||||
|
||||
* セキュリティ - HTTPS
|
||||
* HTTPS
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
* **レプリケーション(実行中のプロセス数)**
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* メモリ
|
||||
* 開始前の事前ステップ
|
||||
|
||||
ほとんどの場合、ベースとなるイメージは使用せず、公式のPython Dockerイメージをベースにした**コンテナイメージをゼロからビルド**します。
|
||||
|
||||
`Dockerfile`と**Dockerキャッシュ**内の命令の**順番**に注意することで、**ビルド時間を最小化**することができ、生産性を最大化することができます(そして退屈を避けることができます)。😎
|
||||
|
||||
特別なケースでは、FastAPI用の公式Dockerイメージを使いたいかもしれません。🤓
|
||||
`Dockerfile`と**Dockerキャッシュ**内の命令の**順番**に注意することで、**ビルド時間を最小化**し、生産性を最大化できます(そして退屈を避けることができます)。😎
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# FastAPI Cloud { #fastapi-cloud }
|
||||
|
||||
<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> に **コマンド1つ** でデプロイできます。まだならウェイティングリストにご登録ください。🚀
|
||||
|
||||
## ログイン { #login }
|
||||
|
||||
すでに **FastAPI Cloud** アカウントをお持ちであることを確認してください(ウェイティングリストからご招待しています 😉)。
|
||||
|
||||
次にログインします:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## デプロイ { #deploy }
|
||||
|
||||
では、**コマンド1つ** でアプリをデプロイします:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi deploy
|
||||
|
||||
Deploying to FastAPI Cloud...
|
||||
|
||||
✅ Deployment successful!
|
||||
|
||||
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
以上です!その URL からアプリにアクセスできます。✨
|
||||
|
||||
## FastAPI Cloud について { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** は、**FastAPI** の作者とチームによって開発されています。
|
||||
|
||||
最小限の手間で API を**構築**・**デプロイ**・**利用**できるように工程を簡素化します。
|
||||
|
||||
FastAPI での開発と同じ**開発者体験**を、クラウドへの**デプロイ**にももたらします。🎉
|
||||
|
||||
さらに、アプリのデプロイ時に必要となる多くの事項も任せられます。例えば:
|
||||
|
||||
* HTTPS
|
||||
* レプリケーション(リクエストに基づくオートスケーリング付き)
|
||||
* など
|
||||
|
||||
FastAPI Cloud は、*FastAPI and friends* のオープンソースプロジェクトに対する主要スポンサーかつ資金提供元です。✨
|
||||
|
||||
## 他のクラウドプロバイダーへのデプロイ { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI はオープンソースで標準に基づいています。お好みの任意のクラウドプロバイダーに FastAPI アプリをデプロイできます。
|
||||
|
||||
各クラウドプロバイダーのガイドに従って FastAPI アプリをデプロイしてください。🤓
|
||||
|
||||
## 自分のサーバーへのデプロイ { #deploy-your-own-server }
|
||||
|
||||
この**デプロイ**ガイドの後半では詳細も解説します。何が起きているのか、何が必要なのか、そして自分のサーバーを含めて FastAPI アプリを自力でデプロイする方法が分かるようになります。🤓
|
||||
@@ -1,10 +1,10 @@
|
||||
# HTTPS について
|
||||
# HTTPS について { #about-https }
|
||||
|
||||
HTTPSは単に「有効」か「無効」かで決まるものだと思いがちです。
|
||||
|
||||
しかし、それよりもはるかに複雑です。
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
もし急いでいたり、HTTPSの仕組みについて気にしないのであれば、次のセクションに進み、さまざまなテクニックを使ってすべてをセットアップするステップ・バイ・ステップの手順をご覧ください。
|
||||
|
||||
@@ -22,25 +22,19 @@ HTTPSは単に「有効」か「無効」かで決まるものだと思いがち
|
||||
* 接続の暗号化は**TCPレベル**で行われます。
|
||||
* それは**HTTPの1つ下**のレイヤーです。
|
||||
* つまり、**証明書と暗号化**の処理は、**HTTPの前**に行われます。
|
||||
* **TCPは "ドメイン "について知りません**。IPアドレスについてのみ知っています。
|
||||
* **TCPは「ドメイン」について知りません**。IPアドレスについてのみ知っています。
|
||||
* 要求された**特定のドメイン**に関する情報は、**HTTPデータ**に入ります。
|
||||
* **HTTPS証明書**は、**特定のドメイン**を「証明」しますが、プロトコルと暗号化はTCPレベルで行われ、どのドメインが扱われているかを**知る前**に行われます。
|
||||
* **デフォルトでは**、**IPアドレスごとに1つのHTTPS証明書**しか持てないことになります。
|
||||
* これは、サーバーの規模やアプリケーションの規模に寄りません。
|
||||
* しかし、これには**解決策**があります。
|
||||
* **TLS**プロトコル(HTTPの前に、TCPレベルで暗号化を処理するもの)には、**<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="サーバー名表示">SNI</abbr></a>**と呼ばれる**拡張**があります。
|
||||
* **TLS**プロトコル(HTTPの前に、TCPレベルで暗号化を処理するもの)には、**<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication - サーバー名表示">SNI</abbr></a>**と呼ばれる**拡張**があります。
|
||||
* このSNI拡張機能により、1つのサーバー(**単一のIPアドレス**を持つ)が**複数のHTTPS証明書**を持ち、**複数のHTTPSドメイン/アプリケーション**にサービスを提供できるようになります。
|
||||
* これが機能するためには、**パブリックIPアドレス**でリッスンしている、サーバー上で動作している**単一の**コンポーネント(プログラム)が、サーバー内の**すべてのHTTPS証明書**を持っている必要があります。
|
||||
|
||||
* セキュアな接続を取得した**後**でも、通信プロトコルは**HTTPのまま**です。
|
||||
* コンテンツは**HTTPプロトコル**で送信されているにもかかわらず、**暗号化**されています。
|
||||
|
||||
|
||||
サーバー(マシン、ホストなど)上で**1つのプログラム/HTTPサーバー**を実行させ、**HTTPSに関する全てのこと**を管理するのが一般的です。
|
||||
|
||||
**暗号化された HTTPS リクエスト** を受信し、**復号化された HTTP リクエスト** を同じサーバーで実行されている実際の HTTP アプリケーション(この場合は **FastAPI** アプリケーション)に送信し、アプリケーションから **HTTP レスポンス** を受け取り、適切な **HTTPS 証明書** を使用して **暗号化** し、そして**HTTPS** を使用してクライアントに送り返します。
|
||||
|
||||
このサーバーはしばしば **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">TLS Termination Proxy</a>**と呼ばれます。
|
||||
サーバー(マシン、ホストなど)上で**1つのプログラム/HTTPサーバー**を実行させ、**HTTPSに関する全てのこと**を管理するのが一般的です。**暗号化された HTTPS リクエスト** を受信し、**復号化された HTTP リクエスト** を同じサーバーで実行されている実際の HTTP アプリケーション(この場合は **FastAPI** アプリケーション)に送信し、アプリケーションから **HTTP レスポンス** を受け取り、適切な **HTTPS 証明書** を使用して **暗号化** し、そして**HTTPS** を使用してクライアントに送り返します。このサーバーはしばしば **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">TLS Termination Proxy</a>**と呼ばれます。
|
||||
|
||||
TLS Termination Proxyとして使えるオプションには、以下のようなものがあります:
|
||||
|
||||
@@ -50,7 +44,7 @@ TLS Termination Proxyとして使えるオプションには、以下のよう
|
||||
* HAProxy
|
||||
|
||||
|
||||
## Let's Encrypt
|
||||
## Let's Encrypt { #lets-encrypt }
|
||||
|
||||
Let's Encrypt以前は、これらの**HTTPS証明書**は信頼できる第三者によって販売されていました。
|
||||
|
||||
@@ -64,27 +58,27 @@ Let's Encrypt以前は、これらの**HTTPS証明書**は信頼できる第三
|
||||
|
||||
このアイデアは、これらの証明書の取得と更新を自動化することで、**安全なHTTPSを、無料で、永遠に**利用できるようにすることです。
|
||||
|
||||
## 開発者のための HTTPS
|
||||
## 開発者のための HTTPS { #https-for-developers }
|
||||
|
||||
ここでは、HTTPS APIがどのように見えるかの例を、主に開発者にとって重要なアイデアに注意を払いながら、ステップ・バイ・ステップで説明します。
|
||||
|
||||
### ドメイン名
|
||||
### ドメイン名 { #domain-name }
|
||||
|
||||
ステップの初めは、**ドメイン名**を**取得すること**から始まるでしょう。その後、DNSサーバー(おそらく同じクラウドプロバイダー)に設定します。
|
||||
|
||||
おそらくクラウドサーバー(仮想マシン)かそれに類するものを手に入れ、<abbr title="変わらない">固定の</abbr> **パブリックIPアドレス**を持つことになるでしょう。
|
||||
おそらくクラウドサーバー(仮想マシン)かそれに類するものを手に入れ、<dfn title="時間とともに変化しない。動的ではない。">固定の</dfn> **パブリックIPアドレス**を持つことになるでしょう。
|
||||
|
||||
DNSサーバーでは、**取得したドメイン**をあなたのサーバーのパプリック**IPアドレス**に向けるレコード(「`Aレコード`」)を設定します。
|
||||
DNSサーバーでは、**取得したドメイン**をあなたのサーバーのパプリック**IPアドレス**に向けるレコード(「`A record`」)を設定します。
|
||||
|
||||
これはおそらく、最初の1回だけあり、すべてをセットアップするときに行うでしょう。
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
ドメイン名の話はHTTPSに関する話のはるか前にありますが、すべてがドメインとIPアドレスに依存するため、ここで言及する価値があります。
|
||||
|
||||
///
|
||||
|
||||
### DNS
|
||||
### DNS { #dns }
|
||||
|
||||
では、実際のHTTPSの部分に注目してみよう。
|
||||
|
||||
@@ -94,7 +88,7 @@ DNSサーバーは、ブラウザに特定の**IPアドレス**を使用する
|
||||
|
||||
<img src="/img/deployment/https/https01.drawio.svg">
|
||||
|
||||
### TLS Handshake の開始
|
||||
### TLS Handshake の開始 { #tls-handshake-start }
|
||||
|
||||
ブラウザはIPアドレスと**ポート443**(HTTPSポート)で通信します。
|
||||
|
||||
@@ -104,7 +98,7 @@ DNSサーバーは、ブラウザに特定の**IPアドレス**を使用する
|
||||
|
||||
TLS接続を確立するためのクライアントとサーバー間のこのやりとりは、**TLSハンドシェイク**と呼ばれます。
|
||||
|
||||
### SNI拡張機能付きのTLS
|
||||
### SNI拡張機能付きのTLS { #tls-with-sni-extension }
|
||||
|
||||
サーバー内の**1つのプロセス**だけが、特定 の**IPアドレス**の特定の**ポート** で待ち受けることができます。
|
||||
|
||||
@@ -112,7 +106,7 @@ TLS接続を確立するためのクライアントとサーバー間のこの
|
||||
|
||||
TLS(HTTPS)はデフォルトで`443`という特定のポートを使用する。つまり、これが必要なポートです。
|
||||
|
||||
このポートをリッスンできるのは1つのプロセスだけなので、これを実行するプロセスは**TLS Termination Proxy**となります。
|
||||
このポートをリクエストできるのは1つのプロセスだけなので、これを実行するプロセスは**TLS Termination Proxy**となります。
|
||||
|
||||
TLS Termination Proxyは、1つ以上の**TLS証明書**(HTTPS証明書)にアクセスできます。
|
||||
|
||||
@@ -130,13 +124,13 @@ TLS Termination Proxyは、1つ以上の**TLS証明書**(HTTPS証明書)に
|
||||
|
||||
これが**HTTPS**であり、純粋な(暗号化されていない)TCP接続ではなく、**セキュアなTLS接続**の中に**HTTP**があるだけです。
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
通信の暗号化は、HTTPレベルではなく、**TCPレベル**で行われることに注意してください。
|
||||
|
||||
///
|
||||
|
||||
### HTTPS リクエスト
|
||||
### HTTPS リクエスト { #https-request }
|
||||
|
||||
これでクライアントとサーバー(具体的にはブラウザとTLS Termination Proxy)は**暗号化されたTCP接続**を持つことになり、**HTTP通信**を開始することができます。
|
||||
|
||||
@@ -144,19 +138,19 @@ TLS Termination Proxyは、1つ以上の**TLS証明書**(HTTPS証明書)に
|
||||
|
||||
<img src="/img/deployment/https/https04.drawio.svg">
|
||||
|
||||
### リクエストの復号化
|
||||
### リクエストの復号化 { #decrypt-the-request }
|
||||
|
||||
TLS Termination Proxy は、合意が取れている暗号化を使用して、**リクエストを復号化**し、**プレーン (復号化された) HTTP リクエスト** をアプリケーションを実行しているプロセス (例えば、FastAPI アプリケーションを実行している Uvicorn を持つプロセス) に送信します。
|
||||
|
||||
<img src="/img/deployment/https/https05.drawio.svg">
|
||||
|
||||
### HTTP レスポンス
|
||||
### HTTP レスポンス { #http-response }
|
||||
|
||||
アプリケーションはリクエストを処理し、**プレーン(暗号化されていない)HTTPレスポンス** をTLS Termination Proxyに送信します。
|
||||
|
||||
<img src="/img/deployment/https/https06.drawio.svg">
|
||||
|
||||
### HTTPS レスポンス
|
||||
### HTTPS レスポンス { #https-response }
|
||||
|
||||
TLS Termination Proxyは次に、事前に合意が取れている暗号(`someapp.example.com`の証明書から始まる)を使って**レスポンスを暗号化し**、ブラウザに送り返す。
|
||||
|
||||
@@ -166,7 +160,7 @@ TLS Termination Proxyは次に、事前に合意が取れている暗号(`someap
|
||||
|
||||
クライアント(ブラウザ)は、レスポンスが正しいサーバーから来たことを知ることができます。 なぜなら、そのサーバーは、以前に**HTTPS証明書**を使って合意した暗号を使っているからです。
|
||||
|
||||
### 複数のアプリケーション
|
||||
### 複数のアプリケーション { #multiple-applications }
|
||||
|
||||
同じサーバー(または複数のサーバー)に、例えば他のAPIプログラムやデータベースなど、**複数のアプリケーション**が存在する可能性があります。
|
||||
|
||||
@@ -176,7 +170,7 @@ TLS Termination Proxyは次に、事前に合意が取れている暗号(`someap
|
||||
|
||||
そうすれば、TLS Termination Proxy は、**複数のドメイン**や複数のアプリケーションのHTTPSと証明書を処理し、それぞれのケースで適切なアプリケーションにリクエストを送信することができます。
|
||||
|
||||
### 証明書の更新
|
||||
### 証明書の更新 { #certificate-renewal }
|
||||
|
||||
将来のある時点で、各証明書は(取得後約3ヶ月で)**失効**します。
|
||||
|
||||
@@ -200,10 +194,42 @@ TLS Termination Proxyは次に、事前に合意が取れている暗号(`someap
|
||||
|
||||
アプリを提供しながらこのような更新処理を行うことは、アプリケーション・サーバー(Uvicornなど)でTLS証明書を直接使用するのではなく、TLS Termination Proxyを使用して**HTTPSを処理する別のシステム**を用意したくなる主な理由の1つです。
|
||||
|
||||
## まとめ
|
||||
## プロキシ転送ヘッダー { #proxy-forwarded-headers }
|
||||
|
||||
プロキシを使ってHTTPSを処理する場合、**アプリケーションサーバー**(たとえばFastAPI CLI経由のUvicorn)はHTTPS処理について何も知らず、**TLS Termination Proxy**とはプレーンなHTTPで通信します。
|
||||
|
||||
この**プロキシ**は通常、リクエストを**アプリケーションサーバー**に転送する前に、その場でいくつかのHTTPヘッダーを設定し、リクエストがプロキシによって**転送**されていることをアプリケーションサーバーに知らせます。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
プロキシヘッダーは次のとおりです:
|
||||
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
|
||||
|
||||
///
|
||||
|
||||
それでも、**アプリケーションサーバー**は信頼できる**プロキシ**の背後にあることを知らないため、デフォルトではそれらのヘッダーを信頼しません。
|
||||
|
||||
しかし、**アプリケーションサーバー**が**プロキシ**から送信される*forwarded*ヘッダーを信頼するように設定できます。FastAPI CLIを使用している場合は、*CLI Option* `--forwarded-allow-ips` を使って、どのIPからの*forwarded*ヘッダーを信頼すべきかを指定できます。
|
||||
|
||||
たとえば、**アプリケーションサーバー**が信頼できる**プロキシ**からの通信のみを受け取っている場合、`--forwarded-allow-ips="*"` に設定して、受信するすべてのIPを信頼するようにできます。受け取るリクエストは、**プロキシ**が使用するIPからのものだけになるためです。
|
||||
|
||||
こうすることで、アプリケーションは、HTTPSを使用しているかどうか、ドメインなど、自身のパブリックURLが何であるかを把握できるようになります。
|
||||
|
||||
これは、たとえばリダイレクトを適切に処理するのに便利です。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これについては、[Behind a Proxy - Enable Proxy Forwarded Headers](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank} のドキュメントで詳しく学べます。
|
||||
|
||||
///
|
||||
|
||||
## まとめ { #recap }
|
||||
|
||||
**HTTPS**を持つことは非常に重要であり、ほとんどの場合、かなり**クリティカル**です。開発者として HTTPS に関わる労力のほとんどは、これらの**概念とその仕組みを理解する**ことです。
|
||||
|
||||
しかし、ひとたび**開発者向けHTTPS**の基本的な情報を知れば、簡単な方法ですべてを管理するために、さまざまなツールを組み合わせて設定することができます。
|
||||
|
||||
次の章では、**FastAPI** アプリケーションのために **HTTPS** をセットアップする方法について、いくつかの具体例を紹介します。🔒
|
||||
次の章のいくつかでは、**FastAPI** アプリケーションのために **HTTPS** をセットアップする方法について、いくつかの具体例を紹介します。🔒
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
# デプロイ
|
||||
# デプロイ { #deployment }
|
||||
|
||||
**FastAPI** 製のアプリケーションは比較的容易にデプロイできます。
|
||||
**FastAPI** アプリケーションのデプロイは比較的簡単です。
|
||||
|
||||
ユースケースや使用しているツールによっていくつかの方法に分かれます。
|
||||
## デプロイとは { #what-does-deployment-mean }
|
||||
|
||||
次のセクションでより詳しくそれらの方法について説明します。
|
||||
アプリケーションを**デプロイ**するとは、**ユーザーが利用できるようにする**ために必要な手順を実行することを意味します。
|
||||
|
||||
**Web API** の場合、通常は **リモートマシン** 上に配置し、優れたパフォーマンス、安定性などを提供する **サーバープログラム** と組み合わせて、**ユーザー** が中断や問題なく効率的にアプリケーションへ**アクセス**できるようにします。
|
||||
|
||||
これは **開発** 段階とは対照的です。開発では、コードを常に変更し、壊しては直し、開発サーバーを停止したり再起動したりします。
|
||||
|
||||
## デプロイ戦略 { #deployment-strategies }
|
||||
|
||||
具体的なユースケースや使用するツールによって、いくつかの方法があります。
|
||||
|
||||
複数のツールを組み合わせて自分で**サーバーをデプロイ**することもできますし、作業の一部を代行してくれる **クラウドサービス** を使うこともできます。ほかにも選択肢があります。
|
||||
|
||||
たとえば、FastAPI の開発チームである私たちは、クラウドへの FastAPI アプリのデプロイを可能な限り合理化し、FastAPI を使って開発するのと同じ開発者体験を提供するために、<a href="https://fastapicloud.com" class="external-link" target="_blank">**FastAPI Cloud**</a> を構築しました。
|
||||
|
||||
**FastAPI** アプリケーションをデプロイする際に、おそらく念頭に置くべき主要な概念をいくつか紹介します(ただし、そのほとんどは他の種類の Web アプリケーションにも当てはまります)。
|
||||
|
||||
次のセクションでは、留意すべき点の詳細や、それを実現するためのいくつかの手法を確認します。 ✨
|
||||
|
||||
@@ -1,12 +1,82 @@
|
||||
# 手動デプロイ
|
||||
# サーバーを手動で実行する { #run-a-server-manually }
|
||||
|
||||
**FastAPI** を手動でデプロイすることもできます。
|
||||
## fastapi run コマンドを使う { #use-the-fastapi-run-command }
|
||||
|
||||
以下の様なASGI対応のサーバをインストールする必要があります:
|
||||
結論として、FastAPI アプリケーションを提供するには `fastapi run` を使います:
|
||||
|
||||
//// tab | Uvicorn
|
||||
<div class="termy">
|
||||
|
||||
* <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a>, uvloopとhttptoolsを基にした高速なASGIサーバ。
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting production server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>2306215</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
これでほとんどのケースは動作します。😎
|
||||
|
||||
このコマンドは、たとえばコンテナやサーバー内で **FastAPI** アプリを起動するのに使えます。
|
||||
|
||||
## ASGIサーバー { #asgi-servers }
|
||||
|
||||
少し詳しく見ていきます。
|
||||
|
||||
FastAPI は、Python の Web フレームワークとサーバーのための標準である <abbr title="Asynchronous Server Gateway Interface - 非同期サーバーゲートウェイインターフェース">ASGI</abbr> を使います。FastAPI は ASGI Web フレームワークです。
|
||||
|
||||
リモートのサーバーマシンで **FastAPI** アプリケーション(や他の ASGI アプリケーション)を実行するのに主に必要なのは **Uvicorn** のような ASGI サーバープログラムです。これは `fastapi` コマンドにデフォルトで含まれています。
|
||||
|
||||
他にもいくつかの選択肢があります:
|
||||
|
||||
* <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a>: 高性能な ASGI サーバー。
|
||||
* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a>: HTTP/2 や Trio に対応する ASGI サーバーなど。
|
||||
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a>: Django Channels のために作られた ASGI サーバー。
|
||||
* <a href="https://github.com/emmett-framework/granian" class="external-link" target="_blank">Granian</a>: Python アプリケーション向けの Rust 製 HTTP サーバー。
|
||||
* <a href="https://unit.nginx.org/howto/fastapi/" class="external-link" target="_blank">NGINX Unit</a>: 軽量で多用途な Web アプリケーションランタイム。
|
||||
|
||||
## サーバーマシンとサーバープログラム { #server-machine-and-server-program }
|
||||
|
||||
名称に関する小さな注意点があります。💡
|
||||
|
||||
「サーバー」という言葉は、リモート/クラウド上のコンピュータ(物理/仮想マシン)と、そのマシン上で動作しているプログラム(例: Uvicorn)の両方を指すのに一般的に使われます。
|
||||
|
||||
一般に「サーバー」と書かれているときは、そのどちらかを指している可能性があることを覚えておいてください。
|
||||
|
||||
リモートマシンを指す場合、「サーバー」のほか「マシン」「VM(仮想マシン)」「ノード」などとも呼ばれます。いずれも通常 Linux を実行し、そこでプログラムを動かすリモートマシンを指します。
|
||||
|
||||
## サーバープログラムをインストール { #install-the-server-program }
|
||||
|
||||
FastAPI をインストールすると、本番サーバーの Uvicorn が同梱されており、`fastapi run` コマンドで起動できます。
|
||||
|
||||
ただし、ASGI サーバーを手動でインストールすることもできます。
|
||||
|
||||
[仮想環境](../virtual-environments.md){.internal-link target=_blank}を作成して有効化し、サーバーアプリケーションをインストールしてください。
|
||||
|
||||
例として、Uvicorn をインストールするには:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -18,37 +88,21 @@ $ pip install "uvicorn[standard]"
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
他の ASGI サーバープログラムでも同様の手順です。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`standard` を加えることで、Uvicornがインストールされ、いくつかの推奨される依存関係を利用するようになります。
|
||||
`standard` を付けると、Uvicorn は推奨の追加依存関係もインストールして使用します。
|
||||
|
||||
これには、`asyncio` の高性能な完全互換品である `uvloop` が含まれ、並行処理のパフォーマンスが大幅に向上します。
|
||||
その中には、`asyncio` の高性能なドロップイン代替であり、大きな並行実行性能の向上をもたらす `uvloop` も含まれます。
|
||||
|
||||
`pip install "fastapi[standard]"` のように FastAPI をインストールした場合は、すでに `uvicorn[standard]` も含まれます。
|
||||
|
||||
///
|
||||
|
||||
//// tab | Hypercorn
|
||||
## サーバープログラムを起動 { #run-the-server-program }
|
||||
|
||||
* <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, HTTP/2にも対応しているASGIサーバ。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install hypercorn
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
...または、これら以外のASGIサーバ。
|
||||
|
||||
////
|
||||
|
||||
そして、チュートリアルと同様な方法でアプリケーションを起動して下さい。ただし、以下の様に`--reload` オプションは使用しないで下さい:
|
||||
|
||||
//// tab | Uvicorn
|
||||
ASGI サーバーを手動でインストールした場合、通常は FastAPI アプリケーションをインポートさせるために、特別な形式のインポート文字列を渡す必要があります:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -60,26 +114,44 @@ $ uvicorn main:app --host 0.0.0.0 --port 80
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
/// note | 備考
|
||||
|
||||
//// tab | Hypercorn
|
||||
`uvicorn main:app` というコマンドは次を指します:
|
||||
|
||||
<div class="termy">
|
||||
* `main`: ファイル `main.py`(Python の「モジュール」)。
|
||||
* `app`: `main.py` 内で `app = FastAPI()` により作成されたオブジェクト。
|
||||
|
||||
```console
|
||||
$ hypercorn main:app --bind 0.0.0.0:80
|
||||
これは次と等価です:
|
||||
|
||||
Running on 0.0.0.0:8080 over http (CTRL + C to quit)
|
||||
```Python
|
||||
from main import app
|
||||
```
|
||||
|
||||
</div>
|
||||
///
|
||||
|
||||
////
|
||||
他の ASGI サーバープログラムでも同様のコマンドがあり、詳細はそれぞれのドキュメントを参照してください。
|
||||
|
||||
停止した場合に自動的に再起動させるツールを設定したいかもしれません。
|
||||
/// warning | 注意
|
||||
|
||||
さらに、<a href="https://gunicorn.org/" class="external-link" target="_blank">Gunicorn</a>をインストールして<a href="https://www.uvicorn.dev/#running-with-gunicorn" class="external-link" target="_blank">Uvicornのマネージャーとして使用したり</a>、複数のワーカーでHypercornを使用したいかもしれません。
|
||||
Uvicorn などのサーバーは、開発時に便利な `--reload` オプションをサポートしています。
|
||||
|
||||
ワーカー数などの微調整も行いたいかもしれません。
|
||||
しかし `--reload` は多くのリソースを消費し、不安定になるなどの性質があります。
|
||||
|
||||
しかしこれら全てをやろうとすると、自動的にこれらを行うDockerイメージを使う方が楽かもしれません。
|
||||
開発中には非常に役立ちますが、 本番環境では使用すべきではありません。
|
||||
|
||||
///
|
||||
|
||||
## デプロイの概念 { #deployment-concepts }
|
||||
|
||||
これらの例は、サーバープログラム(例: Uvicorn)を実行し、事前に決めたポート(例: `80`)で、すべての IP(`0.0.0.0`)をリッスンする「単一プロセス」を起動します。
|
||||
|
||||
これが基本的な考え方です。ただし、次のような追加事項にも対応したくなるでしょう:
|
||||
|
||||
* セキュリティ - HTTPS
|
||||
* 起動時に実行
|
||||
* 再起動
|
||||
* レプリケーション(実行プロセス数)
|
||||
* メモリ
|
||||
* 起動前の事前ステップ
|
||||
|
||||
これらの各概念についての考え方や、対処するための具体例・戦略を次の章で説明します。🚀
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Server Workers - Gunicorn と Uvicorn
|
||||
# Server Workers - ワーカー付きUvicorn { #server-workers-uvicorn-with-workers }
|
||||
|
||||
前回のデプロイメントのコンセプトを振り返ってみましょう:
|
||||
|
||||
@@ -9,124 +9,79 @@
|
||||
* メモリ
|
||||
* 開始前の事前ステップ
|
||||
|
||||
ここまでのドキュメントのチュートリアルでは、おそらくUvicornのような**サーバープログラム**を**単一のプロセス**で実行しています。
|
||||
ここまでのドキュメントのチュートリアルでは、おそらく `fastapi` コマンドなど(Uvicornを実行するもの)を使って、**単一のプロセス**として動作する**サーバープログラム**を実行してきたはずです。
|
||||
|
||||
アプリケーションをデプロイする際には、**複数のコア**を利用し、そしてより多くのリクエストを処理できるようにするために、プロセスの**レプリケーション**を持つことを望むでしょう。
|
||||
|
||||
前のチャプターである[デプロイメントのコンセプト](concepts.md){.internal-link target=_blank}にて見てきたように、有効な戦略がいくつかあります。
|
||||
|
||||
ここでは<a href="https://gunicorn.org/" class="external-link" target="_blank">**Gunicorn**</a>が**Uvicornのワーカー・プロセス**を管理する場合の使い方について紹介していきます。
|
||||
ここでは、`fastapi` コマンド、または `uvicorn` コマンドを直接使って、**ワーカープロセス**付きの **Uvicorn** を使う方法を紹介します。
|
||||
|
||||
/// info
|
||||
/// info | 情報
|
||||
|
||||
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
|
||||
DockerやKubernetesなどのコンテナを使用している場合は、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}
|
||||
DockerやKubernetesなどのコンテナを使用している場合は、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}。
|
||||
|
||||
特に**Kubernetes**上で実行する場合は、おそらく**Gunicornを使用せず**、**コンテナごとに単一のUvicornプロセス**を実行することになりますが、それについてはこの章の後半で説明します。
|
||||
特に**Kubernetes**上で実行する場合は、おそらくワーカーは使わず、代わりに**コンテナごとに単一のUvicornプロセス**を実行したいはずですが、それについてはその章の後半で説明します。
|
||||
|
||||
///
|
||||
|
||||
## GunicornによるUvicornのワーカー・プロセスの管理
|
||||
## 複数ワーカー { #multiple-workers }
|
||||
|
||||
**Gunicorn**は**WSGI標準**のアプリケーションサーバーです。このことは、GunicornはFlaskやDjangoのようなアプリケーションにサービスを提供できることを意味します。Gunicornそれ自体は**FastAPI**と互換性がないですが、というのもFastAPIは最新の**<a href="https://asgi.readthedocs.io/en/latest/" class="external-link" target="_blank">ASGI 標準</a>**を使用しているためです。
|
||||
`--workers` コマンドラインオプションで複数のワーカーを起動できます。
|
||||
|
||||
しかし、Gunicornは**プロセスマネージャー**として動作し、ユーザーが特定の**ワーカー・プロセスクラス**を使用するように指示することができます。するとGunicornはそのクラスを使い1つ以上の**ワーカー・プロセス**を開始します。
|
||||
//// tab | `fastapi`
|
||||
|
||||
そして**Uvicorn**には**Gunicorn互換のワーカークラス**があります。
|
||||
|
||||
この組み合わせで、Gunicornは**プロセスマネージャー**として動作し、**ポート**と**IP**をリッスンします。そして、**Uvicornクラス**を実行しているワーカー・プロセスに通信を**転送**します。
|
||||
|
||||
そして、Gunicorn互換の**Uvicornワーカー**クラスが、FastAPIが使えるように、Gunicornから送られてきたデータをASGI標準に変換する役割を担います。
|
||||
|
||||
## GunicornとUvicornをインストールする
|
||||
`fastapi` コマンドを使う場合:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "uvicorn[standard]" gunicorn
|
||||
$ <font color="#4E9A06">fastapi</font> run --workers 4 <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
---> 100%
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting production server 🚀
|
||||
|
||||
Searching for package file structure from directories with
|
||||
<font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with the
|
||||
following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to
|
||||
quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started parent process <b>[</b><font color="#34E2E2"><b>27365</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27368</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27369</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27370</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>27367</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
これによりUvicornと(高性能を得るための)標準(`standard`)の追加パッケージとGunicornの両方がインストールされます。
|
||||
////
|
||||
|
||||
## UvicornのワーカーとともにGunicornを実行する
|
||||
//// tab | `uvicorn`
|
||||
|
||||
Gunicornを以下のように起動させることができます:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80
|
||||
|
||||
[19499] [INFO] Starting gunicorn 20.1.0
|
||||
[19499] [INFO] Listening at: http://0.0.0.0:80 (19499)
|
||||
[19499] [INFO] Using worker: uvicorn.workers.UvicornWorker
|
||||
[19511] [INFO] Booting worker with pid: 19511
|
||||
[19513] [INFO] Booting worker with pid: 19513
|
||||
[19514] [INFO] Booting worker with pid: 19514
|
||||
[19515] [INFO] Booting worker with pid: 19515
|
||||
[19511] [INFO] Started server process [19511]
|
||||
[19511] [INFO] Waiting for application startup.
|
||||
[19511] [INFO] Application startup complete.
|
||||
[19513] [INFO] Started server process [19513]
|
||||
[19513] [INFO] Waiting for application startup.
|
||||
[19513] [INFO] Application startup complete.
|
||||
[19514] [INFO] Started server process [19514]
|
||||
[19514] [INFO] Waiting for application startup.
|
||||
[19514] [INFO] Application startup complete.
|
||||
[19515] [INFO] Started server process [19515]
|
||||
[19515] [INFO] Waiting for application startup.
|
||||
[19515] [INFO] Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
それぞれのオプションの意味を見てみましょう:
|
||||
|
||||
* `main:app`: `main`は"`main`"という名前のPythonモジュール、つまりファイル`main.py`を意味します。そして `app` は **FastAPI** アプリケーションの変数名です。
|
||||
* main:app`はPythonの`import`文と同じようなものだと想像できます:
|
||||
|
||||
```Python
|
||||
from main import app
|
||||
```
|
||||
|
||||
* つまり、`main:app`のコロンは、`from main import app`のPythonの`import`の部分と同じになります。
|
||||
|
||||
* `--workers`: 使用するワーカー・プロセスの数で、それぞれがUvicornのワーカーを実行します。
|
||||
|
||||
* `--worker-class`: ワーカー・プロセスで使用するGunicorn互換のワーカークラスです。
|
||||
* ここではGunicornがインポートして使用できるクラスを渡します:
|
||||
|
||||
```Python
|
||||
import uvicorn.workers.UvicornWorker
|
||||
```
|
||||
|
||||
* `--bind`: GunicornにリッスンするIPとポートを伝えます。コロン(`:`)でIPとポートを区切ります。
|
||||
* Uvicornを直接実行している場合は、`--bind 0.0.0.0:80` (Gunicornのオプション)の代わりに、`--host 0.0.0.0`と `--port 80`を使います。
|
||||
|
||||
出力では、各プロセスの**PID**(プロセスID)が表示されているのがわかります(単なる数字です)。
|
||||
|
||||
以下の通りです:
|
||||
|
||||
* Gunicornの**プロセス・マネージャー**はPID `19499`(あなたの場合は違う番号でしょう)で始まります。
|
||||
* 次に、`Listening at: http://0.0.0.0:80`を開始します。
|
||||
* それから `uvicorn.workers.UvicornWorker` でワーカークラスを使用することを検出します。
|
||||
* そして、**4つのワーカー**を起動します。それぞれのワーカーのPIDは、`19511`、`19513`、`19514`、`19515`です。
|
||||
|
||||
Gunicornはまた、ワーカーの数を維持するために必要であれば、**ダウンしたプロセス**を管理し、**新しいプロセスを**再起動**させます。そのため、上記のリストにある**再起動**の概念に一部役立ちます。
|
||||
|
||||
しかしながら、必要であればGunicornを**再起動**させ、**起動時に実行**させるなど、外部のコンポーネントを持たせることも必要かもしれません。
|
||||
|
||||
## Uvicornとワーカー
|
||||
|
||||
Uvicornには複数の**ワーカー・プロセス**を起動し実行するオプションもあります。
|
||||
|
||||
とはいうものの、今のところUvicornのワーカー・プロセスを扱う機能はGunicornよりも制限されています。そのため、このレベル(Pythonレベル)でプロセスマネージャーを持ちたいのであれば、Gunicornをプロセスマネージャーとして使ってみた方が賢明かもしれないです。
|
||||
|
||||
どんな場合であれ、以下のように実行します:
|
||||
`uvicorn` コマンドを直接使いたい場合:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -150,36 +105,35 @@ $ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
|
||||
|
||||
</div>
|
||||
|
||||
ここで唯一の新しいオプションは `--workers` で、Uvicornに4つのワーカー・プロセスを起動するように指示しています。
|
||||
////
|
||||
|
||||
各プロセスの **PID** が表示され、親プロセスの `27365` (これは **プロセスマネージャ**) と、各ワーカー・プロセスの **PID** が表示されます: `27368`、`27369`、`27370`、`27367`になります。
|
||||
ここで唯一の新しいオプションは `--workers` で、Uvicornに4つのワーカープロセスを起動するように指示しています。
|
||||
|
||||
## デプロイメントのコンセプト
|
||||
各プロセスの **PID** も表示されていて、親プロセス(これは**プロセスマネージャー**)が `27365`、各ワーカープロセスがそれぞれ `27368`、`27369`、`27370`、`27367` です。
|
||||
|
||||
ここでは、アプリケーションの実行を**並列化**し、CPUの**マルチコア**を活用し、**より多くのリクエスト**に対応できるようにするために、**Gunicorn**(またはUvicorn)を使用して**Uvicornワーカー・プロセス**を管理する方法を見ていきました。
|
||||
## デプロイメントのコンセプト { #deployment-concepts }
|
||||
|
||||
上記のデプロイのコンセプトのリストから、ワーカーを使うことは主に**レプリケーション**の部分と、**再起動**を少し助けてくれます:
|
||||
ここでは、複数の **ワーカー** を使ってアプリケーションの実行を**並列化**し、CPUの**複数コア**を活用して、**より多くのリクエスト**を処理できるようにする方法を見てきました。
|
||||
|
||||
* セキュリティ - HTTPS
|
||||
* 起動時の実行
|
||||
* 再起動
|
||||
上のデプロイメントのコンセプトのリストから、ワーカーを使うことは主に**レプリケーション**の部分と、**再起動**を少し助けてくれますが、それ以外については引き続き対処が必要です:
|
||||
|
||||
* **セキュリティ - HTTPS**
|
||||
* **起動時の実行**
|
||||
* ***再起動***
|
||||
* レプリケーション(実行中のプロセス数)
|
||||
* メモリー
|
||||
* 開始前の事前のステップ
|
||||
* **メモリ**
|
||||
* **開始前の事前ステップ**
|
||||
|
||||
## コンテナとDocker { #containers-and-docker }
|
||||
|
||||
## コンテナとDocker
|
||||
<!-- NOTE: the current version of docker.md is outdated compared to English one. -->
|
||||
次章の[コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}では、その他の**デプロイのコンセプト**を扱うために実施するであろう戦略をいくつか紹介します。
|
||||
次章の[コンテナ内のFastAPI - Docker](docker.md){.internal-link target=_blank}では、その他の**デプロイメントのコンセプト**を扱うために使える戦略をいくつか説明します。
|
||||
|
||||
また、**GunicornとUvicornワーカー**を含む**公式Dockerイメージ**と、簡単なケースに役立ついくつかのデフォルト設定も紹介します。
|
||||
単一のUvicornプロセスを実行するために、**ゼロから独自のイメージを構築する**方法も紹介します。これは簡単なプロセスで、**Kubernetes**のような分散コンテナ管理システムを使う場合に、おそらくやりたいことでしょう。
|
||||
|
||||
また、(Gunicornを使わずに)Uvicornプロセスを1つだけ実行するために、**ゼロから独自のイメージを**構築する方法も紹介します。これは簡単なプロセスで、おそらく**Kubernetes**のような分散コンテナ管理システムを使うときにやりたいことでしょう。
|
||||
## まとめ { #recap }
|
||||
|
||||
## まとめ
|
||||
`fastapi` または `uvicorn` コマンドで `--workers` CLIオプションを使うことで、**マルチコアCPU**を活用し、**複数のプロセスを並列実行**できるように複数のワーカープロセスを利用できます。
|
||||
|
||||
Uvicornワーカーを使ったプロセスマネージャとして**Gunicorn**(またはUvicorn)を使えば、**マルチコアCPU**を活用して**複数のプロセスを並列実行**できます。
|
||||
他のデプロイメントのコンセプトを自分で対応しながら、**独自のデプロイシステム**を構築している場合にも、これらのツールやアイデアを使えます。
|
||||
|
||||
これらのツールやアイデアは、**あなた自身のデプロイシステム**をセットアップしながら、他のデプロイコンセプトを自分で行う場合にも使えます。
|
||||
|
||||
次の章では、コンテナ(DockerやKubernetesなど)を使った**FastAPI**について学んでいきましょう。これらのツールには、他の**デプロイのコンセプト**も解決する簡単な方法があることがわかるでしょう。✨
|
||||
次の章で、コンテナ(例:DockerやKubernetes)を使った **FastAPI** について学びましょう。これらのツールにも、他の**デプロイメントのコンセプト**を解決する簡単な方法があることがわかります。✨
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
# FastAPIのバージョンについて
|
||||
# FastAPIのバージョンについて { #about-fastapi-versions }
|
||||
|
||||
**FastAPI** は既に多くのアプリケーションやシステムに本番環境で使われています。また、100%のテストカバレッジを維持しています。しかし、活発な開発が続いています。
|
||||
**FastAPI** はすでに多くのアプリケーションやシステムで本番環境にて使われています。また、テストカバレッジは 100% に維持されています。しかし、開発は依然として急速に進んでいます。
|
||||
|
||||
高頻度で新機能が追加され、定期的にバグが修正され、実装は継続的に改善されています。
|
||||
新機能が高頻度で追加され、定期的にバグが修正され、コードは継続的に改善されています。
|
||||
|
||||
これが現在のバージョンがいまだに `0.x.x` な理由であり、それぞれのバージョンは破壊的な変更がなされる可能性があります。これは、<a href="https://semver.org/" class="external-link" target="_blank">セマンティック バージョニング</a>の規則に則っています。
|
||||
|
||||
**FastAPI** を使用すると本番用アプリケーションをすぐに作成できますが (すでに何度も経験しているかもしれませんが)、残りのコードが正しく動作するバージョンなのか確認しなければいけません。
|
||||
**FastAPI** を使用すると本番用アプリケーションを今すぐ作成できます(そして、おそらくあなたはしばらく前からそうしているはずです)。必要なのは、残りのコードと正しく動作するバージョンを使用していることを確認することだけです。
|
||||
|
||||
## `fastapi` のバージョンを固定
|
||||
## `fastapi` のバージョンを固定 { #pin-your-fastapi-version }
|
||||
|
||||
最初にすべきことは、アプリケーションが正しく動作する **FastAPI** のバージョンを固定することです。
|
||||
最初にすべきことは、使用している **FastAPI** のバージョンを、アプリケーションで正しく動作することが分かっている特定の最新バージョンに「固定(pin)」することです。
|
||||
|
||||
例えば、バージョン `0.45.0` を使っているとしましょう。
|
||||
例えば、アプリでバージョン `0.112.0` を使っているとしましょう。
|
||||
|
||||
`requirements.txt` を使っているなら、以下の様にバージョンを指定できます:
|
||||
`requirements.txt` ファイルを使う場合は、以下のようにバージョンを指定できます:
|
||||
|
||||
```txt
|
||||
fastapi==0.45.0
|
||||
fastapi[standard]==0.112.0
|
||||
```
|
||||
|
||||
これは、厳密にバージョン `0.45.0` だけを使うことを意味します。
|
||||
これは、厳密にバージョン `0.112.0` だけを使うことを意味します。
|
||||
|
||||
または、以下の様に固定することもできます:
|
||||
または、以下のように固定することもできます:
|
||||
|
||||
```txt
|
||||
fastapi[standard]>=0.112.0,<0.113.0
|
||||
```
|
||||
|
||||
これは `0.112.0` 以上、`0.113.0` 未満のバージョンを使うことを意味します。例えば、バージョン `0.112.2` は使用可能です。
|
||||
|
||||
`uv`、Poetry、Pipenv など、他のインストール管理ツールを使用している場合でも、いずれもパッケージの特定バージョンを定義する方法があります。
|
||||
|
||||
## 利用可能なバージョン { #available-versions }
|
||||
|
||||
利用可能なバージョン(例: 現在の最新が何かを確認するため)は、[Release Notes](../release-notes.md){.internal-link target=_blank} で確認できます。
|
||||
|
||||
## バージョンについて { #about-versions }
|
||||
|
||||
セマンティック バージョニングの規約に従って、`1.0.0` 未満のバージョンは破壊的な変更が加わる可能性があります。
|
||||
|
||||
FastAPI では「PATCH」バージョンの変更はバグ修正と非破壊的な変更に使う、という規約にも従っています。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
「PATCH」は最後の数字です。例えば、`0.2.3` では PATCH バージョンは `3` です。
|
||||
|
||||
///
|
||||
|
||||
従って、以下のようなバージョンの固定ができるはずです:
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
これは `0.45.0` 以上、`0.46.0` 未満のバージョンを使うことを意味します。例えば、バージョン `0.45.2` は使用可能です。
|
||||
|
||||
PoetryやPipenvなど、他のインストール管理ツールを使用している場合でも、それぞれパッケージのバージョンを指定する機能があります。
|
||||
|
||||
## 利用可能なバージョン
|
||||
|
||||
[Release Notes](../release-notes.md){.internal-link target=_blank}で利用可能なバージョンが確認できます (現在の最新版の確認などのため)。
|
||||
|
||||
## バージョンについて
|
||||
|
||||
セマンティック バージョニングの規約に従って、`1.0.0` 未満の全てのバージョンは破壊的な変更が加わる可能性があります。
|
||||
|
||||
FastAPIでは「パッチ」バージョンはバグ修正と非破壊的な変更に留めるという規約に従っています。
|
||||
破壊的な変更と新機能は「MINOR」バージョンで追加されます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
「パッチ」は最後の数字を指します。例えば、`0.2.3` ではパッチバージョンは `3` です。
|
||||
「MINOR」は真ん中の数字です。例えば、`0.2.3` では MINOR バージョンは `2` です。
|
||||
|
||||
///
|
||||
|
||||
従って、以下の様なバージョンの固定が望ましいです:
|
||||
## FastAPIのバージョンのアップグレード { #upgrading-the-fastapi-versions }
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
アプリケーションにテストを追加すべきです。
|
||||
|
||||
破壊的な変更と新機能実装は「マイナー」バージョンで加えられます。
|
||||
**FastAPI** では非常に簡単に実現できます(Starlette のおかげです)。ドキュメントを確認して下さい: [テスト](../tutorial/testing.md){.internal-link target=_blank}
|
||||
|
||||
/// tip | 豆知識
|
||||
テストを追加したら、**FastAPI** のバージョンをより新しいものにアップグレードし、テストを実行することで全てのコードが正しく動作するか確認できます。
|
||||
|
||||
「マイナー」は真ん中の数字です。例えば、`0.2.3` ではマイナーバージョンは `2` です。
|
||||
全てが動作する、または必要な変更を行った後に全てのテストが通るなら、その新しいバージョンに `fastapi` を固定できます。
|
||||
|
||||
///
|
||||
## Starletteについて { #about-starlette }
|
||||
|
||||
## FastAPIのバージョンのアップグレード
|
||||
`starlette` のバージョンは固定すべきではありません。
|
||||
|
||||
アプリケーションにテストを加えるべきです。
|
||||
**FastAPI** のバージョンが異なれば、Starlette の特定のより新しいバージョンが使われます。
|
||||
|
||||
**FastAPI** では非常に簡単に実現できます (Starletteのおかげで)。ドキュメントを確認して下さい: [テスト](../tutorial/testing.md){.internal-link target=_blank}
|
||||
そのため、正しい Starlette バージョンを **FastAPI** に任せればよいです。
|
||||
|
||||
テストを加えた後で、**FastAPI** のバージョンをより最新のものにアップグレードし、テストを実行することで全てのコードが正常に動作するか確認できます。
|
||||
## Pydanticについて { #about-pydantic }
|
||||
|
||||
全てが動作するか、修正を行った上で全てのテストを通過した場合、使用している`fastapi` のバージョンをより最新のバージョンに固定できます。
|
||||
Pydantic は自身のテストに **FastAPI** のテストも含んでいるため、Pydantic の新しいバージョン(`1.0.0` より上)は常に FastAPI と互換性があります。
|
||||
|
||||
## Starletteについて
|
||||
|
||||
`Starlette` のバージョンは固定すべきではありません。
|
||||
|
||||
**FastAPI** は、バージョン毎にStarletteのより新しいバージョンを使用します。
|
||||
|
||||
よって、最適なStarletteのバージョン選択を**FastAPI** に任せることができます。
|
||||
|
||||
## Pydanticについて
|
||||
|
||||
Pydanticは自身のテストだけでなく**FastAPI** のためのテストを含んでいます。なので、Pydanticの新たなバージョン ( `1.0.0` 以降) は全てFastAPIと整合性があります。
|
||||
|
||||
Pydanticのバージョンを、動作が保証できる`1.0.0`以降のいずれかのバージョンから`2.0.0` 未満の間に固定できます。
|
||||
Pydantic は、自分にとって動作する `1.0.0` より上の任意のバージョンに固定できます。
|
||||
|
||||
例えば:
|
||||
|
||||
```txt
|
||||
pydantic>=1.2.0,<2.0.0
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
```
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# 環境変数
|
||||
# 環境変数 { #environment-variables }
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
もし、「環境変数」とは何か、それをどう使うかを既に知っている場合は、このセクションをスキップして構いません。
|
||||
|
||||
///
|
||||
|
||||
環境変数(**env var**とも呼ばれる)はPythonコードの**外側**、つまり**OS**に存在する変数で、Pythonから読み取ることができます。(他のプログラムでも同様に読み取れます。)
|
||||
環境変数(「**env var**」とも呼ばれます)とは、Pythonコードの**外側**、つまり**オペレーティングシステム**に存在する変数で、Pythonコード(または他のプログラム)から読み取れます。
|
||||
|
||||
環境変数は、アプリケーションの**設定**の管理や、Pythonの**インストール**などに役立ちます。
|
||||
環境変数は、アプリケーションの**設定**の扱い、Pythonの**インストール**の一部などで役立ちます。
|
||||
|
||||
## 環境変数の作成と使用
|
||||
## 環境変数の作成と使用 { #create-and-use-env-vars }
|
||||
|
||||
環境変数は**シェル(ターミナル)**内で**作成**して使用でき、それらにPythonは不要です。
|
||||
環境変数は、Pythonを必要とせず、**シェル(ターミナル)**で**作成**して使用できます。
|
||||
|
||||
//// tab | Linux, macOS, Windows Bash
|
||||
|
||||
@@ -36,7 +36,6 @@ Hello Wade Wilson
|
||||
|
||||
<div class="termy">
|
||||
|
||||
|
||||
```console
|
||||
// Create an env var MY_NAME
|
||||
$ $Env:MY_NAME = "Wade Wilson"
|
||||
@@ -51,9 +50,9 @@ Hello Wade Wilson
|
||||
|
||||
////
|
||||
|
||||
## Pythonで環境変数を読み取る
|
||||
## Pythonで環境変数を読み取る { #read-env-vars-in-python }
|
||||
|
||||
環境変数をPythonの**外側**、ターミナル(や他の方法)で作成し、**Python内で読み取る**こともできます。
|
||||
環境変数はPythonの**外側**(ターミナル、またはその他の方法)で作成し、その後に**Pythonで読み取る**こともできます。
|
||||
|
||||
例えば、以下のような`main.py`ファイルを用意します:
|
||||
|
||||
@@ -64,11 +63,11 @@ name = os.getenv("MY_NAME", "World")
|
||||
print(f"Hello {name} from Python")
|
||||
```
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
<a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> の第2引数は、デフォルトで返される値を指定します。
|
||||
<a href="https://docs.python.org/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> の第2引数は、デフォルトで返される値です。
|
||||
|
||||
この引数を省略するとデフォルト値として`None`が返されますが、ここではデフォルト値として`"World"`を指定しています。
|
||||
指定しない場合、デフォルトは`None`ですが、ここでは使用するデフォルト値として`"World"`を指定しています。
|
||||
|
||||
///
|
||||
|
||||
@@ -128,11 +127,11 @@ Hello Wade Wilson from Python
|
||||
|
||||
////
|
||||
|
||||
環境変数はコードの外側で設定し、内側から読み取ることができるので、他のファイルと一緒に(`git`に)保存する必要がありません。そのため、環境変数をコンフィグレーションや**設定**に使用することが一般的です。
|
||||
環境変数はコードの外側で設定でき、コードから読み取れ、他のファイルと一緒に(`git`に)保存(コミット)する必要がないため、設定や**settings**に使うのが一般的です。
|
||||
|
||||
また、**特定のプログラムの呼び出し**のための環境変数を、そのプログラムのみ、その実行中に限定して利用できるよう作成できます。
|
||||
また、**特定のプログラムの呼び出し**のためだけに、そのプログラムでのみ、実行中の間だけ利用できる環境変数を作成することもできます。
|
||||
|
||||
そのためには、プログラム起動コマンドと同じコマンドライン上の、起動コマンド直前で環境変数を作成してください。
|
||||
そのためには、同じ行で、プログラム自体の直前に作成してください。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -152,25 +151,25 @@ Hello World from Python
|
||||
|
||||
</div>
|
||||
|
||||
/// tip
|
||||
/// tip | 豆知識
|
||||
|
||||
詳しくは <a href="https://12factor.net/config" class="external-link" target="_blank">The Twelve-Factor App: Config</a> を参照してください。
|
||||
詳しくは <a href="https://12factor.net/config" class="external-link" target="_blank">The Twelve-Factor App: 設定</a> を参照してください。
|
||||
|
||||
///
|
||||
|
||||
## 型とバリデーション
|
||||
## 型とバリデーション { #types-and-validation }
|
||||
|
||||
環境変数は**テキスト文字列**のみを扱うことができます。これは、環境変数がPython外部に存在し、他のプログラムやシステム全体(Linux、Windows、macOS間の互換性を含む)と連携する必要があるためです。
|
||||
これらの環境変数が扱えるのは**テキスト文字列**のみです。環境変数はPythonの外部にあり、他のプログラムやシステム全体(Linux、Windows、macOSなど異なるオペレーティングシステム間も)との互換性が必要になるためです。
|
||||
|
||||
つまり、Pythonが環境変数から読み取る**あらゆる値**は **`str`型となり**、他の型への変換やバリデーションはコード内で行う必要があります。
|
||||
つまり、環境変数からPythonで読み取る**あらゆる値**は **`str`になり**、他の型への変換やバリデーションはコード内で行う必要があります。
|
||||
|
||||
環境変数を使用して**アプリケーション設定**を管理する方法については、[高度なユーザーガイド - Settings and Environment Variables](./advanced/settings.md){.internal-link target=_blank}で詳しく学べます。
|
||||
環境変数を使って**アプリケーション設定**を扱う方法については、[高度なユーザーガイド - Settings and Environment Variables](./advanced/settings.md){.internal-link target=_blank} で詳しく学べます。
|
||||
|
||||
## `PATH`環境変数
|
||||
## `PATH`環境変数 { #path-environment-variable }
|
||||
|
||||
**`PATH`**という**特別な**環境変数があります。この環境変数は、OS(Linux、macOS、Windows)が実行するプログラムを発見するために使用されます。
|
||||
**`PATH`**という**特別な**環境変数があります。これはオペレーティングシステム(Linux、macOS、Windows)が実行するプログラムを見つけるために使用されます。
|
||||
|
||||
`PATH`変数は、複数のディレクトリのパスから成る長い文字列です。このパスはLinuxやMacOSの場合は`:`で、Windowsの場合は`;`で区切られています。
|
||||
変数`PATH`の値は長い文字列で、LinuxとmacOSではコロン`:`、Windowsではセミコロン`;`で区切られたディレクトリで構成されます。
|
||||
|
||||
例えば、`PATH`環境変数は次のような文字列かもしれません:
|
||||
|
||||
@@ -180,7 +179,7 @@ Hello World from Python
|
||||
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
||||
```
|
||||
|
||||
これは、OSはプログラムを見つけるために以下のディレクトリを探す、ということを意味します:
|
||||
これは、システムが次のディレクトリでプログラムを探すことを意味します:
|
||||
|
||||
* `/usr/local/bin`
|
||||
* `/usr/bin`
|
||||
@@ -196,7 +195,7 @@ Hello World from Python
|
||||
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
|
||||
```
|
||||
|
||||
これは、OSはプログラムを見つけるために以下のディレクトリを探す、ということを意味します:
|
||||
これは、システムが次のディレクトリでプログラムを探すことを意味します:
|
||||
|
||||
* `C:\Program Files\Python312\Scripts`
|
||||
* `C:\Program Files\Python312`
|
||||
@@ -204,63 +203,61 @@ C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System3
|
||||
|
||||
////
|
||||
|
||||
ターミナル上で**コマンド**を入力すると、 OSはそのプログラムを見つけるために、`PATH`環境変数のリストに記載された**それぞれのディレクトリを探し**ます。
|
||||
ターミナル上で**コマンド**を入力すると、オペレーティングシステムは`PATH`環境変数に記載された**それぞれのディレクトリ**の中からプログラムを**探し**ます。
|
||||
|
||||
例えば、ターミナル上で`python`を入力すると、OSは`python`によって呼ばれるプログラムを見つけるために、そのリストの**先頭のディレクトリ**を最初に探します。
|
||||
例えば、ターミナルで`python`と入力すると、オペレーティングシステムはそのリストの**最初のディレクトリ**で`python`というプログラムを探します。
|
||||
|
||||
OSは、もしそのプログラムをそこで発見すれば**実行し**ますが、そうでなければリストの**他のディレクトリ**を探していきます。
|
||||
見つかればそれを**使用**します。見つからなければ、**他のディレクトリ**を探し続けます。
|
||||
|
||||
### PythonのインストールとPATH環境変数の更新
|
||||
### Pythonのインストールと`PATH`の更新 { #installing-python-and-updating-the-path }
|
||||
|
||||
Pythonのインストール時に`PATH`環境変数を更新したいか聞かれるかもしれません。
|
||||
Pythonのインストール時に、`PATH`環境変数を更新するかどうかを尋ねられるかもしれません。
|
||||
|
||||
/// tab | Linux, macOS
|
||||
//// tab | Linux, macOS
|
||||
|
||||
Pythonをインストールして、そのプログラムが`/opt/custompython/bin`というディレクトリに配置されたとします。
|
||||
Pythonをインストールして、その結果`/opt/custompython/bin`というディレクトリに配置されたとします。
|
||||
|
||||
もし、`PATH`環境変数を更新するように答えると、`PATH`環境変数に`/opt/custompython/bin`が追加されます。
|
||||
`PATH`環境変数を更新することに同意すると、インストーラーは`PATH`環境変数に`/opt/custompython/bin`を追加します。
|
||||
|
||||
`PATH`環境変数は以下のように更新されるでしょう:
|
||||
例えば次のようになります:
|
||||
|
||||
``` plaintext
|
||||
```plaintext
|
||||
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
|
||||
```
|
||||
|
||||
このようにして、ターミナルで`python`と入力したときに、OSは`/opt/custompython/bin`(リストの末尾のディレクトリ)にあるPythonプログラムを見つけ、使用します。
|
||||
このようにして、ターミナルで`python`と入力すると、システムは`/opt/custompython/bin`(最後のディレクトリ)にあるPythonプログラムを見つけ、それを使用します。
|
||||
|
||||
///
|
||||
////
|
||||
|
||||
/// tab | Windows
|
||||
//// tab | Windows
|
||||
|
||||
Pythonをインストールして、そのプログラムが`C:\opt\custompython\bin`というディレクトリに配置されたとします。
|
||||
Pythonをインストールして、その結果`C:\opt\custompython\bin`というディレクトリに配置されたとします。
|
||||
|
||||
もし、`PATH`環境変数を更新するように答えると、`PATH`環境変数に`C:\opt\custompython\bin`が追加されます。
|
||||
|
||||
`PATH`環境変数は以下のように更新されるでしょう:
|
||||
`PATH`環境変数を更新することに同意すると、インストーラーは`PATH`環境変数に`C:\opt\custompython\bin`を追加します。
|
||||
|
||||
```plaintext
|
||||
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
|
||||
```
|
||||
|
||||
このようにして、ターミナルで`python`と入力したときに、OSは`C:\opt\custompython\bin\python`(リストの末尾のディレクトリ)にあるPythonプログラムを見つけ、使用します。
|
||||
このようにして、ターミナルで`python`と入力すると、システムは`C:\opt\custompython\bin`(最後のディレクトリ)にあるPythonプログラムを見つけ、それを使用します。
|
||||
|
||||
///
|
||||
////
|
||||
|
||||
つまり、ターミナルで以下のコマンドを入力すると:
|
||||
つまり、ターミナルで次のように入力すると:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
``` console
|
||||
```console
|
||||
$ python
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// tab | Linux, macOS
|
||||
//// tab | Linux, macOS
|
||||
|
||||
OSは`/opt/custompython/bin`にある`python`プログラムを**見つけ**て実行します。
|
||||
システムは`/opt/custompython/bin`にある`python`プログラムを**見つけ**て実行します。
|
||||
|
||||
これは、次のコマンドを入力した場合とほとんど同等です:
|
||||
これは、次のように入力するのとおおむね同等です:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -270,13 +267,13 @@ $ /opt/custompython/bin/python
|
||||
|
||||
</div>
|
||||
|
||||
///
|
||||
////
|
||||
|
||||
/// tab | Windows
|
||||
//// tab | Windows
|
||||
|
||||
OSは`C:\opt\custompython\bin\python`にある`python`プログラムを**見つけ**て実行します。
|
||||
システムは`C:\opt\custompython\bin\python`にある`python`プログラムを**見つけ**て実行します。
|
||||
|
||||
これは、次のコマンドを入力した場合とほとんど同等です:
|
||||
これは、次のように入力するのとおおむね同等です:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -286,16 +283,16 @@ $ C:\opt\custompython\bin\python
|
||||
|
||||
</div>
|
||||
|
||||
///
|
||||
////
|
||||
|
||||
この情報は、[Virtual Environments](virtual-environments.md) について学ぶ際にも役立ちます。
|
||||
この情報は、[Virtual Environments](virtual-environments.md){.internal-link target=_blank} について学ぶ際にも役立ちます。
|
||||
|
||||
## まとめ
|
||||
## まとめ { #conclusion }
|
||||
|
||||
これで、**環境変数**とは何か、Pythonでどのように使用するかについて、基本的な理解が得られたはずです。
|
||||
|
||||
環境変数についての詳細は、<a href="https://en.wikipedia.org/wiki/Environment_variable" class="external-link" target="_blank">Wikipedia: Environment Variable</a> を参照してください。
|
||||
環境変数についての詳細は、<a href="https://en.wikipedia.org/wiki/Environment_variable" class="external-link" target="_blank">Wikipedia の環境変数</a> も参照してください。
|
||||
|
||||
環境変数の用途や適用方法が最初は直感的ではないかもしれませんが、開発中のさまざまなシナリオで繰り返し登場します。そのため、基本を知っておくことが重要です。
|
||||
多くの場合、環境変数がどのように役立ち、すぐに適用できるのかはあまり明確ではありません。しかし、開発中のさまざまなシナリオで何度も登場するため、知っておくとよいでしょう。
|
||||
|
||||
たとえば、この情報は次のセクションで扱う[Virtual Environments](virtual-environments.md)にも関連します。
|
||||
例えば、次のセクションの[Virtual Environments](virtual-environments.md)でこの情報が必要になります。
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# FastAPI CLI { #fastapi-cli }
|
||||
|
||||
**FastAPI CLI** は、FastAPI アプリの提供、FastAPI プロジェクトの管理などに使用できるコマンドラインプログラムです。
|
||||
|
||||
FastAPI をインストールすると(例: `pip install "fastapi[standard]"`)、`fastapi-cli` というパッケージが含まれます。このパッケージがターミナルで使用する `fastapi` コマンドを提供します。
|
||||
|
||||
開発用に FastAPI アプリを起動するには、`fastapi dev` コマンドを使用できます:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
|
||||
Searching for package file structure from directories with
|
||||
<font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with the
|
||||
following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to
|
||||
quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
`fastapi` というコマンドラインプログラムが **FastAPI CLI** です。
|
||||
|
||||
FastAPI CLI は、Python プログラムへのパス(例: `main.py`)を受け取り、`FastAPI` インスタンス(通常は `app`)を自動検出し、適切な import 方法を判断して提供します。
|
||||
|
||||
本番環境では代わりに `fastapi run` を使用します。🚀
|
||||
|
||||
内部的には、**FastAPI CLI** は <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>(高性能で本番運用向けの ASGI サーバー)を使用します。😎
|
||||
|
||||
## `fastapi dev` { #fastapi-dev }
|
||||
|
||||
`fastapi dev` を実行すると、開発モードが有効になります。
|
||||
|
||||
デフォルトでは、**auto-reload** が有効です。コードを変更するとサーバーが自動で再読み込みされます。これはリソースを多く消費し、無効時より安定性が低くなる可能性があります。開発時のみに使用してください。また、IP アドレス `127.0.0.1`(マシン自身のみと通信するための IP、`localhost`)で待ち受けます。
|
||||
|
||||
## `fastapi run` { #fastapi-run }
|
||||
|
||||
`fastapi run` を実行すると、デフォルトで本番モードで起動します。
|
||||
|
||||
デフォルトでは、**auto-reload** は無効です。また、IP アドレス `0.0.0.0`(利用可能なすべての IP アドレスを意味します)で待ち受けるため、そのマシンと通信できる任意のクライアントから公開アクセスが可能になります。これは、たとえばコンテナ内など、本番環境で一般的な実行方法です。
|
||||
|
||||
多くの場合(そして推奨されるのは)、上位に HTTPS を終端する「termination proxy」を置きます。これはアプリのデプロイ方法に依存し、プロバイダが代行する場合もあれば、自分で設定する必要がある場合もあります。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
詳しくは、[デプロイのドキュメント](deployment/index.md){.internal-link target=_blank}を参照してください。
|
||||
|
||||
///
|
||||
+102
-105
@@ -1,54 +1,55 @@
|
||||
# 機能
|
||||
# 機能 { #features }
|
||||
|
||||
## FastAPIの機能
|
||||
## FastAPIの機能 { #fastapi-features }
|
||||
|
||||
**FastAPI** は以下の機能をもちます:
|
||||
**FastAPI** は次のものを提供します:
|
||||
|
||||
### オープンスタンダード準拠
|
||||
### オープンスタンダード準拠 { #based-on-open-standards }
|
||||
|
||||
* API作成のための<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a>。これは、<abbr title="also known as: endpoints, routes">path</abbr> <abbr title="also known as HTTP methods, as POST, GET, PUT, DELETE">operations</abbr>の宣言、パラメータ、ボディリクエスト、セキュリティなどを含んでいます。
|
||||
* <a href="http://json-schema.org/" class="external-link" target="_blank"><strong>JSONスキーマ</strong></a>を使用したデータモデルのドキュメント自動生成(OpenAPIはJSONスキーマに基づいている)。
|
||||
* 綿密な調査の結果、上層に後付けするのではなく、これらの基準に基づいて設計されました。
|
||||
* API 作成のための <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a>。<dfn title="別名: エンドポイント、ルート">path</dfn> <dfn title="別名: HTTP メソッド(POST、GET、PUT、DELETE など)">operations</dfn>、パラメータ、リクエストボディ、セキュリティなどの宣言を含みます。
|
||||
* <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> によるデータモデルの自動ドキュメント化(OpenAPI 自体が JSON Schema に基づいています)。
|
||||
* 入念な調査のうえ、これらの標準を中心に設計されています。後付けのレイヤーではありません。
|
||||
* これにより、多くの言語で自動 **クライアントコード生成** が可能です。
|
||||
|
||||
### 自動ドキュメント生成
|
||||
対話的なAPIドキュメントと探索的なwebユーザーインターフェースを提供します。フレームワークはOpenAPIを基にしているため、いくつかのオプションがあり、デフォルトで2つ含まれています。
|
||||
### 自動ドキュメント { #automatic-docs }
|
||||
|
||||
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>で、インタラクティブな探索をしながら、ブラウザから直接APIを呼び出してテストが行えます。
|
||||
対話的な API ドキュメントと探索的な Web ユーザーインターフェース。フレームワークは OpenAPI に基づいているため、複数のオプションがあり、デフォルトで 2 つ含まれます。
|
||||
|
||||
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>。インタラクティブに探索しつつ、ブラウザから直接 API を呼び出してテストできます。
|
||||
|
||||

|
||||
|
||||
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>を使用したもう一つのAPIドキュメント生成。
|
||||
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a> による代替の API ドキュメント。
|
||||
|
||||

|
||||
|
||||
### 現代的なPython
|
||||
### 現代的なPythonのみ { #just-modern-python }
|
||||
|
||||
FastAPIの機能はすべて、標準のPython 3.8型宣言に基づいています(Pydanticの功績)。新しい構文はありません。ただの現代的な標準のPythonです。
|
||||
すべて標準の **Python の型** 宣言(Pydantic に感謝)に基づいています。新しい構文を学ぶ必要はありません。標準的でモダンな Python だけです。
|
||||
|
||||
(FastAPIを使用しない場合でも)Pythonの型の使用方法について簡単な復習が必要な場合は、短いチュートリアル([Python Types](python-types.md){.internal-link target=_blank})を参照してください。
|
||||
(FastAPI を使わない場合でも)Python の型の使い方を 2 分で復習したい場合は、短いチュートリアル [Python Types](python-types.md){.internal-link target=_blank} を参照してください。
|
||||
|
||||
型を使用した標準的なPythonを記述します:
|
||||
型を使った標準的な Python を記述します:
|
||||
|
||||
```Python
|
||||
from datetime import date
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Declare a variable as a str
|
||||
# and get editor support inside the function
|
||||
# 変数を str として宣言
|
||||
# そして関数内でエディタ支援を受ける
|
||||
def main(user_id: str):
|
||||
return user_id
|
||||
|
||||
|
||||
# A Pydantic model
|
||||
# Pydantic モデル
|
||||
class User(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
joined: date
|
||||
```
|
||||
|
||||
これは以下のように用いられます:
|
||||
これは次のように使えます:
|
||||
|
||||
```Python
|
||||
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
|
||||
@@ -62,143 +63,139 @@ second_user_data = {
|
||||
my_second_user: User = User(**second_user_data)
|
||||
```
|
||||
|
||||
/// info | 情報
|
||||
/// info
|
||||
|
||||
`**second_user_data` は以下を意味します:
|
||||
`**second_user_data` は次の意味です:
|
||||
|
||||
`second_user_data`辞書のキーと値を直接、キーと値の引数として渡します。これは、`User(id=4, name="Mary", joined="2018-11-30")`と同等です。
|
||||
`second_user_data` 辞書のキーと値を、そのままキーバリュー引数として渡します。これは `User(id=4, name="Mary", joined="2018-11-30")` と同等です。
|
||||
|
||||
///
|
||||
|
||||
### エディタのサポート
|
||||
### エディタのサポート { #editor-support }
|
||||
|
||||
すべてのフレームワークは使いやすく直感的に使用できるように設計されており、すべての決定は開発を開始する前でも複数のエディターでテストされ、最高の開発体験が保証されます。
|
||||
フレームワーク全体が使いやすく直感的になるよう設計されており、最高の開発体験を確保するため、開発開始前から複数のエディタであらゆる判断が検証されています。
|
||||
|
||||
前回のPython開発者調査では、<a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">最も使用されている機能が「オートコンプリート」であることが明らかになりました。</a>
|
||||
Python 開発者調査では、<a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">最もよく使われる機能の 1 つが「オートコンプリート」であることが明らかです</a>。
|
||||
|
||||
**FastAPI** フレームワークは、この要求を満たすことを基本としています。オートコンプリートはどこでも機能します。
|
||||
**FastAPI** はその要求を満たすことを基盤にしています。オートコンプリートはどこでも機能します。
|
||||
|
||||
ドキュメントに戻る必要はほとんどありません。
|
||||
|
||||
エディターがどのように役立つかを以下に示します:
|
||||
エディタがどのように役立つかの例です:
|
||||
|
||||
* <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a>の場合:
|
||||
* <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a> の場合:
|
||||
|
||||

|
||||
|
||||
* <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>の場合:
|
||||
* <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> の場合:
|
||||
|
||||

|
||||
|
||||
以前は不可能だと考えていたコードでさえ補完されます。例えば、リクエストからのJSONボディ(ネストされている可能性がある)内の `price`キーです。
|
||||
以前は不可能だと思っていたコードでも補完が得られます。例えば、リクエストから届く(ネストされている可能性のある)JSON ボディ内の `price` キーなどです。
|
||||
|
||||
間違ったキー名を入力したり、ドキュメント間を行き来したり、上下にスクロールして`username`と`user_name`のどちらを使用したか調べたりする必要はもうありません。
|
||||
もう間違ったキー名を入力したり、ドキュメントを行き来したり、上下にスクロールして最終的に `username` と `user_name` のどちらを使ったのか探す必要はありません。
|
||||
|
||||
### 簡潔
|
||||
### 簡潔 { #short }
|
||||
|
||||
すべてに適切な**デフォルト**があり、オプションの構成ができます。必要なことを実行し、必要なAPIを定義するためにすべてのパラメーターを調整できます。
|
||||
すべてに妥当な **デフォルト** があり、どこでもオプションで構成できます。必要に応じてすべてのパラメータを微調整して、求める API を定義できます。
|
||||
|
||||
ただし、デフォルトでもすべて **うまくいきます**。
|
||||
しかしデフォルトのままでも、すべて **うまく動きます**。
|
||||
|
||||
### 検証
|
||||
### 検証 { #validation }
|
||||
|
||||
* 以下の様な、ほとんどの(すべての?)Python **データ型**の検証:
|
||||
* JSONオブジェクト(`dict`)
|
||||
* 項目の型を定義するJSON配列(`list`)
|
||||
* 最小長と最大長のある文字列(`str`)フィールド
|
||||
* 最小値と最大値のある数値(`int`、` float`)
|
||||
* ほとんど(あるいはすべて?)の Python の **データ型** に対する検証:
|
||||
* JSON オブジェクト(`dict`)。
|
||||
* 項目の型を定義する JSON 配列(`list`)。
|
||||
* 文字列(`str`)フィールドの最小/最大長。
|
||||
* 数値(`int`、`float`)の最小/最大値、など。
|
||||
|
||||
* よりエキゾチックな型の検証:
|
||||
* URL
|
||||
* Eメール
|
||||
* UUID
|
||||
* ...その他
|
||||
* よりエキゾチックな型の検証:
|
||||
* URL。
|
||||
* Email。
|
||||
* UUID。
|
||||
* ...その他。
|
||||
|
||||
すべての検証は、確立された堅牢な **Pydantic** によって処理されます。
|
||||
すべての検証は、確立され堅牢な **Pydantic** によって処理されます。
|
||||
|
||||
### セキュリティと認証
|
||||
### セキュリティと認証 { #security-and-authentication }
|
||||
|
||||
セキュリティと認証が統合されています。 データベースまたはデータモデルについても妥協していません。
|
||||
セキュリティと認証が統合されています。データベースやデータモデルとの妥協はありません。
|
||||
|
||||
以下のOpenAPIで定義されているすべてのセキュリティスキームを含む:
|
||||
OpenAPI で定義されたすべてのセキュリティスキームをサポートします:
|
||||
|
||||
* HTTPベーシック
|
||||
* **OAuth2**(**JWTトークン**も使用)。 JWTを使用したOAuth2のチュートリアル([OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank})を確認してください。
|
||||
* APIキー:
|
||||
* ヘッダー
|
||||
* クエリパラメータ
|
||||
* クッキー、等
|
||||
* HTTP Basic。
|
||||
* **OAuth2**(**JWT トークン** も可)。チュートリアル [JWT を用いた OAuth2](tutorial/security/oauth2-jwt.md){.internal-link target=_blank} を確認してください。
|
||||
* API キー(以下の場所):
|
||||
* ヘッダー。
|
||||
* クエリパラメータ。
|
||||
* クッキー、など。
|
||||
|
||||
さらに、Starletteのすべてのセキュリティ機能も含みます(**セッションCookie**を含む)。
|
||||
さらに、Starlette のすべてのセキュリティ機能(**セッション Cookie** を含む)も利用できます。
|
||||
|
||||
これらは、システム、データストア、リレーショナルデータベース、NoSQLデータベースなどと簡単に統合できる再利用可能なツールとコンポーネントとして構築されています。
|
||||
これらはすべて再利用可能なツールやコンポーネントとして構築されており、システム、データストア、リレーショナル/NoSQL データベース等と容易に統合できます。
|
||||
|
||||
### 依存性の注入(Dependency Injection)
|
||||
### 依存性の注入 { #dependency-injection }
|
||||
|
||||
FastAPIには非常に使いやすく、非常に強力な<abbr title='also known as "components", "resources", "services", "providers"'><strong>依存性の注入</strong></abbr>システムを備えています。
|
||||
FastAPI には、非常に使いやすく、かつ非常に強力な <dfn title='別名: コンポーネント、リソース、サービス、プロバイダー'><strong>依存性の注入</strong></dfn> システムがあります。
|
||||
|
||||
* 依存関係でさえも依存関係を持つことができ、階層または **依存関係の"グラフ"** を作成することができます。
|
||||
* 依存関係は依存関係を持つこともでき、階層または **依存関係の「グラフ」** を作成できます。
|
||||
* すべてフレームワークによって**自動的に処理**されます。
|
||||
* すべての依存関係はリクエストからデータを要求でき、*path operation* の制約と自動ドキュメントを**拡張**できます。
|
||||
* 依存関係で定義された *path operation* のパラメータについても**自動検証**されます。
|
||||
* 複雑なユーザー認証システム、**データベース接続** などのサポート。
|
||||
* **データベースやフロントエンド等との妥協は不要**。すべてと簡単に統合できます。
|
||||
|
||||
* フレームワークによってすべて**自動的に処理**されます。
|
||||
* すべての依存関係はリクエストからのデータを要請できて、**path operationsの制約と自動ドキュメンテーションを拡張できます**。
|
||||
* 依存関係で定義された *path operation* パラメータも**自動検証**が可能です。
|
||||
* 複雑なユーザー認証システム、**データベース接続**などのサポート
|
||||
* **データベース、フロントエンドなどに対する妥協はありません**。それらすべてと簡単に統合できます。
|
||||
### 無制限の「プラグイン」 { #unlimited-plug-ins }
|
||||
|
||||
### 無制限の「プラグイン」
|
||||
別の言い方をすれば、プラグインは不要で、必要なコードをインポートして使うだけです。
|
||||
|
||||
他の方法では、それらを必要とせず、必要なコードをインポートして使用します。
|
||||
あらゆる統合は(依存関係を用いて)非常に簡単に使えるよう設計されており、*path operation* で使うのと同じ構造と構文で、2 行のコードでアプリケーション用の「プラグイン」を作れます。
|
||||
|
||||
統合は非常に簡単に使用できるように設計されており(依存関係を用いて)、*path operations* で使用されているのと同じ構造と構文を使用して、2行のコードでアプリケーションの「プラグイン」を作成できます。
|
||||
### テスト済み { #tested }
|
||||
|
||||
* 100% の <dfn title="自動的にテストされるコードの量">テストカバレッジ</dfn>。
|
||||
* 100% <dfn title="Python の型アノテーション。これにより、エディタや外部ツールからより良い支援が受けられます">型アノテーション付き</dfn>のコードベース。
|
||||
* 本番アプリケーションで使用されています。
|
||||
|
||||
### テスト
|
||||
## Starletteの機能 { #starlette-features }
|
||||
|
||||
* <abbr title = "自動的にテストされるコードの量">テストカバレッジ</abbr> 100%
|
||||
* <abbr title = "Python型アノテーション。これにより、ユーザーはより良いエディターと外部ツールのサポート受けられる。">型アノテーション</abbr>100%のコードベース
|
||||
* 本番アプリケーションで使用されます
|
||||
**FastAPI** は <a href="https://www.starlette.dev/" class="external-link" target="_blank"><strong>Starlette</strong></a> と完全に互換性があり(かつそれに基づいています)。そのため、手元の Starlette の追加コードも動作します。
|
||||
|
||||
## Starletteの機能
|
||||
`FastAPI` は実際には `Starlette` のサブクラスです。すでに Starlette を知っている、あるいは使っているなら、ほとんどの機能は同じように動作します。
|
||||
|
||||
**FastAPI**は、<a href="https://www.starlette.dev/" class="external-link" target="_blank"><strong>Starlette </strong></a>と完全に互換性があります(そしてベースになっています)。したがって、追加のStarletteコードがあれば、それも機能します。
|
||||
**FastAPI** では **Starlette** のすべての機能が利用できます(FastAPI は強化された Starlette にすぎません):
|
||||
|
||||
`FastAPI`は実際には`Starlette`のサブクラスです。したがって、Starletteをすでに知っているか使用している場合は、ほとんどの機能が同じように機能します。
|
||||
* 圧倒的なパフォーマンス。<a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">利用可能な最速クラスの Python フレームワークの 1 つで、**NodeJS** や **Go** と同等です</a>。
|
||||
* **WebSocket** のサポート。
|
||||
* プロセス内バックグラウンドタスク。
|
||||
* 起動およびシャットダウンイベント。
|
||||
* HTTPX に基づくテストクライアント。
|
||||
* **CORS**、GZip、静的ファイル、ストリーミングレスポンス。
|
||||
* **セッションと Cookie** のサポート。
|
||||
* テストカバレッジ 100%。
|
||||
* 型アノテーション 100% のコードベース。
|
||||
|
||||
**FastAPI**を使用すると、以下のような、**Starlette**のすべての機能を利用できます(FastAPIはStarletteを強化したものにすぎないため):
|
||||
## Pydanticの機能 { #pydantic-features }
|
||||
|
||||
* 見事なパフォーマンス。<a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank"> **NodeJS**および**Go**に匹敵する、最速のPythonフレームワークの1つです。</a>
|
||||
**FastAPI** は <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a> と完全に互換性があり(かつそれに基づいています)。そのため、手元の Pydantic の追加コードも動作します。
|
||||
|
||||
* **WebSocket**のサポート
|
||||
* **GraphQL**のサポート
|
||||
* プロセス内バックグラウンドタスク
|
||||
* 起動およびシャットダウンイベント
|
||||
* `httpx`に基づいて構築されたテストクライアント
|
||||
* **CORS**、GZip、静的ファイル、ストリーミング応答
|
||||
* **セッションとCookie**のサポート
|
||||
* テストカバレッジ100%
|
||||
* 型アノテーション100%のコードベース
|
||||
Pydantic に基づく外部ライブラリ(データベース用の <abbr title="Object-Relational Mapper - オブジェクト関係マッパー">ORM</abbr>、<abbr title="Object-Document Mapper - オブジェクトドキュメントマッパー">ODM</abbr> など)も含まれます。
|
||||
|
||||
## Pydanticの特徴
|
||||
これは、すべてが自動的に検証されるため、多くの場合、リクエストから取得したオブジェクトを **そのままデータベースに** 渡せることを意味します。
|
||||
|
||||
**FastAPI**は<a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic </strong></a>と完全に互換性があります(そしてベースになっています)。したがって、追加のPydanticコードがあれば、それも機能します。
|
||||
逆方向も同様で、多くの場合、データベースから取得したオブジェクトを **そのままクライアントに** 渡せます。
|
||||
|
||||
データベースのために<abbr title = "Object-Relational Mapper">ORM</abbr>sや、<abbr title = "Object-Document Mapper">ODM</abbr>sなどの、Pydanticに基づく外部ライブラリを備えています。
|
||||
**FastAPI** では **Pydantic** のすべての機能が利用できます(FastAPI はデータ処理のすべてで Pydantic に基づいています):
|
||||
|
||||
これは、すべてが自動的に検証されるため、多くの場合、リクエストから取得したオブジェクトを**データベースに直接**渡すことができるということを意味しています。
|
||||
|
||||
同じことがその逆にも当てはまり、多くの場合、データベースから取得したオブジェクトを**クライアントに直接**渡すことができます。
|
||||
|
||||
**FastAPI**を使用すると、**Pydantic**のすべての機能を利用できます(FastAPIがPydanticに基づいてすべてのデータ処理を行っているため)。
|
||||
|
||||
* **brainfuckなし**:
|
||||
* スキーマ定義のためのマイクロ言語を新たに学習する必要はありません。
|
||||
* Pythonの型を知っている場合は、既にPydanticの使用方法を知っているに等しいです。
|
||||
* ユーザーの **<abbr title = "コードエディターに似た統合開発環境">IDE</abbr>/<abbr title = "コードエラーをチェックするプログラム">リンター</abbr>/思考 とうまく連携します**:
|
||||
* Pydanticのデータ構造は、ユーザーが定義するクラスの単なるインスタンスであるため、オートコンプリート、リンティング、mypy、およびユーザーの直感はすべて、検証済みのデータで適切に機能するはずです。
|
||||
* **複雑な構造**を検証:
|
||||
* 階層的なPydanticモデルや、Pythonの「`typing`」の「`list`」と「`dict`」などの利用。
|
||||
* バリデーターにより、複雑なデータスキーマを明確かつ簡単に定義、チェックし、JSONスキーマとして文書化できます。
|
||||
* 深く**ネストされたJSON**オブジェクトを作成し、それらすべてを検証してアノテーションを付けることができます。
|
||||
* **brainfuck なし**:
|
||||
* スキーマ定義のための新しいマイクロ言語を学ぶ必要はありません。
|
||||
* Python の型を知っていれば、Pydantic の使い方もわかります。
|
||||
* **<abbr title="Integrated Development Environment - 統合開発環境: コードエディタに類似">IDE</abbr>/<dfn title="コードのエラーを検査するプログラム">リンター</dfn>/思考** と気持ちよく連携します:
|
||||
* Pydantic のデータ構造は、あなたが定義するクラスの単なるインスタンスなので、オートコンプリート、リンティング、mypy、そしてあなたの直感が、検証済みデータに対して適切に機能します。
|
||||
* **複雑な構造** を検証:
|
||||
* 階層的な Pydantic モデルや、Python の `typing` にある `List` や `Dict` などを利用できます。
|
||||
* さらにバリデータにより、複雑なデータスキーマを明確かつ容易に定義・検査でき、JSON Schema として文書化できます。
|
||||
* 深く **ネストされた JSON** オブジェクトを扱え、それらすべてを検証してアノテーションを付与できます。
|
||||
* **拡張可能**:
|
||||
* Pydanticでは、カスタムデータ型を定義できます。または、バリデーターデコレーターで装飾されたモデルのメソッドを使用して検証を拡張できます。
|
||||
* Pydantic ではカスタムデータ型を定義できますし、バリデータデコレーターで装飾したモデルメソッドで検証を拡張できます。
|
||||
* テストカバレッジ 100%。
|
||||
|
||||
+209
-55
@@ -1,101 +1,255 @@
|
||||
# FastAPIを応援 - ヘルプの入手
|
||||
# FastAPIを応援 - ヘルプの入手 { #help-fastapi-get-help }
|
||||
|
||||
**FastAPI** は気に入りましたか?
|
||||
|
||||
FastAPIやユーザーや開発者を応援したいですか?
|
||||
FastAPIや他のユーザー、作者を応援したいですか?
|
||||
|
||||
もしくは、 **FastAPI** についてヘルプが必要ですか?
|
||||
それとも **FastAPI** についてヘルプが必要ですか?
|
||||
|
||||
とても簡単に応援できます (ただ1、2回クリックするだけのものもあります)。
|
||||
とても簡単に応援できる方法があります(1、2回クリックするだけのものもあります)。
|
||||
|
||||
また、ヘルプを入手する手段がいくつかあります。
|
||||
ヘルプを得る方法もいくつかあります。
|
||||
|
||||
## GitHubで **FastAPI** にStar
|
||||
## ニュースレターを購読 { #subscribe-to-the-newsletter }
|
||||
|
||||
GitHubでFastAPIに「Star」をつけることができます (右上部のStarボタンをクリック): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. ⭐️
|
||||
[**FastAPI and friends** ニュースレター](newsletter.md){.internal-link target=_blank}(配信はまれです)を購読すると、次の情報をキャッチアップできます:
|
||||
|
||||
スターを増やすことで、他のユーザーの目につきやすくなり、多くの人にとって便利なものであることを示せます。
|
||||
* FastAPI と関連プロジェクトのニュース 🚀
|
||||
* ガイド 📝
|
||||
* 機能 ✨
|
||||
* 互換性に影響する変更 🚨
|
||||
* ヒントやコツ ✅
|
||||
|
||||
## GitHubレポジトリのリリースをWatch
|
||||
## X (Twitter) で FastAPI をフォロー { #follow-fastapi-on-x-twitter }
|
||||
|
||||
GitHubでFastAPIを「Watch」できます (右上部のWatchボタンをクリック): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
|
||||
<a href="https://x.com/fastapi" class="external-link" target="_blank">**X (Twitter)** で @fastapi をフォロー</a>して、**FastAPI** の最新情報を受け取りましょう。🐦
|
||||
|
||||
## GitHubで **FastAPI** にStar { #star-fastapi-in-github }
|
||||
|
||||
GitHubでFastAPIに「Star」をつけることができます(右上部のStarボタンをクリック): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>。⭐️
|
||||
|
||||
スターを増やすことで、他のユーザーの目につきやすくなり、すでに多くの人の役に立っていることが伝わります。
|
||||
|
||||
## GitHubレポジトリのリリースをWatch { #watch-the-github-repository-for-releases }
|
||||
|
||||
GitHubでFastAPIを「Watch」できます(右上部の「Watch」ボタンをクリック): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>。👀
|
||||
|
||||
そこで「Releases only」を選択できます。
|
||||
|
||||
これを行うと、**FastAPI** バグ修正や新機能の実装などの新しいリリース (新しいバージョン) があるたびに (メールで) 通知を受け取れます。
|
||||
これを行うと、バグ修正や新機能を含む **FastAPI** の新しいリリース(新バージョン)があるたびに、(メールで)通知を受け取れます。
|
||||
|
||||
## 開発者とつながる
|
||||
## 開発者とつながる { #connect-with-the-author }
|
||||
|
||||
以下で、<a href="https://tiangolo.com" class="external-link" target="_blank">開発者 (Sebastián Ramírez / `tiangolo`)</a> とコンタクトをとれます:
|
||||
作者である<a href="https://tiangolo.com" class="external-link" target="_blank">私(Sebastián Ramírez / `tiangolo`)</a>とつながれます。
|
||||
|
||||
できること:
|
||||
|
||||
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">**GitHub** でフォロー</a>。
|
||||
* 他のオープンソースプロジェクトを確認できます。何かの助けになるものが見つかるかもしれません。
|
||||
* 新たなオープンソースプロジェクトを作成したときに通知されます。
|
||||
* <a href="https://x.com/tiangolo" class="external-link" target="_blank">**X (Twitter)** でフォロー</a>。
|
||||
* FastAPIの使用用途を教えてください (聞いてみたいです)。
|
||||
* 新たなツールの発表やリリースが聞けます。
|
||||
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">**Linkedin** でつながる</a>。
|
||||
* 新たなツールの発表やリリースが聞けます (ただしX (Twitter)の方が利用頻度が高いですが 🤷♂)。
|
||||
* <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> や <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a> で著作物を読む (またはフォロー)。
|
||||
* アイデアや作成ツールについての記事が読めます。
|
||||
* 新規記事の執筆を通知してくれます。
|
||||
* 役に立つかもしれない、私が作成した他のオープンソースプロジェクトを見られます。
|
||||
* 新しいオープンソースプロジェクトを作成したときにわかります。
|
||||
* <a href="https://x.com/tiangolo" class="external-link" target="_blank">**X (Twitter)** でフォロー</a> または <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>。
|
||||
* あなたがどのようにFastAPIを使っているか教えてください(聞けると嬉しいです)。
|
||||
* 新しいツールの告知やリリースを聞けます。
|
||||
* さらに、<a href="https://x.com/fastapi" class="external-link" target="_blank">X (Twitter) の @fastapi</a>(別アカウント)もフォローできます。
|
||||
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">**LinkedIn** でフォロー</a>。
|
||||
* 新しいツールの告知やリリースを聞けます(ただしX (Twitter) の方をよく使っています 🤷♂)。
|
||||
* <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> や <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a> で執筆内容を読む(またはフォロー)。
|
||||
* 私のアイデアや、作成したツールに関する記事を読めます。
|
||||
* 新しい記事を公開したときに読めます。
|
||||
|
||||
## **FastAPI** に関するツイート
|
||||
## **FastAPI** についてツイート { #tweet-about-fastapi }
|
||||
|
||||
<a href="https://x.com/compose/tweet?text=I'm loving FastAPI because... https://github.com/fastapi/fastapi cc @tiangolo" class="external-link" target="_blank">**FastAPI** についてツイート</a>し、開発者や他の人にどこが気に入ったのか教えてください。🎉
|
||||
<a href="https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI** についてツイート</a>して、なぜ気に入っているのかを私や他の人に教えてください。🎉
|
||||
|
||||
**FastAPI** がどのように使われ、どこが気に入られ、どんなプロジェクト/会社で使われているかなどについて知りたいです。
|
||||
**FastAPI** がどのように使われているか、どこを気に入っているか、どのプロジェクト/会社で使っているか等、聞けると嬉しいです。
|
||||
|
||||
## FastAPIに投票
|
||||
## FastAPIに投票 { #vote-for-fastapi }
|
||||
|
||||
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Slantで **FastAPI** に投票</a>
|
||||
* <a href="https://alternativeto.net/software/fastapi/" class="external-link" target="_blank">AlternativeToで **FastAPI** に投票</a>
|
||||
* <a href="https://github.com/marmelab/awesome-rest/pull/93" class="external-link" target="_blank">awesome-restで **FastAPI** に投票</a>
|
||||
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Slantで **FastAPI** に投票</a>。
|
||||
* <a href="https://alternativeto.net/software/fastapi/about/" class="external-link" target="_blank">AlternativeToで **FastAPI** に投票</a>。
|
||||
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">StackShare で **FastAPI** を使っていると宣言</a>。
|
||||
|
||||
## GitHub issuesで他の人を助ける
|
||||
## GitHubで質問に困っている人を助ける { #help-others-with-questions-in-github }
|
||||
|
||||
<a href="https://github.com/fastapi/fastapi/issues" class="external-link" target="_blank">既存のissues</a>を確認して、他の人を助けてみてください。皆さんが回答を知っているかもしれない質問がほとんどです。🤓
|
||||
次の場所で、他の人の質問を手助けできます:
|
||||
|
||||
## GitHubレポジトリをWatch
|
||||
* <a href="https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">GitHub Discussions</a>
|
||||
* <a href="https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+" class="external-link" target="_blank">GitHub Issues</a>
|
||||
|
||||
GitHubでFastAPIを「watch」できます (右上部の「watch」ボタンをクリック): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>. 👀
|
||||
多くの場合、その質問の答えをすでに知っているかもしれません。🤓
|
||||
|
||||
「Releases only」ではなく「Watching」を選択すると、新たなissueが立てられた際に通知されます。
|
||||
もし多くの人の質問に答えて助けてくれたなら、あなたは公式の[FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank}になります。🎉
|
||||
|
||||
そして、issueを解決し他の人を助けることができます。
|
||||
最も大事なポイントは「親切であること」を心がけることです。人はフラストレーションを抱えてやって来るので、必ずしも最良の聞き方をしているとは限りませんが、できる限り親切に対応しましょう。🤗
|
||||
|
||||
## issuesを立てる
|
||||
**FastAPI** コミュニティは親切で歓迎的であることを目指しています。同時に、いじめや他者への無礼な振る舞いは受け入れないでください。お互いを大事にしましょう。
|
||||
|
||||
GitHubレポジトリで<a href="https://github.com/fastapi/fastapi/issues/new/choose" class="external-link" target="_blank">新たなissueを立てられます</a>。例えば:
|
||||
---
|
||||
|
||||
* 質問、または、問題の報告
|
||||
* 新機能の提案
|
||||
以下は(Discussions や Issues で)他の人の質問を手助けする方法です:
|
||||
|
||||
**Note**: issueを立てた人は、他の人の手助けもお願いします。😉
|
||||
### 質問を理解する { #understand-the-question }
|
||||
|
||||
## プルリクエストをする
|
||||
* 質問者の「目的」やユースケースを理解できるか確認します。
|
||||
|
||||
以下の様な<a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">プルリクエストを作成</a>できます:
|
||||
* 次に、質問(大半は質問です)が「明確」か確認します。
|
||||
|
||||
* ドキュメントのタイプミスを修正。
|
||||
* 新たなドキュメントセクションを提案。
|
||||
* 既存のissue/バグを修正。
|
||||
* 新機能を追加。
|
||||
* 多くの場合、ユーザーが想像した解決策についての質問になっていますが、もっと「良い」方法があるかもしれません。問題やユースケースをよりよく理解できれば、より良い「代替解決策」を提案できるかもしれません。
|
||||
|
||||
## 開発者のスポンサーになる
|
||||
* 質問が理解できない場合は、さらに「詳細」を尋ねます。
|
||||
|
||||
<a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>を通して開発者を経済的にサポートできます。
|
||||
### 問題を再現する { #reproduce-the-problem }
|
||||
|
||||
そこで、感謝の気持ちを伝えるためにコーヒー☕️を買うことができます 😄。
|
||||
多くのケースや質問は、その人の「元のコード」に関係しています。
|
||||
|
||||
## FastAPIを強化するツールのスポンサーになる
|
||||
しばしばコードの断片だけが共有されますが、それでは問題を「再現」するには不十分です。
|
||||
|
||||
ドキュメントで見たように、FastAPIはStarletteとPydanticという巨人の肩に乗っています。
|
||||
* ローカルで同じエラーや挙動を確認できるように、またはユースケースをよりよく理解できるように、**コピー&ペースト**して実行できる<a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">最小の再現可能な例</a>の提供を依頼できます。
|
||||
|
||||
以下のスポンサーになることもできます:
|
||||
* とても寛大な気分なら、問題の説明だけをもとに、あなた自身でそのような**例を作成**してみることもできます。ただし時間がかかる可能性が高いので、まずは問題の明確化を依頼した方が良い場合もあります。
|
||||
|
||||
* <a href="https://github.com/sponsors/samuelcolvin" class="external-link" target="_blank">Samuel Colvin (Pydantic)</a>
|
||||
* <a href="https://github.com/sponsors/encode" class="external-link" target="_blank">Encode (Starlette, Uvicorn)</a>
|
||||
### 解決策を提案する { #suggest-solutions }
|
||||
|
||||
* 質問を理解できたら、可能な**回答**を提示できます。
|
||||
|
||||
* 多くの場合、相手の「根本的な問題やユースケース」を理解することが重要です。相手が試している方法より良い解決方法があるかもしれないからです。
|
||||
|
||||
### クローズを依頼する { #ask-to-close }
|
||||
|
||||
もし相手が返信してきて、あなたが問題を解決できたなら、おめでとう、**あなたはヒーロー**です!🦸
|
||||
|
||||
* その場合、次のように依頼できます:
|
||||
|
||||
* GitHub Discussions: コメントを**回答**としてマークしてもらう。
|
||||
* GitHub Issues: issue を**クローズ**してもらう。
|
||||
|
||||
## GitHubレポジトリをWatch { #watch-the-github-repository }
|
||||
|
||||
GitHubでFastAPIを「Watch」できます(右上部の「Watch」ボタンをクリック): <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">https://github.com/fastapi/fastapi</a>。👀
|
||||
|
||||
「Releases only」ではなく「Watching」を選択すると、新しい issue や質問が作成されたときに通知を受け取れます。新しい issue のみ、Discussions のみ、PR のみ、など通知対象を絞ることもできます。
|
||||
|
||||
その上で、そうした質問の解決を手助けできます。
|
||||
|
||||
## 質問する { #ask-questions }
|
||||
|
||||
GitHubレポジトリで<a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">新しい質問</a>を作成できます。例えば:
|
||||
|
||||
* **質問**をする、または**問題**について尋ねる。
|
||||
* 新しい**機能**を提案する。
|
||||
|
||||
**Note**: もしそうするなら、他の人の手助けもお願いします。😉
|
||||
|
||||
## プルリクエストをレビュー { #review-pull-requests }
|
||||
|
||||
他の人からのプルリクエストのレビューを手伝ってもらえます。
|
||||
|
||||
ここでも、できる限り親切であるようにしてください。🤗
|
||||
|
||||
---
|
||||
|
||||
プルリクエストをレビューするときのポイントです:
|
||||
|
||||
### 問題を理解する { #understand-the-problem }
|
||||
|
||||
* まず、そのプルリクエストが解決しようとしている**問題を理解**してください。長めの議論が GitHub Discussion や issue にあるかもしれません。
|
||||
|
||||
* その問題は実は**別の方法**で解決でき、プルリクエスト自体が不要な場合もあります。その場合は、その提案や質問をしても良いでしょう。
|
||||
|
||||
### スタイルは気にしすぎない { #dont-worry-about-style }
|
||||
|
||||
* コミットメッセージのスタイルなどはあまり気にしなくて大丈夫です。私は squash and merge を使い、コミットを手動で調整します。
|
||||
|
||||
* スタイルルールについても心配無用です。自動化ツールがすでにチェックしています。
|
||||
|
||||
ほかにスタイルや一貫性の要件があれば、私から直接依頼しますし、必要な変更を上に積む形でコミットを追加します。
|
||||
|
||||
### コードを確認 { #check-the-code }
|
||||
|
||||
* コードを確認して読み、妥当かどうかを見て、**ローカルで実行**し、本当に問題を解決しているか確かめてください。
|
||||
|
||||
* そのうえで、それを行ったことを**コメント**で伝えてください。そうすれば、実際に確認してくれたとわかります。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
残念ながら、承認が複数ついただけのPRを、そのまま信頼することはできません。
|
||||
|
||||
説明が魅力的なためか、3件、5件以上の承認がついていても、実際にPRを確認すると壊れていたり、バグがあったり、主張する問題を解決していなかったりすることが何度もありました。😅
|
||||
|
||||
ですので、実際にコードを読み、実行して確認し、それをコメントで知らせてもらえることが本当に重要です。🤓
|
||||
|
||||
///
|
||||
|
||||
* もしPRを簡素化できそうなら、その依頼をしても構いませんが、細かい点にこだわり過ぎる必要はありません。主観的な見方が多く(私にもあります 🙈)、基本的な点に集中できるとより良いでしょう。
|
||||
|
||||
### テスト { #tests }
|
||||
|
||||
* PRに**テスト**があるか確認を手伝ってください。
|
||||
|
||||
* PR前はテストが**失敗**することを確認します。🚨
|
||||
|
||||
* そしてPR後にテストが**成功**することを確認します。✅
|
||||
|
||||
* 多くのPRにはテストがありません。テストの追加を**リマインド**したり、テストを**提案**したりできます。これは最も時間を消費する部分の一つで、大いに助けになります。
|
||||
|
||||
* 何を試したかもコメントしてください。そうすれば、確認してくれたことがわかります。🤓
|
||||
|
||||
## プルリクエストを作成 { #create-a-pull-request }
|
||||
|
||||
[貢献](contributing.md){.internal-link target=_blank}として、次のようにプルリクエストでソースコードに貢献できます:
|
||||
|
||||
* ドキュメントで見つけたタイポの修正。
|
||||
* 自分が作成/発見した FastAPI に関する記事・動画・ポッドキャストを、<a href="https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">このファイルを編集</a>して共有。
|
||||
* 該当セクションの先頭にリンクを追加してください。
|
||||
* 自分の言語への[ドキュメント翻訳を手伝う](contributing.md#translations){.internal-link target=_blank}。
|
||||
* 他の人が作成した翻訳のレビューも手伝えます。
|
||||
* 新しいドキュメントセクションの提案。
|
||||
* 既存のissue/バグの修正。
|
||||
* テストを追加してください。
|
||||
* 新機能の追加。
|
||||
* テストを追加してください。
|
||||
* 関連があればドキュメントも追加してください。
|
||||
|
||||
## FastAPIのメンテナンスを手伝う { #help-maintain-fastapi }
|
||||
|
||||
**FastAPI** のメンテナンスを手伝ってください!🤓
|
||||
|
||||
やることはたくさんあり、その多くは**あなた**にもできます。
|
||||
|
||||
今すぐできる主なタスクは次のとおりです:
|
||||
|
||||
* [GitHubで質問に困っている人を助ける](#help-others-with-questions-in-github){.internal-link target=_blank}(上のセクションを参照)。
|
||||
* [プルリクエストをレビュー](#review-pull-requests){.internal-link target=_blank}(上のセクションを参照)。
|
||||
|
||||
この2つが**最も時間を消費**します。FastAPI のメンテナンス作業の中心です。
|
||||
|
||||
これを手伝ってもらえると、**FastAPIのメンテナンスに貢献**し、**より速く・より良く前進**できるようになります。🚀
|
||||
|
||||
## チャットに参加 { #join-the-chat }
|
||||
|
||||
👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">Discord チャットサーバー</a> 👥 に参加し、FastAPI コミュニティのみんなと交流しましょう。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
質問は <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions</a> に投稿してください。そこなら[FastAPI Experts](fastapi-people.md#fastapi-experts){.internal-link target=_blank}から助けてもらえる可能性がずっと高いです。
|
||||
|
||||
チャットは一般的な会話のみに使いましょう。
|
||||
|
||||
///
|
||||
|
||||
### 質問でチャットを使わない { #dont-use-the-chat-for-questions }
|
||||
|
||||
チャットは「自由な会話」がしやすいため、一般的すぎて答えにくい質問になりがちです。そのため、回答が得られない可能性があります。
|
||||
|
||||
GitHub では、テンプレートが正しい形で質問を書くのを助けてくれるため、良い回答を得やすくなりますし、質問する前に自分で問題を解決できることもあります。さらにGitHubなら、時間がかかっても私が必ずすべてに回答できるようにできます。チャットでは私個人にはそれができません。😅
|
||||
|
||||
チャットでの会話はGitHubほど検索しやすくないため、質問と回答が会話に埋もれがちです。そして、[FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank}になるためにカウントされるのはGitHub上の活動だけです。ですから、GitHubの方が注目を集めやすいでしょう。
|
||||
|
||||
一方で、チャットには数千人のユーザーがいるため、ほぼ常に誰かと会話できる可能性が高いです。😄
|
||||
|
||||
## 作者をスポンサー { #sponsor-the-author }
|
||||
|
||||
あなたの**製品/会社**が **FastAPI** に依存している、または関連しており、そのユーザーにリーチしたい場合は、<a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a> を通じて作者(私)を支援できます。プランに応じて、ドキュメントにバッジが表示されるなどの特典がある場合があります。🎁
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
# 歴史、設計、そしてこれから
|
||||
# 歴史、設計、そしてこれから { #history-design-and-future }
|
||||
|
||||
少し前に、<a href="https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">**FastAPI**
|
||||
のユーザーに以下の様に尋ねられました</a>:
|
||||
少し前に、<a href="https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">**FastAPI**のユーザーに以下の様に尋ねられました</a>:
|
||||
|
||||
> このプロジェクトの歴史は?何もないところから、数週間ですごいものができているようです。 [...]
|
||||
|
||||
これがその歴史のほんの一部です。
|
||||
|
||||
## 代替手段
|
||||
## 代替手段 { #alternatives }
|
||||
|
||||
数年前から、私は複雑な要件を持つAPI (機械学習、分散システム、非同期ジョブ、NoSQLデータベースなど) を作成しており、いくつかの開発者チームを率いています。
|
||||
|
||||
@@ -19,7 +18,7 @@
|
||||
|
||||
<blockquote markdown="1">
|
||||
|
||||
**FastAPI**は、代替ツールのこれまでの働きがなければ存在しなかったでしょう。
|
||||
**FastAPI**は、他の人々のこれまでの働きがなければ存在しなかったでしょう。
|
||||
|
||||
以前に作られた多くのツールが、作成における刺激として役立ってきました。
|
||||
|
||||
@@ -29,7 +28,7 @@
|
||||
|
||||
</blockquote>
|
||||
|
||||
## 調査
|
||||
## 調査 { #investigation }
|
||||
|
||||
すべて既存の代替手段を使うことで、そのすべてを学び、アイデアを得て、自分や一緒に仕事をしてきた開発者のチームにとって最良の方法で組み合わせる機会を得ました。
|
||||
|
||||
@@ -39,7 +38,7 @@
|
||||
|
||||
そこで、**FastAPI**のコードを書き始める前に、OpenAPI、JSON Schema、OAuth2などの仕様を数ヶ月かけて勉強し、それらの関係、重複する箇所、相違点を理解しました。
|
||||
|
||||
## 設計
|
||||
## 設計 { #design }
|
||||
|
||||
その後、 (FastAPIを使う開発者として) ユーザーが欲しい「API」の設計に時間を費やしました。
|
||||
|
||||
@@ -53,19 +52,19 @@
|
||||
|
||||
すべての箇所で、すべての開発者に最高の開発体験を提供しました。
|
||||
|
||||
## 要件
|
||||
## 要件 { #requirements }
|
||||
|
||||
いくつかの代替手法を試したあと、私は<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">**Pydantic**</a>の強みを利用することを決めました。
|
||||
|
||||
そして、JSON Schemaに完全に準拠するようにしたり、制約宣言を定義するさまざまな方法をサポートしたり、いくつかのエディターでのテストに基づいてエディターのサポート (型チェック、自動補完) を改善するために貢献しました。
|
||||
|
||||
開発中、もう1つの重要な鍵となる<a href="https://www.starlette.dev/" class="external-link" target="_blank">**Starlette**</a>、にも貢献しました。
|
||||
開発中、もう1つの重要な鍵となる<a href="https://www.starlette.dev/" class="external-link" target="_blank">**Starlette**</a>にも貢献しました。
|
||||
|
||||
## 開発
|
||||
## 開発 { #development }
|
||||
|
||||
私が**FastAPI**自体の作成を開始した時には、ほとんどの部分がすでに準備されており、設計が定義され、必要な条件とツールの準備ができていました。そして規格や仕様に関する知識が、明確になり、更新されていました。
|
||||
|
||||
## これから
|
||||
## これから { #future }
|
||||
|
||||
この時点ですでに、これらのアイデアを持った**FastAPI**が多くの人の役に立っていることは明らかです。
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# 古い 403 認証エラーのステータスコードを使う { #use-old-403-authentication-error-status-codes }
|
||||
|
||||
FastAPI バージョン `0.122.0` より前は、統合されたセキュリティユーティリティが認証に失敗してクライアントへエラーを返す際、HTTP ステータスコード `403 Forbidden` を使用していました。
|
||||
|
||||
FastAPI バージョン `0.122.0` 以降では、より適切な HTTP ステータスコード `401 Unauthorized` を使用し、HTTP 仕様に従ってレスポンスに妥当な `WWW-Authenticate` ヘッダーを含めます。<a href="https://datatracker.ietf.org/doc/html/rfc7235#section-3.1" class="external-link" target="_blank">RFC 7235</a>、<a href="https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized" class="external-link" target="_blank">RFC 9110</a>。
|
||||
|
||||
しかし、何らかの理由でクライアントが従来の挙動に依存している場合は、セキュリティクラスでメソッド `make_not_authenticated_error` をオーバーライドすることで、その挙動に戻せます。
|
||||
|
||||
たとえば、既定の `401 Unauthorized` エラーの代わりに `403 Forbidden` エラーを返す `HTTPBearer` のサブクラスを作成できます:
|
||||
|
||||
{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
この関数は例外インスタンスを返す点に注意してください。ここでは例外を送出しません。送出は内部の他のコードで行われます。
|
||||
|
||||
///
|
||||
@@ -1,8 +1,8 @@
|
||||
# 条件付き OpenAPI
|
||||
# 条件付き OpenAPI { #conditional-openapi }
|
||||
|
||||
必要であれば、設定と環境変数を利用して、環境に応じて条件付きでOpenAPIを構成することが可能です。また、完全にOpenAPIを無効にすることもできます。
|
||||
|
||||
## セキュリティとAPI、およびドキュメントについて
|
||||
## セキュリティとAPI、およびドキュメントについて { #about-security-apis-and-docs }
|
||||
|
||||
本番環境においてドキュメントのUIを非表示にすることによって、APIを保護しようと *すべきではありません*。
|
||||
|
||||
@@ -10,26 +10,26 @@
|
||||
|
||||
もしセキュリティ上の欠陥がソースコードにあるならば、それは存在したままです。
|
||||
|
||||
ドキュメンテーションを非表示にするのは、単にあなたのAPIへのアクセス方法を難解にするだけでなく、同時にあなた自身の本番環境でのAPIのデバッグを困難にしてしまう可能性があります。単純に、 <a href="https://en.wikipedia.org/wiki/Security_through_obscurity" class="external-link" target="_blank">Security through obscurity</a> の一つの形態として考えられるでしょう。
|
||||
ドキュメンテーションを非表示にするのは、単にあなたのAPIへのアクセス方法を難解にするだけでなく、同時にあなた自身の本番環境でのAPIのデバッグを困難にしてしまう可能性があります。単純に、 <a href="https://en.wikipedia.org/wiki/Security_through_obscurity" class="external-link" target="_blank">秘匿によるセキュリティ</a> の一つの形態として考えられるでしょう。
|
||||
|
||||
もしあなたのAPIのセキュリティを強化したいなら、いくつかのよりよい方法があります。例を示すと、
|
||||
|
||||
* リクエストボディとレスポンスのためのPydanticモデルの定義を見直す。
|
||||
* 依存関係に基づきすべての必要なパーミッションとロールを設定する。
|
||||
* パスワードを絶対に平文で保存しない。パスワードハッシュのみを保存する。
|
||||
* PasslibやJWTトークンに代表される、よく知られた暗号化ツールを使って実装する。
|
||||
* pwdlibやJWTトークンに代表される、よく知られた暗号化ツールを使って実装する。
|
||||
* そして必要なところでは、もっと細かいパーミッション制御をOAuth2スコープを使って行う。
|
||||
* など
|
||||
* ...など
|
||||
|
||||
それでも、例えば本番環境のような特定の環境のみで、あるいは環境変数の設定によってAPIドキュメントをどうしても無効にしたいという、非常に特殊なユースケースがあるかもしれません。
|
||||
|
||||
## 設定と環境変数による条件付き OpenAPI
|
||||
## 設定と環境変数による条件付き OpenAPI { #conditional-openapi-from-settings-and-env-vars }
|
||||
|
||||
生成するOpenAPIとドキュメントUIの構成は、共通のPydanticの設定を使用して簡単に切り替えられます。
|
||||
|
||||
例えば、
|
||||
|
||||
{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *}
|
||||
{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
|
||||
|
||||
ここでは `openapi_url` の設定を、デフォルトの `"/openapi.json"` のまま宣言しています。
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Swagger UI の設定 { #configure-swagger-ui }
|
||||
|
||||
いくつかの追加の <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/" class="external-link" target="_blank">Swagger UI パラメータ</a>を設定できます。
|
||||
|
||||
設定するには、`FastAPI()` のアプリオブジェクトを作成するとき、または `get_swagger_ui_html()` 関数に `swagger_ui_parameters` 引数を渡します。
|
||||
|
||||
`swagger_ui_parameters` は、Swagger UI に直接渡される設定を含む辞書を受け取ります。
|
||||
|
||||
FastAPI はそれらの設定を **JSON** に変換し、JavaScript と互換にします。Swagger UI が必要とするのはこの形式です。
|
||||
|
||||
## シンタックスハイライトを無効化 { #disable-syntax-highlighting }
|
||||
|
||||
例えば、Swagger UI のシンタックスハイライトを無効化できます。
|
||||
|
||||
設定を変更しなければ、シンタックスハイライトはデフォルトで有効です:
|
||||
|
||||
<img src="/img/tutorial/extending-openapi/image02.png">
|
||||
|
||||
しかし、`syntaxHighlight` を `False` に設定すると無効化できます:
|
||||
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}
|
||||
|
||||
...その場合、Swagger UI ではシンタックスハイライトが表示されなくなります:
|
||||
|
||||
<img src="/img/tutorial/extending-openapi/image03.png">
|
||||
|
||||
## テーマの変更 { #change-the-theme }
|
||||
|
||||
同様に、キー `"syntaxHighlight.theme"`(途中にドットが含まれている点に注意)でシンタックスハイライトのテーマを設定できます:
|
||||
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}
|
||||
|
||||
この設定により、シンタックスハイライトの配色テーマが変わります:
|
||||
|
||||
<img src="/img/tutorial/extending-openapi/image04.png">
|
||||
|
||||
## 既定の Swagger UI パラメータの変更 { #change-default-swagger-ui-parameters }
|
||||
|
||||
FastAPI には、多くのユースケースに適した既定の設定パラメータが含まれています。
|
||||
|
||||
既定では次の設定が含まれます:
|
||||
|
||||
{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}
|
||||
|
||||
引数 `swagger_ui_parameters` に別の値を指定することで、これらを上書きできます。
|
||||
|
||||
例えば、`deepLinking` を無効化するには、次の設定を `swagger_ui_parameters` に渡します:
|
||||
|
||||
{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}
|
||||
|
||||
## その他の Swagger UI パラメータ { #other-swagger-ui-parameters }
|
||||
|
||||
利用可能な他のすべての設定については、公式の <a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/" class="external-link" target="_blank">Swagger UI パラメータのドキュメント</a>を参照してください。
|
||||
|
||||
## JavaScript 専用の設定 { #javascript-only-settings }
|
||||
|
||||
Swagger UI では、他にも **JavaScript 専用** のオブジェクト(例: JavaScript の関数)による設定が可能です。
|
||||
|
||||
FastAPI には、次の JavaScript 専用の `presets` 設定も含まれています:
|
||||
|
||||
```JavaScript
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIBundle.SwaggerUIStandalonePreset
|
||||
]
|
||||
```
|
||||
|
||||
これらは文字列ではなく **JavaScript** のオブジェクトであるため、Python のコードから直接渡すことはできません。
|
||||
|
||||
そのような JavaScript 専用の設定を使う必要がある場合は、上記のいずれかの方法を使用し、Swagger UI の path operation をオーバーライドして、必要な JavaScript を手動で記述してください。
|
||||
@@ -0,0 +1,185 @@
|
||||
# カスタムドキュメント UI の静的アセット(セルフホスティング) { #custom-docs-ui-static-assets-self-hosting }
|
||||
|
||||
API ドキュメントは **Swagger UI** と **ReDoc** を使用しており、それぞれにいくつかの JavaScript と CSS ファイルが必要です。
|
||||
|
||||
既定では、これらのファイルは <abbr title="Content Delivery Network - コンテンツ配信ネットワーク: 通常は複数のサーバーで構成され、JavaScript や CSS などの静的ファイルを提供するサービス。クライアントに近いサーバーからそれらのファイルを配信することで、パフォーマンスを改善するためによく使われます。">CDN</abbr> から配信されます。
|
||||
|
||||
しかし、カスタマイズすることも可能で、特定の CDN を指定したり、自分でファイルを配信したりできます。
|
||||
|
||||
## JavaScript と CSS のカスタム CDN { #custom-cdn-for-javascript-and-css }
|
||||
|
||||
別の <abbr title="Content Delivery Network - コンテンツ配信ネットワーク">CDN</abbr> を使いたいとします。例えば `https://unpkg.com/` を使いたい場合です。
|
||||
|
||||
例えば、一部の URL が制限されている国に住んでいる場合に役立ちます。
|
||||
|
||||
### 自動ドキュメントの無効化 { #disable-the-automatic-docs }
|
||||
|
||||
最初の手順は自動ドキュメントを無効化することです。デフォルトではそれらは既定の CDN を使用します。
|
||||
|
||||
無効化するには、`FastAPI` アプリ作成時にそれらの URL を `None` に設定します:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
|
||||
|
||||
### カスタムドキュメントの追加 { #include-the-custom-docs }
|
||||
|
||||
これで、カスタムドキュメント用の *path operations* を作成できます。
|
||||
|
||||
FastAPI の内部関数を再利用してドキュメント用の HTML ページを生成し、必要な引数を渡せます:
|
||||
|
||||
- `openapi_url`: ドキュメントの HTML ページが API の OpenAPI スキーマを取得する URL。ここでは属性 `app.openapi_url` を使用できます。
|
||||
- `title`: API のタイトル。
|
||||
- `oauth2_redirect_url`: 既定値を使うにはここで `app.swagger_ui_oauth2_redirect_url` を使用できます。
|
||||
- `swagger_js_url`: Swagger UI ドキュメント用の HTML が取得する JavaScript ファイルの URL。これはカスタム CDN の URL です。
|
||||
- `swagger_css_url`: Swagger UI ドキュメント用の HTML が取得する CSS ファイルの URL。これはカスタム CDN の URL です。
|
||||
|
||||
ReDoc についても同様です...
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`swagger_ui_redirect` 用の *path operation* は、OAuth2 を使用する場合の補助です。
|
||||
|
||||
API を OAuth2 プロバイダと統合すると、認証を実行して取得したクレデンシャルを持った状態で API ドキュメントに戻れます。そして実際の OAuth2 認証を用いてドキュメント上から API と対話できます。
|
||||
|
||||
Swagger UI がこの処理を裏側で行いますが、そのためにこの「redirect」の補助が必要です。
|
||||
|
||||
///
|
||||
|
||||
### テスト用の *path operation* を作成 { #create-a-path-operation-to-test-it }
|
||||
|
||||
すべてが動作するかをテストできるように、*path operation* を作成します:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
|
||||
|
||||
### テスト { #test-it }
|
||||
|
||||
これで、<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> にアクセスしてページを再読み込みすると、新しい CDN からそれらのアセットが読み込まれるはずです。
|
||||
|
||||
## ドキュメント用 JavaScript と CSS のセルフホスティング { #self-hosting-javascript-and-css-for-docs }
|
||||
|
||||
オフライン(インターネット非接続)でも、あるいはローカルネットワークで、アプリを動作させたい場合などには、JavaScript と CSS をセルフホストするのが有用です。
|
||||
|
||||
ここでは、同じ FastAPI アプリ内でそれらのファイルを配信し、ドキュメントでそれらを使用するように設定する方法を示します。
|
||||
|
||||
### プロジェクトのファイル構成 { #project-file-structure }
|
||||
|
||||
プロジェクトのファイル構成が次のようになっているとします:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
```
|
||||
|
||||
これらの静的ファイルを保存するためのディレクトリを作成します。
|
||||
|
||||
新しいファイル構成は次のようになります:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
└── static/
|
||||
```
|
||||
|
||||
### ファイルのダウンロード { #download-the-files }
|
||||
|
||||
ドキュメントに必要な静的ファイルをダウンロードし、`static/` ディレクトリに配置します。
|
||||
|
||||
各リンクを右クリックして「リンク先を別名で保存...」のようなオプションを選べます。
|
||||
|
||||
**Swagger UI** では次のファイルを使用します:
|
||||
|
||||
- <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
|
||||
- <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
|
||||
|
||||
そして **ReDoc** では次のファイルを使用します:
|
||||
|
||||
- <a href="https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a>
|
||||
|
||||
その後、ファイル構成は次のようになります:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
└── static
|
||||
├── redoc.standalone.js
|
||||
├── swagger-ui-bundle.js
|
||||
└── swagger-ui.css
|
||||
```
|
||||
|
||||
### 静的ファイルの配信 { #serve-the-static-files }
|
||||
|
||||
- `StaticFiles` をインポートします。
|
||||
- 特定のパスに `StaticFiles()` インスタンスを「マウント」します。
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
|
||||
|
||||
### 静的ファイルのテスト { #test-the-static-files }
|
||||
|
||||
アプリケーションを起動し、<a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a> にアクセスします。
|
||||
|
||||
**ReDoc** 用の非常に長い JavaScript ファイルが表示されるはずです。
|
||||
|
||||
先頭は次のようになっているかもしれません:
|
||||
|
||||
```JavaScript
|
||||
/*! For license information please see redoc.standalone.js.LICENSE.txt */
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
|
||||
...
|
||||
```
|
||||
|
||||
これで、アプリから静的ファイルを配信できていること、そしてドキュメント用の静的ファイルを正しい場所に配置できていることが確認できます。
|
||||
|
||||
次に、ドキュメントでそれらの静的ファイルを使用するようにアプリを設定します。
|
||||
|
||||
### 静的ファイル用に自動ドキュメントを無効化 { #disable-the-automatic-docs-for-static-files }
|
||||
|
||||
カスタム CDN を使う場合と同様、最初の手順は自動ドキュメントを無効化することです。既定では CDN を使用します。
|
||||
|
||||
無効化するには、`FastAPI` アプリ作成時にそれらの URL を `None` に設定します:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
|
||||
|
||||
### 静的ファイル用のカスタムドキュメントを追加 { #include-the-custom-docs-for-static-files }
|
||||
|
||||
カスタム CDN と同様の方法で、カスタムドキュメント用の *path operations* を作成できます。
|
||||
|
||||
再び、FastAPI の内部関数を再利用してドキュメント用の HTML ページを生成し、必要な引数を渡します:
|
||||
|
||||
- `openapi_url`: ドキュメントの HTML ページが API の OpenAPI スキーマを取得する URL。ここでは属性 `app.openapi_url` を使用できます。
|
||||
- `title`: API のタイトル。
|
||||
- `oauth2_redirect_url`: 既定値を使うにはここで `app.swagger_ui_oauth2_redirect_url` を使用できます。
|
||||
- `swagger_js_url`: Swagger UI ドキュメント用の HTML が取得する **JavaScript** ファイルの URL。**これはあなたのアプリ自身がいま配信しているものです**。
|
||||
- `swagger_css_url`: Swagger UI ドキュメント用の HTML が取得する **CSS** ファイルの URL。**これはあなたのアプリ自身がいま配信しているものです**。
|
||||
|
||||
ReDoc についても同様です...
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`swagger_ui_redirect` 用の *path operation* は、OAuth2 を使用する場合の補助です。
|
||||
|
||||
API を OAuth2 プロバイダと統合すると、認証を実行して取得したクレデンシャルを持った状態で API ドキュメントに戻れます。そして実際の OAuth2 認証を用いてドキュメント上から API と対話できます。
|
||||
|
||||
Swagger UI がこの処理を裏側で行いますが、そのためにこの「redirect」の補助が必要です。
|
||||
|
||||
///
|
||||
|
||||
### 静的ファイルをテストするための *path operation* を作成 { #create-a-path-operation-to-test-static-files }
|
||||
|
||||
すべてが動作するかをテストできるように、*path operation* を作成します:
|
||||
|
||||
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
|
||||
|
||||
### 静的ファイル UI のテスト { #test-static-files-ui }
|
||||
|
||||
これで、WiFi を切断して <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> にアクセスし、ページを再読み込みできるはずです。
|
||||
|
||||
インターネットに接続していなくても、API のドキュメントを表示し、API と対話できます。
|
||||
@@ -0,0 +1,109 @@
|
||||
# カスタム Request と APIRoute クラス { #custom-request-and-apiroute-class }
|
||||
|
||||
場合によっては、`Request` や `APIRoute` クラスで使われるロジックを上書きしたいことがあります。
|
||||
|
||||
特に、ミドルウェアでのロジックの代替として有効な場合があります。
|
||||
|
||||
たとえば、アプリケーションで処理される前にリクエストボディを読み取ったり操作したりしたい場合です。
|
||||
|
||||
/// danger | 警告
|
||||
|
||||
これは「上級」機能です。
|
||||
|
||||
FastAPI を始めたばかりの場合は、このセクションは読み飛ばしてもよいでしょう。
|
||||
|
||||
///
|
||||
|
||||
## ユースケース { #use-cases }
|
||||
|
||||
ユースケースの例:
|
||||
|
||||
* JSON ではないリクエストボディを JSON に変換する(例: <a href="https://msgpack.org/index.html" class="external-link" target="_blank">`msgpack`</a>)。
|
||||
* gzip 圧縮されたリクエストボディの解凍。
|
||||
* すべてのリクエストボディの自動ロギング。
|
||||
|
||||
## カスタムリクエストボディのエンコーディングの処理 { #handling-custom-request-body-encodings }
|
||||
|
||||
gzip のリクエストを解凍するために、カスタムの `Request` サブクラスを使う方法を見ていきます。
|
||||
|
||||
そして、そのカスタムリクエストクラスを使うための `APIRoute` サブクラスを用意します。
|
||||
|
||||
### カスタム `GzipRequest` クラスの作成 { #create-a-custom-gziprequest-class }
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これは仕組みを示すためのサンプルです。Gzip 対応が必要な場合は、用意されている [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank} を使用できます。
|
||||
|
||||
///
|
||||
|
||||
まず、`GzipRequest` クラスを作成します。これは適切なヘッダーがある場合に本体を解凍するよう、`Request.body()` メソッドを上書きします。
|
||||
|
||||
ヘッダーに `gzip` がなければ、解凍は試みません。
|
||||
|
||||
この方法により、同じルートクラスで gzip 圧縮済み/未圧縮のリクエストの両方を扱えます。
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}
|
||||
|
||||
### カスタム `GzipRoute` クラスの作成 { #create-a-custom-gziproute-class }
|
||||
|
||||
次に、`GzipRequest` を利用する `fastapi.routing.APIRoute` のカスタムサブクラスを作成します。
|
||||
|
||||
ここでは `APIRoute.get_route_handler()` メソッドを上書きします。
|
||||
|
||||
このメソッドは関数を返します。そしてその関数がリクエストを受け取り、レスポンスを返します。
|
||||
|
||||
ここでは、元のリクエストから `GzipRequest` を作成するために利用します。
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
`Request` には `request.scope` 属性があり、これはリクエストに関するメタデータを含む Python の `dict` です。
|
||||
|
||||
`Request` には `request.receive` もあり、これはリクエストの本体を「受信」するための関数です。
|
||||
|
||||
`scope` の `dict` と `receive` 関数はいずれも ASGI 仕様の一部です。
|
||||
|
||||
そしてこの 2 つ(`scope` と `receive`)が、新しい `Request` インスタンスを作成するために必要なものです。
|
||||
|
||||
`Request` について詳しくは、<a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">Starlette の Requests に関するドキュメント</a> を参照してください。
|
||||
|
||||
///
|
||||
|
||||
`GzipRequest.get_route_handler` が返す関数が異なるのは、`Request` を `GzipRequest` に変換する点だけです。
|
||||
|
||||
これにより、`GzipRequest` は必要に応じてデータを解凍してから *path operations* に渡します。
|
||||
|
||||
それ以降の処理ロジックはすべて同じです。
|
||||
|
||||
ただし、`GzipRequest.body` を変更しているため、必要に応じて **FastAPI** によって読み込まれる際にリクエストボディが自動的に解凍されます。
|
||||
|
||||
## 例外ハンドラでのリクエストボディへのアクセス { #accessing-the-request-body-in-an-exception-handler }
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
同じ問題を解決するには、`RequestValidationError` 用のカスタムハンドラで `body` を使う方がずっと簡単でしょう([エラー処理](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank})。
|
||||
|
||||
ただし、この例も有効で、内部コンポーネントとどのようにやり取りするかを示しています。
|
||||
|
||||
///
|
||||
|
||||
同じアプローチを使って、例外ハンドラ内でリクエストボディにアクセスすることもできます。
|
||||
|
||||
やることは、`try`/`except` ブロックの中でリクエストを処理するだけです:
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}
|
||||
|
||||
例外が発生しても、`Request` インスタンスはスコープ内に残るため、エラー処理時にリクエストボディを読み取り、活用できます:
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}
|
||||
|
||||
## ルーターでのカスタム `APIRoute` クラス { #custom-apiroute-class-in-a-router }
|
||||
|
||||
`APIRouter` の `route_class` パラメータを設定することもできます:
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}
|
||||
|
||||
この例では、`router` 配下の *path operations* はカスタムの `TimedRoute` クラスを使用し、レスポンスの生成にかかった時間を示す追加の `X-Response-Time` ヘッダーがレスポンスに含まれます:
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}
|
||||
@@ -0,0 +1,80 @@
|
||||
# OpenAPI の拡張 { #extending-openapi }
|
||||
|
||||
生成された OpenAPI スキーマを変更する必要がある場合があります。
|
||||
|
||||
このセクションではその方法を説明します。
|
||||
|
||||
## 通常のプロセス { #the-normal-process }
|
||||
|
||||
通常(デフォルト)のプロセスは次のとおりです。
|
||||
|
||||
`FastAPI` アプリケーション(インスタンス)には、OpenAPI スキーマを返すことが期待される `.openapi()` メソッドがあります。
|
||||
|
||||
アプリケーションオブジェクトの作成時に、`/openapi.json`(または `openapi_url` に設定したパス)への path operation が登録されます。
|
||||
|
||||
これは単に、アプリケーションの `.openapi()` メソッドの結果を含む JSON レスポンスを返します。
|
||||
|
||||
デフォルトでは、`.openapi()` メソッドはプロパティ `.openapi_schema` に内容があるかを確認し、あればそれを返します。
|
||||
|
||||
なければ、`fastapi.openapi.utils.get_openapi` にあるユーティリティ関数を使って生成します。
|
||||
|
||||
この関数 `get_openapi()` は次の引数を受け取ります:
|
||||
|
||||
- `title`: ドキュメントに表示される OpenAPI のタイトル。
|
||||
- `version`: API のバージョン。例: `2.5.0`。
|
||||
- `openapi_version`: 使用する OpenAPI 仕様のバージョン。デフォルトは最新の `3.1.0`。
|
||||
- `summary`: API の短い概要。
|
||||
- `description`: API の説明。Markdown を含めることができ、ドキュメントに表示されます。
|
||||
- `routes`: ルートのリスト。登録済みの各 path operation です。`app.routes` から取得されます。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
パラメータ `summary` は OpenAPI 3.1.0 以降で利用可能で、FastAPI 0.99.0 以降が対応しています。
|
||||
|
||||
///
|
||||
|
||||
## デフォルトの上書き { #overriding-the-defaults }
|
||||
|
||||
上記の情報を使って、同じユーティリティ関数で OpenAPI スキーマを生成し、必要な部分を上書きできます。
|
||||
|
||||
たとえば、<a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">カスタムロゴを含めるための ReDoc の OpenAPI 拡張</a>を追加してみましょう。
|
||||
|
||||
### 通常の **FastAPI** { #normal-fastapi }
|
||||
|
||||
まず、通常どおりに **FastAPI** アプリケーションを実装します:
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}
|
||||
|
||||
### OpenAPI スキーマの生成 { #generate-the-openapi-schema }
|
||||
|
||||
次に、`custom_openapi()` 関数内で同じユーティリティ関数を使って OpenAPI スキーマを生成します:
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}
|
||||
|
||||
### OpenAPI スキーマの変更 { #modify-the-openapi-schema }
|
||||
|
||||
OpenAPI スキーマの `info`「オブジェクト」にカスタムの `x-logo` を追加して、ReDoc 拡張を加えます:
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}
|
||||
|
||||
### OpenAPI スキーマのキャッシュ { #cache-the-openapi-schema }
|
||||
|
||||
生成したスキーマを保持する「キャッシュ」として `.openapi_schema` プロパティを利用できます。
|
||||
|
||||
こうすることで、ユーザーが API ドキュメントを開くたびにスキーマを生成する必要がなくなります。
|
||||
|
||||
最初の1回だけ生成され、その後は同じキャッシュ済みスキーマが以降のリクエストで使われます。
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}
|
||||
|
||||
### メソッドの上書き { #override-the-method }
|
||||
|
||||
これで、`.openapi()` メソッドを新しい関数に置き換えられます。
|
||||
|
||||
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}
|
||||
|
||||
### 確認 { #check-it }
|
||||
|
||||
<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> にアクセスすると、カスタムロゴ(この例では **FastAPI** のロゴ)が使われていることが確認できます:
|
||||
|
||||
<img src="/img/tutorial/extending-openapi/image01.png">
|
||||
@@ -0,0 +1,39 @@
|
||||
# 一般 - ハウツー - レシピ { #general-how-to-recipes }
|
||||
|
||||
ここでは、一般的またはよくある質問に対して、ドキュメント内の他の箇所への参照をいくつか示します。
|
||||
|
||||
## データのフィルタリング - セキュリティ { #filter-data-security }
|
||||
|
||||
返すべき以上のデータを返さないようにするには、[チュートリアル - レスポンスモデル - 戻り値の型](../tutorial/response-model.md){.internal-link target=_blank} を参照してください。
|
||||
|
||||
## ドキュメントのタグ - OpenAPI { #documentation-tags-openapi }
|
||||
|
||||
*path operations* にタグを追加し、ドキュメント UI でグループ化するには、[チュートリアル - path operation の設定 - タグ](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank} を参照してください。
|
||||
|
||||
## ドキュメントの概要と説明 - OpenAPI { #documentation-summary-and-description-openapi }
|
||||
|
||||
*path operations* に概要と説明を追加し、ドキュメント UI に表示するには、[チュートリアル - path operation の設定 - 概要と説明](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank} を参照してください。
|
||||
|
||||
## ドキュメントのレスポンス説明 - OpenAPI { #documentation-response-description-openapi }
|
||||
|
||||
ドキュメント UI に表示されるレスポンスの説明を定義するには、[チュートリアル - path operation の設定 - レスポンスの説明](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank} を参照してください。
|
||||
|
||||
## *Path Operation* の非推奨化 - OpenAPI { #documentation-deprecate-a-path-operation-openapi }
|
||||
|
||||
*path operation* を非推奨にし、ドキュメント UI に表示するには、[チュートリアル - path operation の設定 - 非推奨](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank} を参照してください。
|
||||
|
||||
## 任意のデータを JSON 互換に変換 { #convert-any-data-to-json-compatible }
|
||||
|
||||
任意のデータを JSON 互換に変換するには、[チュートリアル - JSON 互換エンコーダ](../tutorial/encoder.md){.internal-link target=_blank} を参照してください。
|
||||
|
||||
## OpenAPI メタデータ - ドキュメント { #openapi-metadata-docs }
|
||||
|
||||
ライセンス、バージョン、連絡先などを含むメタデータを OpenAPI スキーマに追加するには、[チュートリアル - メタデータとドキュメントの URL](../tutorial/metadata.md){.internal-link target=_blank} を参照してください。
|
||||
|
||||
## OpenAPI のカスタム URL { #openapi-custom-url }
|
||||
|
||||
OpenAPI の URL をカスタマイズ(または削除)するには、[チュートリアル - メタデータとドキュメントの URL](../tutorial/metadata.md#openapi-url){.internal-link target=_blank} を参照してください。
|
||||
|
||||
## OpenAPI ドキュメントの URL { #openapi-docs-urls }
|
||||
|
||||
自動生成されるドキュメント UI が使用する URL を変更するには、[チュートリアル - メタデータとドキュメントの URL](../tutorial/metadata.md#docs-urls){.internal-link target=_blank} を参照してください。
|
||||
@@ -0,0 +1,60 @@
|
||||
# GraphQL { #graphql }
|
||||
|
||||
**FastAPI** は **ASGI** 標準に基づいているため、ASGI に対応した任意の **GraphQL** ライブラリを簡単に統合できます。
|
||||
|
||||
同じアプリケーション内で通常の FastAPI の *path operation* と GraphQL を組み合わせて使えます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
**GraphQL** は非常に特定のユースケースを解決します。
|
||||
|
||||
一般的な **Web API** と比べると、**長所** と **短所** があります。
|
||||
|
||||
ご自身のユースケースで得られる **利点** が **欠点** を補うかどうかを評価してください。 🤓
|
||||
|
||||
///
|
||||
|
||||
## GraphQL ライブラリ { #graphql-libraries }
|
||||
|
||||
**ASGI** をサポートする **GraphQL** ライブラリの一部を以下に示します。**FastAPI** と組み合わせて使用できます:
|
||||
|
||||
* <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry</a> 🍓
|
||||
* <a href="https://strawberry.rocks/docs/integrations/fastapi" class="external-link" target="_blank">FastAPI 向けドキュメント</a>あり
|
||||
* <a href="https://ariadnegraphql.org/" class="external-link" target="_blank">Ariadne</a>
|
||||
* <a href="https://ariadnegraphql.org/docs/fastapi-integration" class="external-link" target="_blank">FastAPI 向けドキュメント</a>あり
|
||||
* <a href="https://tartiflette.io/" class="external-link" target="_blank">Tartiflette</a>
|
||||
* ASGI 連携用の <a href="https://tartiflette.github.io/tartiflette-asgi/" class="external-link" target="_blank">Tartiflette ASGI</a> あり
|
||||
* <a href="https://graphene-python.org/" class="external-link" target="_blank">Graphene</a>
|
||||
* <a href="https://github.com/ciscorn/starlette-graphene3" class="external-link" target="_blank">starlette-graphene3</a> あり
|
||||
|
||||
## Strawberry で GraphQL { #graphql-with-strawberry }
|
||||
|
||||
**GraphQL** が必要、または利用したい場合は、<a href="https://strawberry.rocks/" class="external-link" target="_blank">**Strawberry**</a> を**推奨**します。**FastAPI** の設計に最も近く、すべてが**型アノテーション**に基づいています。
|
||||
|
||||
ユースケースによっては他のライブラリを選ぶ方がよい場合もありますが、私に尋ねられれば、おそらく **Strawberry** を試すことを勧めるでしょう。
|
||||
|
||||
FastAPI と Strawberry を統合する方法の簡単なプレビューです:
|
||||
|
||||
{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}
|
||||
|
||||
詳細は <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry のドキュメント</a>をご覧ください。
|
||||
|
||||
また、<a href="https://strawberry.rocks/docs/integrations/fastapi" class="external-link" target="_blank">Strawberry と FastAPI</a> の連携に関するドキュメントもあります。
|
||||
|
||||
## Starlette の旧 `GraphQLApp` { #older-graphqlapp-from-starlette }
|
||||
|
||||
以前の Starlette には、<a href="https://graphene-python.org/" class="external-link" target="_blank">Graphene</a> と統合するための `GraphQLApp` クラスが含まれていました。
|
||||
|
||||
これは Starlette からは非推奨になりましたが、もしそれを使用しているコードがある場合は、同じユースケースをカバーし、**ほぼ同一のインターフェース**を持つ <a href="https://github.com/ciscorn/starlette-graphene3" class="external-link" target="_blank">starlette-graphene3</a> へ容易に**移行**できます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
GraphQL が必要であれば、依然として <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry</a> の利用を推奨します。独自のクラスや型ではなく、型アノテーションに基づいているためです。
|
||||
|
||||
///
|
||||
|
||||
## さらに学ぶ { #learn-more }
|
||||
|
||||
**GraphQL** については、<a href="https://graphql.org/" class="external-link" target="_blank">公式 GraphQL ドキュメント</a>でさらに学べます。
|
||||
|
||||
上記の各ライブラリについては、リンク先のドキュメントをご参照ください。
|
||||
@@ -0,0 +1,13 @@
|
||||
# ハウツー - レシピ { #how-to-recipes }
|
||||
|
||||
ここでは、**複数のトピック**に関するさまざまなレシピや「ハウツー」ガイドを紹介します。
|
||||
|
||||
これらのアイデアの多くはおおむね**独立**しており、ほとんどの場合、**あなたのプロジェクト**に直接当てはまるものだけを読めば十分です。
|
||||
|
||||
プロジェクトにとって興味深く有用だと思うものがあれば、ぜひ確認してください。そうでなければ、読み飛ばしても問題ありません。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
**FastAPI を学ぶ**ことを体系的に進めたい場合(推奨)、代わりに [チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank} を章ごとに読んでください。
|
||||
|
||||
///
|
||||
@@ -0,0 +1,135 @@
|
||||
# Pydantic v1 から Pydantic v2 への移行 { #migrate-from-pydantic-v1-to-pydantic-v2 }
|
||||
|
||||
古い FastAPI アプリがある場合、Pydantic v1 を使っているかもしれません。
|
||||
|
||||
FastAPI 0.100.0 は Pydantic v1 / v2 のどちらにも対応しており、インストールされている方を使用しました。
|
||||
|
||||
FastAPI 0.119.0 では、Pydantic v2 内からの Pydantic v1 の部分的サポート(`pydantic.v1`)が導入され、v2 への移行が容易になりました。
|
||||
|
||||
FastAPI 0.126.0 で Pydantic v1 のサポートは終了しましたが、しばらくの間は `pydantic.v1` は利用可能でした。
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
Pydantic チームは Python の最新バージョン、つまり **Python 3.14** から、Pydantic v1 のサポートを終了しました。
|
||||
|
||||
これには `pydantic.v1` も含まれ、Python 3.14 以上ではサポートされません。
|
||||
|
||||
Python の最新機能を使いたい場合は、Pydantic v2 を使用していることを確認する必要があります。
|
||||
|
||||
///
|
||||
|
||||
古い FastAPI アプリで Pydantic v1 を使っている場合、ここでは Pydantic v2 への移行方法と、段階的移行を助ける **FastAPI 0.119.0 の機能** を紹介します。
|
||||
|
||||
## 公式ガイド { #official-guide }
|
||||
|
||||
Pydantic には v1 から v2 への公式の <a href="https://docs.pydantic.dev/latest/migration/" class="external-link" target="_blank">移行ガイド</a> があります。
|
||||
|
||||
変更点、検証がより正確で厳密になった点、注意事項などが含まれます。
|
||||
|
||||
何が変わったかをよりよく理解するために参照してください。
|
||||
|
||||
## テスト { #tests }
|
||||
|
||||
アプリに対する[テスト](../tutorial/testing.md){.internal-link target=_blank}を用意し、継続的インテグレーション(CI)で実行するようにしてください。
|
||||
|
||||
これにより、アップグレード後も期待どおり動作していることを確認できます。
|
||||
|
||||
## `bump-pydantic` { #bump-pydantic }
|
||||
|
||||
多くの場合、カスタマイズのない通常の Pydantic モデルを使っていれば、v1 から v2 への移行作業の大半を自動化できます。
|
||||
|
||||
同じ Pydantic チームが提供する <a href="https://github.com/pydantic/bump-pydantic" class="external-link" target="_blank">`bump-pydantic`</a> を使用できます。
|
||||
|
||||
このツールは必要なコード変更のほとんどを自動で行います。
|
||||
|
||||
その後テストを実行し、問題なければ完了です。😎
|
||||
|
||||
## v2 における Pydantic v1 { #pydantic-v1-in-v2 }
|
||||
|
||||
Pydantic v2 には、Pydantic v1 がサブモジュール `pydantic.v1` として同梱されています。ただし、これは Python 3.13 を超えるバージョンではサポートされません。
|
||||
|
||||
つまり、Pydantic v2 の最新バージョンをインストールし、このサブモジュールから旧 Pydantic v1 のコンポーネントをインポートして、あたかも v1 をインストールしているかのように使用できます。
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}
|
||||
|
||||
### v2 内の Pydantic v1 に対する FastAPI のサポート { #fastapi-support-for-pydantic-v1-in-v2 }
|
||||
|
||||
FastAPI 0.119.0 以降では、移行を容易にするため、Pydantic v2 内の Pydantic v1 に対する部分的サポートもあります。
|
||||
|
||||
そのため、Pydantic を v2 の最新に上げ、インポートを `pydantic.v1` サブモジュールに切り替えるだけで、多くの場合そのまま動作します。
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
前述のとおり、Python の最近のバージョン(Python 3.14 以降)では Pydantic v1 がサポートされないため、`pydantic.v1` の使用も Python 3.14 以上ではサポートされません。
|
||||
|
||||
///
|
||||
|
||||
### 同一アプリでの Pydantic v1 と v2 { #pydantic-v1-and-v2-on-the-same-app }
|
||||
|
||||
Pydantic v2 のモデルのフィールドに Pydantic v1 のモデルを(またはその逆を)埋め込むことは、Pydantic では「サポートされていません」。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "❌ Not Supported"
|
||||
direction TB
|
||||
subgraph V2["Pydantic v2 Model"]
|
||||
V1Field["Pydantic v1 Model"]
|
||||
end
|
||||
subgraph V1["Pydantic v1 Model"]
|
||||
V2Field["Pydantic v2 Model"]
|
||||
end
|
||||
end
|
||||
|
||||
style V2 fill:#f9fff3
|
||||
style V1 fill:#fff6f0
|
||||
style V1Field fill:#fff6f0
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
...but, you can have separated models using Pydantic v1 and v2 in the same app.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "✅ Supported"
|
||||
direction TB
|
||||
subgraph V2["Pydantic v2 Model"]
|
||||
V2Field["Pydantic v2 Model"]
|
||||
end
|
||||
subgraph V1["Pydantic v1 Model"]
|
||||
V1Field["Pydantic v1 Model"]
|
||||
end
|
||||
end
|
||||
|
||||
style V2 fill:#f9fff3
|
||||
style V1 fill:#fff6f0
|
||||
style V1Field fill:#fff6f0
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
場合によっては、同じ FastAPI の path operation 内で、Pydantic v1 と v2 の両方のモデルを扱うことも可能です:
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
|
||||
|
||||
上の例では、入力モデルは Pydantic v1、出力モデル(`response_model=ItemV2` で定義)は Pydantic v2 です。
|
||||
|
||||
### Pydantic v1 のパラメータ { #pydantic-v1-parameters }
|
||||
|
||||
Pydantic v1 のモデルで `Body`、`Query`、`Form` などの FastAPI 固有のパラメータユーティリティを使う必要がある場合、v2 への移行が完了するまでの間は `fastapi.temp_pydantic_v1_params` からインポートできます:
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}
|
||||
|
||||
### 段階的に移行 { #migrate-in-steps }
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
まずは `bump-pydantic` を試してください。テストが通り、問題なければコマンド一発で完了です。✨
|
||||
|
||||
///
|
||||
|
||||
`bump-pydantic` が適用できない場合は、同一アプリで v1 と v2 のモデルを併用できるサポートを利用して、徐々に v2 へ移行できます。
|
||||
|
||||
まず Pydantic を v2 の最新にアップグレードし、すべてのモデルのインポートを `pydantic.v1` に切り替えます。
|
||||
|
||||
その後、モデルをグループごとに少しずつ Pydantic v1 から v2 へ移行していきます。🚶
|
||||
@@ -0,0 +1,102 @@
|
||||
# 入力と出力でOpenAPIのスキーマを分けるかどうか { #separate-openapi-schemas-for-input-and-output-or-not }
|
||||
|
||||
**Pydantic v2** のリリース以降、生成される OpenAPI は以前より少し正確で、より正しいものになりました。😎
|
||||
|
||||
実際には、場合によっては同じ Pydantic モデルに対して、入力用と出力用で OpenAPI に **2 つの JSON Schema** が含まれることがあります。これは **デフォルト値** の有無に依存します。
|
||||
|
||||
その動作と、必要に応じての変更方法を見ていきます。
|
||||
|
||||
## 入出力のPydanticモデル { #pydantic-models-for-input-and-output }
|
||||
|
||||
次のようにデフォルト値を持つ Pydantic モデルがあるとします。
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}
|
||||
|
||||
### 入力用モデル { #model-for-input }
|
||||
|
||||
このモデルを次のように入力として使うと:
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
|
||||
|
||||
...`description` フィールドは **必須ではありません**。デフォルト値が `None` だからです。
|
||||
|
||||
### ドキュメントでの入力モデル { #input-model-in-docs }
|
||||
|
||||
ドキュメントで確認すると、`description` フィールドには **赤いアスタリスク** が付いておらず、必須としてはマークされていません:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image01.png">
|
||||
</div>
|
||||
|
||||
### 出力用モデル { #model-for-output }
|
||||
|
||||
しかし同じモデルを次のように出力として使う場合:
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
|
||||
|
||||
...`description` にデフォルト値があるため、そのフィールドに何も返さなくても、その **デフォルト値** が入ります。
|
||||
|
||||
### 出力のレスポンスデータ { #model-for-output-response-data }
|
||||
|
||||
ドキュメントから試してレスポンスを確認すると、コードでは一方の `description` フィールドに何も追加していないにもかかわらず、JSON レスポンスにはデフォルト値(`null`)が含まれています:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image02.png">
|
||||
</div>
|
||||
|
||||
つまりそのフィールドには **常に値があります**。値が `None`(JSON では `null`)になることがあるだけです。
|
||||
|
||||
したがって、この API を使うクライアントは値の有無を確認する必要がなく、フィールドが **常に存在する** と仮定できます。場合によってはデフォルト値の `None` になるだけです。
|
||||
|
||||
これを OpenAPI で表現するには、そのフィールドを **必須** としてマークします。常に存在するためです。
|
||||
|
||||
このため、モデルの JSON Schema は、**入力か出力か** によって異なる場合があります:
|
||||
|
||||
- **入力** では `description` は **必須ではない**
|
||||
- **出力** では **必須**(値は `None`、JSON では `null` の可能性あり)
|
||||
|
||||
### ドキュメントでの出力モデル { #model-for-output-in-docs }
|
||||
|
||||
ドキュメントで出力モデルを見ると、`name` と `description` の **両方** が **赤いアスタリスク** で **必須** としてマークされています:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image03.png">
|
||||
</div>
|
||||
|
||||
### ドキュメントでの入力・出力モデル { #model-for-input-and-output-in-docs }
|
||||
|
||||
さらに、OpenAPI に含まれる利用可能なスキーマ(JSON Schema)を確認すると、`Item-Input` と `Item-Output` の 2 つがあることが分かります。
|
||||
|
||||
`Item-Input` では、`description` は **必須ではありません**(赤いアスタリスクなし)。
|
||||
|
||||
一方、`Item-Output` では、`description` は **必須**(赤いアスタリスクあり)です。
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image04.png">
|
||||
</div>
|
||||
|
||||
この **Pydantic v2** の機能により、API ドキュメントはより **正確** になり、自動生成されたクライアントや SDK もより正確になります。これにより、より良い **開発者エクスペリエンス** と一貫性が得られます。🎉
|
||||
|
||||
## スキーマを分けない { #do-not-separate-schemas }
|
||||
|
||||
一方で、**入力と出力で同じスキーマ** にしたい場合もあります。
|
||||
|
||||
主なユースケースは、すでに自動生成されたクライアントコードや SDK があり、まだそれらをすべて更新したくない場合です。いずれは更新したいとしても、今ではないかもしれません。
|
||||
|
||||
その場合は、**FastAPI** のパラメータ `separate_input_output_schemas=False` でこの機能を無効化できます。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`separate_input_output_schemas` のサポートは FastAPI `0.102.0` で追加されました。🤓
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}
|
||||
|
||||
### ドキュメントで入力・出力に同一スキーマを使用 { #same-schema-for-input-and-output-models-in-docs }
|
||||
|
||||
これでモデルの入力と出力は単一のスキーマ、`Item` のみになり、`description` は **必須ではありません**:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
# データベースのテスト { #testing-a-database }
|
||||
|
||||
データベース、SQL、SQLModel については、<a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel ドキュメント</a>で学べます。🤓
|
||||
|
||||
FastAPI と一緒に SQLModel を使うためのミニ <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">チュートリアル</a>があります。✨
|
||||
|
||||
そのチュートリアルには、<a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/" class="external-link" target="_blank">SQL データベースのテスト</a>に関するセクションも含まれています。😎
|
||||
+275
-178
@@ -1,14 +1,14 @@
|
||||
# FastAPI
|
||||
# FastAPI { #fastapi }
|
||||
|
||||
<style>
|
||||
.md-content .md-typeset h1 { display: none; }
|
||||
</style>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
<a href="https://fastapi.tiangolo.com/ja"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
|
||||
<em>FastAPI フレームワーク、高パフォーマンス、学びやすい、素早くコーディングできる、本番運用に対応</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
|
||||
@@ -27,129 +27,138 @@
|
||||
|
||||
---
|
||||
|
||||
**ドキュメント**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
**ドキュメント**: <a href="https://fastapi.tiangolo.com/ja" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
|
||||
**ソースコード**: <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
|
||||
|
||||
---
|
||||
|
||||
FastAPI は、Pythonの標準である型ヒントに基づいてPython 以降でAPI を構築するための、モダンで、高速(高パフォーマンス)な、Web フレームワークです。
|
||||
FastAPI は、Python の標準である型ヒントに基づいて Python で API を構築するための、モダンで、高速(高パフォーマンス)な Web フレームワークです。
|
||||
|
||||
主な特徴:
|
||||
|
||||
- **高速**: **NodeJS** や **Go** 並みのとても高いパフォーマンス (Starlette と Pydantic のおかげです)。 [最も高速な Python フレームワークの一つです](#_10).
|
||||
* **高速**: **NodeJS** や **Go** 並みのとても高いパフォーマンス(Starlette と Pydantic のおかげです)。 [利用可能な最も高速な Python フレームワークの一つです](#performance)。
|
||||
* **高速なコーディング**: 開発速度を約 200%〜300% 向上させます。*
|
||||
* **少ないバグ**: 開発者起因のヒューマンエラーを約 40% 削減します。*
|
||||
* **直感的**: 素晴らしいエディタサポート。<dfn title="別名: auto-complete、autocompletion、IntelliSense">補完</dfn> があらゆる場所で使えます。デバッグ時間を削減します。
|
||||
* **簡単**: 簡単に利用・習得できるようにデザインされています。ドキュメントを読む時間を削減します。
|
||||
* **短い**: コードの重複を最小限にします。各パラメータ宣言から複数の機能を得られます。バグも減ります。
|
||||
* **堅牢性**: 自動対話型ドキュメントにより、本番環境向けのコードが得られます。
|
||||
* **Standards-based**: API のオープンスタンダードに基づいており(そして完全に互換性があります)、<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>(以前は Swagger として知られていました)や <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a> をサポートします。
|
||||
|
||||
- **高速なコーディング**: 開発速度を約 200%~300%向上させます。 \*
|
||||
- **少ないバグ**: 開発者起因のヒューマンエラーを約 40%削減します。 \*
|
||||
- **直感的**: 素晴らしいエディタのサポートや <abbr title="also known as auto-complete, autocompletion, IntelliSense">オートコンプリート。</abbr> デバッグ時間を削減します。
|
||||
- **簡単**: 簡単に利用、習得できるようにデザインされています。ドキュメントを読む時間を削減します。
|
||||
- **短い**: コードの重複を最小限にしています。各パラメータからの複数の機能。少ないバグ。
|
||||
- **堅牢性**: 自動対話ドキュメントを使用して、本番環境で使用できるコードを取得します。
|
||||
- **Standards-based**: API のオープンスタンダードに基づいており、完全に互換性があります: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (以前は Swagger として知られていました) や <a href="https://json-schema.org/" class="external-link" target="_blank">JSON スキーマ</a>.
|
||||
<small>* 本番アプリケーションを構築している社内開発チームのテストに基づく見積もりです。</small>
|
||||
|
||||
<small>\* 本番アプリケーションを構築している開発チームのテストによる見積もり。</small>
|
||||
|
||||
## Sponsors
|
||||
## Sponsors { #sponsors }
|
||||
|
||||
<!-- sponsors -->
|
||||
|
||||
{% if sponsors %}
|
||||
### Keystone Sponsor { #keystone-sponsor }
|
||||
|
||||
{% for sponsor in sponsors.keystone -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor -%}
|
||||
|
||||
### Gold and Silver Sponsors { #gold-and-silver-sponsors }
|
||||
|
||||
{% for sponsor in sponsors.gold -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor -%}
|
||||
{%- for sponsor in sponsors.silver -%}
|
||||
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Other sponsors</a>
|
||||
<a href="https://fastapi.tiangolo.com/ja/fastapi-people/#sponsors" class="external-link" target="_blank">その他のスポンサー</a>
|
||||
|
||||
## 評価
|
||||
## 評価 { #opinions }
|
||||
|
||||
"_[...] 最近 **FastAPI** を使っています。 [...] 実際に私のチームの全ての **Microsoft の機械学習サービス** で使用する予定です。 そのうちのいくつかのコアな**Windows**製品と**Office**製品に統合されつつあります。_"
|
||||
"_[...] 最近 **FastAPI** を使っています。 [...] 実際に私のチームの全ての **Microsoft の機械学習サービス** で使用する予定です。 そのうちのいくつかのコアな **Windows** 製品と **Office** 製品に統合されつつあります。_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_FastAPIライブラリを採用し、クエリで**予測値**を取得できる**REST**サーバを構築しました。 [for Ludwig]_"
|
||||
"_FastAPIライブラリを採用し、クエリで **予測値** を取得できる **REST** サーバを構築しました。 [for Ludwig]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_**Netflix** は、**危機管理**オーケストレーションフレームワーク、**Dispatch**のオープンソースリリースを発表できることをうれしく思います。 [built with **FastAPI**]_"
|
||||
"_**Netflix** は、**危機管理**オーケストレーションフレームワーク、**Dispatch** のオープンソースリリースを発表できることをうれしく思います。 [built with **FastAPI**]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_私は**FastAPI**にワクワクしています。 めちゃくちゃ楽しいです!_"
|
||||
"_私は **FastAPI** にワクワクしています。 めちゃくちゃ楽しいです!_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_正直、超堅実で洗練されているように見えます。いろんな意味で、それは私がハグしたかったものです。_"
|
||||
"_正直、あなたが作ったものは超堅実で洗練されているように見えます。いろんな意味で、それは私が **Hug** にそうなってほしかったものです。誰かがそれを作るのを見るのは本当に刺激的です。_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"_REST API を構築するための**モダンなフレームワーク**を学びたい方は、**FastAPI** [...] をチェックしてみてください。 [...] 高速で, 使用、習得が簡単です。[...]_"
|
||||
"_REST API を構築するための **モダンなフレームワーク** を学びたい方は、**FastAPI** [...] をチェックしてみてください。 [...] 高速で、使用・習得が簡単です [...]_"
|
||||
|
||||
"_私たちの**API**は**FastAPI**に切り替えました。[...] きっと気に入ると思います。 [...]_"
|
||||
"_私たちの **API** は **FastAPI** に切り替えました [...] きっと気に入ると思います [...]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
## **Typer**, the FastAPI of CLIs
|
||||
"_本番運用の Python API を構築したい方には、**FastAPI** を強くおすすめします。**美しく設計**されており、**使いやすく**、**高いスケーラビリティ**があります。私たちの API ファースト開発戦略の **主要コンポーネント** となり、Virtual TAC Engineer などの多くの自動化やサービスを推進しています。_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
## FastAPI ミニドキュメンタリー { #fastapi-mini-documentary }
|
||||
|
||||
2025 年末に公開された <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">FastAPI ミニドキュメンタリー</a>があります。オンラインで視聴できます:
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
|
||||
|
||||
## **Typer**、CLI 版 FastAPI { #typer-the-fastapi-of-clis }
|
||||
|
||||
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
|
||||
|
||||
もし Web API の代わりにターミナルで使用する<abbr title="Command Line Interface">CLI</abbr>アプリを構築する場合は、<a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>を確認してください。
|
||||
Web API の代わりにターミナルで使用する <abbr title="Command Line Interface - コマンドラインインターフェイス">CLI</abbr> アプリを構築する場合は、<a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a> を確認してください。
|
||||
|
||||
**Typer**は FastAPI の弟分です。そして、**CLI 版 の FastAPI**を意味しています。
|
||||
**Typer** は FastAPI の弟分です。そして、**CLI 版 FastAPI** を意図しています。 ⌨️ 🚀
|
||||
|
||||
## 必要条件
|
||||
## 必要条件 { #requirements }
|
||||
|
||||
FastAPI は巨人の肩の上に立っています。
|
||||
|
||||
- Web の部分は<a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>
|
||||
- データの部分は<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>
|
||||
* Web の部分は <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a>
|
||||
* データの部分は <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>
|
||||
|
||||
## インストール
|
||||
## インストール { #installation }
|
||||
|
||||
<a href="https://fastapi.tiangolo.com/ja/virtual-environments/" class="external-link" target="_blank">virtual environment</a> を作成して有効化し、それから FastAPI をインストールします。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install fastapi
|
||||
$ pip install "fastapi[standard]"
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
本番環境では、<a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> または、 <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>のような、 ASGI サーバーが必要になります。
|
||||
**注**: すべてのターミナルで動作するように、`"fastapi[standard]"` は必ずクォートで囲んでください。
|
||||
|
||||
<div class="termy">
|
||||
## アプリケーション例 { #example }
|
||||
|
||||
```console
|
||||
$ pip install "uvicorn[standard]"
|
||||
### 作成 { #create-it }
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## アプリケーション例
|
||||
|
||||
### アプリケーションの作成
|
||||
|
||||
- `main.py` を作成し、以下のコードを入力します:
|
||||
`main.py` ファイルを作成し、以下のコードを入力します。
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
@@ -163,16 +172,16 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
<details markdown="1">
|
||||
<summary>または<code>async def</code>を使います...</summary>
|
||||
<summary>または <code>async def</code> を使います...</summary>
|
||||
|
||||
`async` / `await`を使用するときは、 `async def`を使います:
|
||||
コードで `async` / `await` を使用する場合は、`async def` を使います。
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -184,28 +193,41 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
**注**:
|
||||
|
||||
わからない場合は、<a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">ドキュメントの`async` と `await`にある</a>"In a hurry?"セクションをチェックしてください。
|
||||
わからない場合は、<a href="https://fastapi.tiangolo.com/ja/async/#in-a-hurry" target="_blank">ドキュメントの `async` と `await` の _"In a hurry?"_ セクション</a>を確認してください。
|
||||
|
||||
</details>
|
||||
|
||||
### 実行
|
||||
### 実行 { #run-it }
|
||||
|
||||
以下のコマンドでサーバーを起動します:
|
||||
以下のコマンドでサーバーを起動します。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
$ fastapi dev main.py
|
||||
|
||||
╭────────── FastAPI CLI - Development mode ───────────╮
|
||||
│ │
|
||||
│ Serving at: http://127.0.0.1:8000 │
|
||||
│ │
|
||||
│ API docs: http://127.0.0.1:8000/docs │
|
||||
│ │
|
||||
│ Running in development mode, for production use: │
|
||||
│ │
|
||||
│ fastapi run │
|
||||
│ │
|
||||
╰─────────────────────────────────────────────────────╯
|
||||
|
||||
INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
INFO: Started reloader process [28720]
|
||||
INFO: Started server process [28722]
|
||||
INFO: Started reloader process [2248755] using WatchFiles
|
||||
INFO: Started server process [2248757]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
```
|
||||
@@ -213,56 +235,56 @@ INFO: Application startup complete.
|
||||
</div>
|
||||
|
||||
<details markdown="1">
|
||||
<summary><code>uvicorn main:app --reload</code>コマンドについて</summary>
|
||||
<summary><code>fastapi dev main.py</code> コマンドについて</summary>
|
||||
|
||||
`uvicorn main:app`コマンドは以下の項目を参照します:
|
||||
`fastapi dev` コマンドは `main.py` ファイルを読み取り、その中の **FastAPI** アプリを検出し、<a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> を使用してサーバーを起動します。
|
||||
|
||||
- `main`: `main.py`ファイル (Python "モジュール")
|
||||
- `app`: `main.py` の`app = FastAPI()`の行で生成されたオブジェクト
|
||||
- `--reload`: コードを変更したらサーバーを再起動します。このオプションは開発環境でのみ使用します
|
||||
デフォルトでは、`fastapi dev` はローカル開発向けに自動リロードを有効にして起動します。
|
||||
|
||||
詳しくは <a href="https://fastapi.tiangolo.com/ja/fastapi-cli/" target="_blank">FastAPI CLI docs</a> を参照してください。
|
||||
|
||||
</details>
|
||||
|
||||
### 動作確認
|
||||
### 動作確認 { #check-it }
|
||||
|
||||
ブラウザから<a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>を開きます。
|
||||
ブラウザで <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a> を開きます。
|
||||
|
||||
以下の JSON のレスポンスが確認できます:
|
||||
以下の JSON のレスポンスが確認できます。
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
もうすでに以下の API が作成されています:
|
||||
すでに以下の API が作成されています。
|
||||
|
||||
- `/` と `/items/{item_id}`のパスで HTTP リクエストを受けます。
|
||||
- どちらのパスも `GET` <em>操作</em> を取ります。(HTTP メソッドとしても知られています。)
|
||||
- `/items/{item_id}` パスのパスパラメータ `item_id` は `int` でなければなりません。
|
||||
- パス `/items/{item_id}` はオプションの `str` クエリパラメータ `q` を持ちます。
|
||||
* _パス_ `/` と `/items/{item_id}` で HTTP リクエストを受け取ります。
|
||||
* 両方の _パス_ は `GET` <em>操作</em>(HTTP _メソッド_ としても知られています)を取ります。
|
||||
* _パス_ `/items/{item_id}` は `int` であるべき _パスパラメータ_ `item_id` を持ちます。
|
||||
* _パス_ `/items/{item_id}` はオプションの `str` _クエリパラメータ_ `q` を持ちます。
|
||||
|
||||
### 自動対話型の API ドキュメント
|
||||
### 自動対話型 API ドキュメント { #interactive-api-docs }
|
||||
|
||||
<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>にアクセスしてみてください。
|
||||
次に、<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> にアクセスします。
|
||||
|
||||
自動対話型の API ドキュメントが表示されます。 (<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>が提供しています。):
|
||||
自動対話型 API ドキュメントが表示されます(<a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> が提供しています)。
|
||||
|
||||

|
||||
|
||||
### 代替の API ドキュメント
|
||||
### 代替 API ドキュメント { #alternative-api-docs }
|
||||
|
||||
<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>にアクセスしてみてください。
|
||||
次に、<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> にアクセスします。
|
||||
|
||||
代替の自動ドキュメントが表示されます。(<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>が提供しています。):
|
||||
代替の自動ドキュメントが表示されます(<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> が提供しています)。
|
||||
|
||||

|
||||
|
||||
## アップグレード例
|
||||
## アップグレード例 { #example-upgrade }
|
||||
|
||||
`PUT`リクエストからボディを受け取るために`main.py`を修正しましょう。
|
||||
次に、`PUT` リクエストからボディを受け取るために `main.py` ファイルを修正しましょう。
|
||||
|
||||
Pydantic によって、Python の標準的な型を使ってボディを宣言します。
|
||||
Pydantic によって、標準的な Python の型を使ってボディを宣言します。
|
||||
|
||||
```Python hl_lines="2 7 8 9 10 23 24 25"
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -272,7 +294,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool = None
|
||||
is_offer: bool | None = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -281,7 +303,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
@@ -290,173 +312,248 @@ def update_item(item_id: int, item: Item):
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
サーバーは自動でリロードされます。(上述の`uvicorn`コマンドで`--reload`オプションを追加しているからです。)
|
||||
`fastapi dev` サーバーは自動でリロードされるはずです。
|
||||
|
||||
### 自動対話型の API ドキュメントのアップグレード
|
||||
### 自動対話型 API ドキュメントのアップグレード { #interactive-api-docs-upgrade }
|
||||
|
||||
<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>にアクセスしましょう。
|
||||
次に、<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> にアクセスします。
|
||||
|
||||
- 自動対話型の API ドキュメントが新しいボディも含めて自動でアップデートされます:
|
||||
* 自動対話型 API ドキュメントは新しいボディも含めて自動でアップデートされます。
|
||||
|
||||

|
||||
|
||||
- "Try it out"ボタンをクリックしてください。パラメータを入力して API と直接やりとりすることができます:
|
||||
* 「Try it out」ボタンをクリックします。パラメータを入力して API と直接やりとりできます。
|
||||
|
||||

|
||||
|
||||
- それから、"Execute" ボタンをクリックしてください。 ユーザーインターフェースは API と通信し、パラメータを送信し、結果を取得して画面に表示します:
|
||||
* 次に、「Execute」ボタンをクリックします。ユーザーインターフェースは API と通信し、パラメータを送信し、結果を取得して画面に表示します。
|
||||
|
||||

|
||||
|
||||
### 代替の API ドキュメントのアップグレード
|
||||
### 代替 API ドキュメントのアップグレード { #alternative-api-docs-upgrade }
|
||||
|
||||
<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>にアクセスしましょう。
|
||||
次に、<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> にアクセスします。
|
||||
|
||||
- 代替の API ドキュメントにも新しいクエリパラメータやボディが反映されます。
|
||||
* 代替のドキュメントにも新しいクエリパラメータやボディが反映されます。
|
||||
|
||||

|
||||
|
||||
### まとめ
|
||||
### まとめ { #recap }
|
||||
|
||||
要約すると、関数のパラメータとして、パラメータやボディ などの型を**一度だけ**宣言します。
|
||||
要約すると、関数のパラメータとして、パラメータやボディなどの型を **一度だけ** 宣言します。
|
||||
|
||||
標準的な最新の Python の型を使っています。
|
||||
標準的な最新の Python の型を使います。
|
||||
|
||||
新しい構文や特定のライブラリのメソッドやクラスなどを覚える必要はありません。
|
||||
|
||||
単なる標準的な**3.8 以降の Python**です。
|
||||
単なる標準的な **Python** です。
|
||||
|
||||
例えば、`int`の場合:
|
||||
例えば、`int` の場合:
|
||||
|
||||
```Python
|
||||
item_id: int
|
||||
```
|
||||
|
||||
または、より複雑な`Item`モデルの場合:
|
||||
または、より複雑な `Item` モデルの場合:
|
||||
|
||||
```Python
|
||||
item: Item
|
||||
```
|
||||
|
||||
...そして、この一度の宣言で、以下のようになります:
|
||||
...そして、この一度の宣言で、以下のようになります。
|
||||
|
||||
- 以下を含むエディタサポート:
|
||||
- 補完
|
||||
- タイプチェック
|
||||
- データの検証:
|
||||
- データが無効な場合に自動でエラーをクリアします。
|
||||
- 深い入れ子になった JSON オブジェクトでも検証が可能です。
|
||||
- 入力データの<abbr title="also known as: serialization, parsing, marshalling">変換</abbr>: ネットワークから Python のデータや型に変換してから読み取ります:
|
||||
- JSON.
|
||||
- パスパラメータ
|
||||
- クエリパラメータ
|
||||
- クッキー
|
||||
- ヘッダー
|
||||
- フォーム
|
||||
- ファイル
|
||||
- 出力データの<abbr title="also known as: serialization, parsing, marshalling">変換</abbr>: Python のデータや型からネットワークデータへ変換します (JSON として):
|
||||
- Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
- `datetime` オブジェクト
|
||||
- `UUID` オブジェクト
|
||||
- データベースモデル
|
||||
- ...などなど
|
||||
- 2 つの代替ユーザーインターフェースを含む自動インタラクティブ API ドキュメント:
|
||||
- Swagger UI.
|
||||
- ReDoc.
|
||||
* 以下を含むエディタサポート:
|
||||
* 補完。
|
||||
* 型チェック。
|
||||
* データの検証:
|
||||
* データが無効な場合に自動で明確なエラーを返します。
|
||||
* 深い入れ子になった JSON オブジェクトでも検証が可能です。
|
||||
* 入力データの <dfn title="別名: serialization、parsing、marshalling">変換</dfn>: ネットワークから Python のデータや型へ。以下から読み取ります:
|
||||
* JSON。
|
||||
* パスパラメータ。
|
||||
* クエリパラメータ。
|
||||
* Cookie。
|
||||
* ヘッダー。
|
||||
* フォーム。
|
||||
* ファイル。
|
||||
* 出力データの <dfn title="別名: serialization、parsing、marshalling">変換</dfn>: Python のデータや型からネットワークデータへ(JSON として)変換します:
|
||||
* Python の型(`str`、`int`、`float`、`bool`、`list` など)の変換。
|
||||
* `datetime` オブジェクト。
|
||||
* `UUID` オブジェクト。
|
||||
* データベースモデル。
|
||||
* ...などなど。
|
||||
* 2 つの代替ユーザーインターフェースを含む自動対話型 API ドキュメント:
|
||||
* Swagger UI。
|
||||
* ReDoc。
|
||||
|
||||
---
|
||||
|
||||
コード例に戻りましょう、**FastAPI** は次のようになります:
|
||||
前のコード例に戻ると、**FastAPI** は次のように動作します。
|
||||
|
||||
- `GET`および`PUT`リクエストのパスに`item_id` があることを検証します。
|
||||
- `item_id`が`GET`および`PUT`リクエストに対して`int` 型であることを検証します。
|
||||
- そうでない場合は、クライアントは有用で明確なエラーが表示されます。
|
||||
- `GET` リクエストに対してオプションのクエリパラメータ `q` (`http://127.0.0.1:8000/items/foo?q=somequery` のように) が存在するかどうかを調べます。
|
||||
- パラメータ `q` は `= None` で宣言されているので、オプションです。
|
||||
- `None`がなければ必須になります(`PUT`の場合のボディと同様です)。
|
||||
- `PUT` リクエストを `/items/{item_id}` に送信する場合は、ボディを JSON として読み込みます:
|
||||
- 必須の属性 `name` を確認してください。 それは `str` であるべきです。
|
||||
- 必須の属性 `price` を確認してください。それは `float` でなければならないです。
|
||||
- オプションの属性 `is_offer` を確認してください。値がある場合は、`bool` であるべきです。
|
||||
- これらはすべて、深くネストされた JSON オブジェクトに対しても動作します。
|
||||
- JSON から JSON に自動的に変換します。
|
||||
- OpenAPIですべてを文書化し、以下を使用することができます:
|
||||
- 対話的なドキュメントシステム。
|
||||
- 多くの言語に対応した自動クライアントコード生成システム。
|
||||
- 2 つの対話的なドキュメントのWebインターフェイスを直接提供します。
|
||||
* `GET` および `PUT` リクエストのパスに `item_id` があることを検証します。
|
||||
* `GET` および `PUT` リクエストに対して `item_id` が `int` 型であることを検証します。
|
||||
* そうでない場合、クライアントは有用で明確なエラーを受け取ります。
|
||||
* `GET` リクエストに対して、`q` という名前のオプションのクエリパラメータ(`http://127.0.0.1:8000/items/foo?q=somequery` のような)が存在するかどうかを調べます。
|
||||
* `q` パラメータは `= None` で宣言されているため、オプションです。
|
||||
* `None` がなければ必須になります(`PUT` の場合のボディと同様です)。
|
||||
* `PUT` リクエストを `/items/{item_id}` に送信する場合、ボディを JSON として読み込みます:
|
||||
* 必須の属性 `name` があり、`str` であるべきことを確認します。
|
||||
* 必須の属性 `price` があり、`float` でなければならないことを確認します。
|
||||
* オプションの属性 `is_offer` があり、存在する場合は `bool` であるべきことを確認します。
|
||||
* これらはすべて、深くネストされた JSON オブジェクトに対しても動作します。
|
||||
* JSON への/からの変換を自動的に行います。
|
||||
* OpenAPI ですべてを文書化し、以下で利用できます:
|
||||
* 対話型ドキュメントシステム。
|
||||
* 多くの言語に対応した自動クライアントコード生成システム。
|
||||
* 2 つの対話型ドキュメント Web インターフェースを直接提供します。
|
||||
|
||||
---
|
||||
|
||||
まだ表面的な部分に触れただけですが、もう全ての仕組みは分かっているはずです。
|
||||
まだ表面的な部分に触れただけですが、仕組みはすでにイメージできているはずです。
|
||||
|
||||
以下の行を変更してみてください:
|
||||
以下の行を変更してみてください。
|
||||
|
||||
```Python
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
...以下を:
|
||||
...以下の:
|
||||
|
||||
```Python
|
||||
... "item_name": item.name ...
|
||||
```
|
||||
|
||||
...以下のように:
|
||||
...を:
|
||||
|
||||
```Python
|
||||
... "item_price": item.price ...
|
||||
```
|
||||
|
||||
...そして、エディタが属性を自動補完し、そのタイプを知る方法を確認してください。:
|
||||
...に変更し、エディタが属性を自動補完し、その型を知ることを確認してください。
|
||||
|
||||

|
||||
|
||||
より多くの機能を含む、より完全な例については、<a href="https://fastapi.tiangolo.com/tutorial/">チュートリアル - ユーザーガイド</a>をご覧ください。
|
||||
より多くの機能を含む、より完全な例については、<a href="https://fastapi.tiangolo.com/ja/tutorial/">Tutorial - User Guide</a> を参照してください。
|
||||
|
||||
**ネタバレ注意**: チュートリアル - ユーザーガイドは以下の情報が含まれています:
|
||||
**ネタバレ注意**: tutorial - user guide には以下が含まれます。
|
||||
|
||||
- **ヘッダー**、**クッキー**、**フォームフィールド**、**ファイル**などの他の場所からの **パラメータ** 宣言。
|
||||
- `maximum_length`や`regex`のような**検証や制約**を設定する方法。
|
||||
- 非常に強力で使いやすい <abbr title="also known as components, resources, providers, services, injectables">**依存性注入**</abbr>システム。
|
||||
- **JWT トークン**を用いた **OAuth2** や **HTTP Basic 認証** のサポートを含む、セキュリティと認証。
|
||||
- **深くネストされた JSON モデル**を宣言するためのより高度な(しかし同様に簡単な)技術(Pydantic のおかげです)。
|
||||
- 以下のようなたくさんのおまけ機能(Starlette のおかげです):
|
||||
- **WebSockets**
|
||||
- **GraphQL**
|
||||
- `httpx` や `pytest`をもとにした極限に簡単なテスト
|
||||
- **CORS**
|
||||
- **クッキーセッション**
|
||||
- ...などなど。
|
||||
* **ヘッダー**、**Cookie**、**フォームフィールド**、**ファイル**など、他のさまざまな場所からの **パラメータ** 宣言。
|
||||
* `maximum_length` や `regex` のような **検証制約** を設定する方法。
|
||||
* 非常に強力で使いやすい **<dfn title="別名: components、resources、providers、services、injectables">依存性注入</dfn>** システム。
|
||||
* **JWT トークン**を用いた **OAuth2** や **HTTP Basic** 認証のサポートを含む、セキュリティと認証。
|
||||
* **深くネストされた JSON モデル**を宣言するための、より高度な(しかし同様に簡単な)手法(Pydantic のおかげです)。
|
||||
* <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> および他のライブラリによる **GraphQL** 統合。
|
||||
* 以下のようなたくさんのおまけ機能(Starlette のおかげです):
|
||||
* **WebSockets**
|
||||
* HTTPX と `pytest` に基づく極めて簡単なテスト
|
||||
* **CORS**
|
||||
* **Cookie Sessions**
|
||||
* ...などなど。
|
||||
|
||||
## パフォーマンス
|
||||
### アプリをデプロイ(任意) { #deploy-your-app-optional }
|
||||
|
||||
独立した TechEmpower のベンチマークでは、Uvicorn で動作する**FastAPI**アプリケーションが、<a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">Python フレームワークの中で最も高速なものの 1 つ</a>であり、Starlette と Uvicorn(FastAPI で内部的に使用されています)にのみ下回っていると示されています。
|
||||
必要に応じて FastAPI アプリを <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> にデプロイできます。まだの場合はウェイティングリストに参加してください。 🚀
|
||||
|
||||
詳細は<a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">ベンチマーク</a>セクションをご覧ください。
|
||||
すでに **FastAPI Cloud** アカウント(ウェイティングリストから招待されました 😉)がある場合は、1 コマンドでアプリケーションをデプロイできます。
|
||||
|
||||
## オプションの依存関係
|
||||
デプロイ前に、ログインしていることを確認してください。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
次に、アプリをデプロイします。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi deploy
|
||||
|
||||
Deploying to FastAPI Cloud...
|
||||
|
||||
✅ Deployment successful!
|
||||
|
||||
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
これで完了です!その URL でアプリにアクセスできます。 ✨
|
||||
|
||||
#### FastAPI Cloud について { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** は **FastAPI** の作者と同じチームによって作られています。
|
||||
|
||||
最小限の労力で API を **構築**、**デプロイ**、**アクセス** するためのプロセスを効率化します。
|
||||
|
||||
FastAPI でアプリを構築するのと同じ **開発者体験** を、クラウドへの **デプロイ** にももたらします。 🎉
|
||||
|
||||
FastAPI Cloud は *FastAPI and friends* オープンソースプロジェクトの主要スポンサーであり、資金提供元です。 ✨
|
||||
|
||||
#### 他のクラウドプロバイダにデプロイ { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI はオープンソースであり、標準に基づいています。選択した任意のクラウドプロバイダに FastAPI アプリをデプロイできます。
|
||||
|
||||
各クラウドプロバイダのガイドに従って、FastAPI アプリをデプロイしてください。 🤓
|
||||
|
||||
## パフォーマンス { #performance }
|
||||
|
||||
独立した TechEmpower のベンチマークでは、Uvicorn で動作する **FastAPI** アプリケーションが、<a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">利用可能な最も高速な Python フレームワークの一つ</a>であり、Starlette と Uvicorn(FastAPI で内部的に使用されています)にのみ下回っていると示されています。(*)
|
||||
|
||||
詳細は <a href="https://fastapi.tiangolo.com/ja/benchmarks/" class="internal-link" target="_blank">Benchmarks</a> セクションをご覧ください。
|
||||
|
||||
## 依存関係 { #dependencies }
|
||||
|
||||
FastAPI は Pydantic と Starlette に依存しています。
|
||||
|
||||
### `standard` 依存関係 { #standard-dependencies }
|
||||
|
||||
FastAPI を `pip install "fastapi[standard]"` でインストールすると、`standard` グループのオプション依存関係が含まれます。
|
||||
|
||||
Pydantic によって使用されるもの:
|
||||
|
||||
- <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - E メールの検証
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - メール検証のため。
|
||||
|
||||
Starlette によって使用されるもの:
|
||||
|
||||
- <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - `TestClient`を使用するために必要です。
|
||||
- <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - デフォルトのテンプレート設定を使用する場合は必要です。
|
||||
- <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>`request.form()`からの変換をサポートしたい場合は必要です。
|
||||
- <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - `SessionMiddleware` サポートのためには必要です。
|
||||
- <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Starlette の `SchemaGenerator` サポートのために必要です。 (FastAPI では必要ないでしょう。)
|
||||
- <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - `GraphQLApp` サポートのためには必要です。
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - `TestClient` を使用したい場合に必要です。
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - デフォルトのテンプレート設定を使用したい場合に必要です。
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - `request.form()` とともに、フォームの <dfn title="HTTP リクエストから届く文字列を Python データに変換すること">「parsing」</dfn> をサポートしたい場合に必要です。
|
||||
|
||||
FastAPI / Starlette に使用されるもの:
|
||||
FastAPI によって使用されるもの:
|
||||
|
||||
- <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - アプリケーションをロードしてサーブするサーバーのため。
|
||||
- <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - `ORJSONResponse`を使用したい場合は必要です。
|
||||
- <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - `UJSONResponse`を使用する場合は必須です。
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - アプリケーションをロードして提供するサーバーのため。これには `uvicorn[standard]` も含まれ、高性能なサービングに必要な依存関係(例: `uvloop`)が含まれます。
|
||||
* `fastapi-cli[standard]` - `fastapi` コマンドを提供します。
|
||||
* これには `fastapi-cloud-cli` が含まれ、FastAPI アプリケーションを <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> にデプロイできます。
|
||||
|
||||
これらは全て `pip install fastapi[all]`でインストールできます。
|
||||
### `standard` 依存関係なし { #without-standard-dependencies }
|
||||
|
||||
## ライセンス
|
||||
`standard` のオプション依存関係を含めたくない場合は、`pip install "fastapi[standard]"` の代わりに `pip install fastapi` でインストールできます。
|
||||
|
||||
このプロジェクトは MIT ライセンスです。
|
||||
### `fastapi-cloud-cli` なし { #without-fastapi-cloud-cli }
|
||||
|
||||
標準の依存関係を含めつつ `fastapi-cloud-cli` を除外して FastAPI をインストールしたい場合は、`pip install "fastapi[standard-no-fastapi-cloud-cli]"` でインストールできます。
|
||||
|
||||
### 追加のオプション依存関係 { #additional-optional-dependencies }
|
||||
|
||||
追加でインストールしたい依存関係があります。
|
||||
|
||||
追加のオプション Pydantic 依存関係:
|
||||
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - 設定管理のため。
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - Pydantic で使用する追加の型のため。
|
||||
|
||||
追加のオプション FastAPI 依存関係:
|
||||
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - `ORJSONResponse` を使用したい場合に必要です。
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - `UJSONResponse` を使用したい場合に必要です。
|
||||
|
||||
## ライセンス { #license }
|
||||
|
||||
このプロジェクトは MIT ライセンスの条項の下でライセンスされています。
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 学習
|
||||
# 学習 { #learn }
|
||||
|
||||
ここでは、**FastAPI** を学習するための入門セクションとチュートリアルを紹介します。
|
||||
|
||||
これは、FastAPIを学習するにあたっての**書籍**や**コース**であり、**公式**かつ推奨される方法とみなすことができます 😎
|
||||
これは、**書籍**や**コース**、FastAPIを学習するための**公式**かつ推奨される方法とみなすことができます。😎
|
||||
|
||||
@@ -1,84 +1,28 @@
|
||||
# プロジェクト生成 - テンプレート
|
||||
# Full Stack FastAPI テンプレート { #full-stack-fastapi-template }
|
||||
|
||||
プロジェクトジェネレーターは、初期設定、セキュリティ、データベース、初期APIエンドポイントなどの多くが含まれているため、プロジェクトの開始に利用できます。
|
||||
テンプレートは通常、特定のセットアップが含まれていますが、柔軟でカスタマイズできるように設計されています。これにより、プロジェクトの要件に合わせて変更・適応でき、優れた出発点になります。🏁
|
||||
|
||||
プロジェクトジェネレーターは常に非常に意見が分かれる設定がされており、ニーズに合わせて更新および調整する必要があります。しかしきっと、プロジェクトの良い出発点となるでしょう。
|
||||
このテンプレートを使って開始できます。初期セットアップ、セキュリティ、データベース、いくつかのAPIエンドポイントがすでに用意されています。
|
||||
|
||||
## フルスタック FastAPI PostgreSQL
|
||||
GitHubリポジトリ: <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a>
|
||||
|
||||
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
|
||||
## Full Stack FastAPI テンプレート - 技術スタックと機能 { #full-stack-fastapi-template-technology-stack-and-features }
|
||||
|
||||
### フルスタック FastAPI PostgreSQL - 機能
|
||||
|
||||
* 完全な**Docker**インテグレーション (Dockerベース)。
|
||||
* Docker Swarm モードデプロイ。
|
||||
* ローカル開発環境向けの**Docker Compose**インテグレーションと最適化。
|
||||
* UvicornとGunicornを使用した**リリース可能な** Python web サーバ。
|
||||
* Python <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**</a> バックエンド:
|
||||
* **高速**: **NodeJS** や **Go** 並みのとても高いパフォーマンス (Starlette と Pydantic のおかげ)。
|
||||
* **直感的**: 素晴らしいエディタのサポートや <abbr title="自動補完、インテリセンスとも呼ばれる">補完。</abbr> デバッグ時間の短縮。
|
||||
* **簡単**: 簡単に利用、習得できるようなデザイン。ドキュメントを読む時間を削減。
|
||||
* **短い**: コードの重複を最小限に。パラメータ宣言による複数の機能。
|
||||
* **堅牢性**: 自動対話ドキュメントを使用した、本番環境で使用できるコード。
|
||||
* **標準規格準拠**: API のオープンスタンダードに基く、完全な互換性: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>や <a href="http://json-schema.org/" class="external-link" target="_blank">JSON スキーマ</a>。
|
||||
* 自動バリデーション、シリアライゼーション、対話的なドキュメント、OAuth2 JWTトークンを用いた認証などを含む、<a href="https://fastapi.tiangolo.com/features/" class="external-link" target="_blank">**その他多くの機能**</a>。
|
||||
* **セキュアなパスワード** ハッシュ化 (デフォルトで)。
|
||||
* **JWTトークン** 認証。
|
||||
* **SQLAlchemy** モデル (Flask用の拡張と独立しているので、Celeryワーカーと直接的に併用できます)。
|
||||
* 基本的なユーザーモデル (任意の修正や削除が可能)。
|
||||
* **Alembic** マイグレーション。
|
||||
* **CORS** (Cross Origin Resource Sharing (オリジン間リソース共有))。
|
||||
* **Celery** ワーカー。バックエンドの残りの部分からモデルとコードを選択的にインポートし、使用可能。
|
||||
* Dockerと統合された**Pytest**ベースのRESTバックエンドテスト。データベースに依存せずに、全てのAPIをテスト可能。Docker上で動作するので、毎回ゼロから新たなデータストアを構築可能。(ElasticSearch、MongoDB、CouchDBなどを使用して、APIの動作をテスト可能)
|
||||
* Atom HydrogenやVisual Studio Code Jupyterなどの拡張機能を使用した、リモートまたはDocker開発用の**Jupyterカーネル**との簡単なPython統合。
|
||||
* **Vue** フロントエンド:
|
||||
* Vue CLIにより生成。
|
||||
* **JWT認証**の処理。
|
||||
* ログインビュー。
|
||||
* ログイン後の、メインダッシュボードビュー。
|
||||
* メインダッシュボードでのユーザー作成と編集。
|
||||
* セルフユーザー版
|
||||
* **Vuex**。
|
||||
* **Vue-router**。
|
||||
* 美しいマテリアルデザインコンポーネントのための**Vuetify**。
|
||||
* **TypeScript**。
|
||||
* **Nginx**ベースのDockerサーバ (Vue-routerとうまく協調する構成)。
|
||||
* Dockerマルチステージビルド。コンパイルされたコードの保存やコミットが不要。
|
||||
* ビルド時にフロントエンドテスト実行 (無効化も可能)。
|
||||
* 可能な限りモジュール化されているのでそのまま使用できますが、Vue CLIで再生成したり、必要に応じて作成したりして、必要なものを再利用可能。
|
||||
* PostgreSQLデータベースのための**PGAdmin**。(PHPMyAdminとMySQLを使用できるように簡単に変更可能)
|
||||
* Celeryジョブ監視のための**Flower**。
|
||||
* **Traefik**を使用してフロントエンドとバックエンド間をロードバランシング。同一ドメインに配置しパスで区切る、ただし、異なるコンテナで処理。
|
||||
* Traefik統合。Let's Encrypt **HTTPS**証明書の自動生成を含む。
|
||||
* GitLab **CI** (継続的インテグレーション)。フロントエンドおよびバックエンドテストを含む。
|
||||
|
||||
## フルスタック FastAPI Couchbase
|
||||
|
||||
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
|
||||
|
||||
⚠️ **警告** ⚠️
|
||||
|
||||
ゼロから新規プロジェクトを始める場合は、ここで代替案を確認してください。
|
||||
|
||||
例えば、<a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">フルスタック FastAPI PostgreSQL</a>のプロジェクトジェネレーターは、積極的にメンテナンスされ、利用されているのでより良い代替案かもしれません。また、すべての新機能と改善点が含まれています。
|
||||
|
||||
Couchbaseベースのジェネレーターは今も無償提供されています。恐らく正常に動作するでしょう。また、すでにそのジェネレーターで生成されたプロジェクトが存在する場合でも (ニーズに合わせてアップデートしているかもしれません)、同様に正常に動作するはずです。
|
||||
|
||||
詳細はレポジトリのドキュメントを参照して下さい。
|
||||
|
||||
## フルスタック FastAPI MongoDB
|
||||
|
||||
...時間の都合等によっては、今後作成されるかもしれません。😅 🎉
|
||||
|
||||
## spaCyとFastAPIを使用した機械学習モデル
|
||||
|
||||
GitHub: <a href="https://github.com/microsoft/cookiecutter-spacy-fastapi" class="external-link" target="_blank">https://github.com/microsoft/cookiecutter-spacy-fastapi</a>
|
||||
|
||||
### spaCyとFastAPIを使用した機械学習モデル - 機能
|
||||
|
||||
* **spaCy** のNERモデルの統合。
|
||||
* **Azure Cognitive Search** のリクエストフォーマットを搭載。
|
||||
* **リリース可能な** UvicornとGunicornを使用したPythonウェブサーバ。
|
||||
* **Azure DevOps** のKubernetes (AKS) CI/CD デプロイを搭載。
|
||||
* **多言語** プロジェクトのために、セットアップ時に言語を容易に選択可能 (spaCyに組み込まれている言語の中から)。
|
||||
* **簡単に拡張可能**。spaCyだけでなく、他のモデルフレームワーク (Pytorch、Tensorflow) へ。
|
||||
- ⚡ PythonバックエンドAPI向けの [**FastAPI**](https://fastapi.tiangolo.com/ja)。
|
||||
- 🧰 PythonのSQLデータベース操作(ORM)向けの [SQLModel](https://sqlmodel.tiangolo.com)。
|
||||
- 🔍 FastAPIで使用される、データバリデーションと設定管理向けの [Pydantic](https://docs.pydantic.dev)。
|
||||
- 💾 SQLデータベースとしての [PostgreSQL](https://www.postgresql.org)。
|
||||
- 🚀 フロントエンド向けの [React](https://react.dev)。
|
||||
- 💃 TypeScript、hooks、Vite、その他のモダンなフロントエンドスタックの各要素を使用。
|
||||
- 🎨 フロントエンドコンポーネント向けの [Tailwind CSS](https://tailwindcss.com) と [shadcn/ui](https://ui.shadcn.com)。
|
||||
- 🤖 自動生成されたフロントエンドクライアント。
|
||||
- 🧪 End-to-Endテスト向けの [Playwright](https://playwright.dev)。
|
||||
- 🦇 ダークモードのサポート。
|
||||
- 🐋 開発および本番向けの [Docker Compose](https://www.docker.com)。
|
||||
- 🔒 デフォルトでの安全なパスワードハッシュ化。
|
||||
- 🔑 JWT(JSON Web Token)認証。
|
||||
- 📫 メールベースのパスワードリカバリ。
|
||||
- ✅ [Pytest](https://pytest.org) によるテスト。
|
||||
- 📞 リバースプロキシ / ロードバランサとしての [Traefik](https://traefik.io)。
|
||||
- 🚢 Docker Composeを使用したデプロイ手順(自動HTTPS証明書を処理するフロントエンドTraefikプロキシのセットアップ方法を含む)。
|
||||
- 🏭 GitHub Actionsに基づくCI(continuous integration)とCD(continuous deployment)。
|
||||
|
||||
+157
-123
@@ -1,31 +1,30 @@
|
||||
# Pythonの型の紹介
|
||||
# Pythonの型の紹介 { #python-types-intro }
|
||||
|
||||
**Python 3.6以降** では「型ヒント」オプションがサポートされています。
|
||||
Python にはオプションの「型ヒント」(「型アノテーション」とも呼ばれます)がサポートされています。
|
||||
|
||||
これらの **"型ヒント"** は変数の<abbr title="例: str, int, float, bool">型</abbr>を宣言することができる新しい構文です。(Python 3.6以降)
|
||||
これらの **「型ヒント」** やアノテーションは、変数の<dfn title="例えば: str、int、float、bool">型</dfn>を宣言できる特別な構文です。
|
||||
|
||||
変数に型を宣言することでエディターやツールがより良いサポートを提供することができます。
|
||||
変数に型を宣言することで、エディターやツールがより良いサポートを提供できます。
|
||||
|
||||
ここではPythonの型ヒントについての **クイックチュートリアル/リフレッシュ** で、**FastAPI**でそれらを使用するために必要な最低限のことだけをカバーしています。...実際には本当に少ないです。
|
||||
これは Python の型ヒントについての **クイックチュートリアル/リフレッシュ** にすぎません。**FastAPI** で使うために必要な最低限のことだけをカバーしています。...実際には本当に少ないです。
|
||||
|
||||
**FastAPI** はすべてこれらの型ヒントに基づいており、多くの強みと利点を与えてくれます。
|
||||
|
||||
しかしたとえまったく **FastAPI** を使用しない場合でも、それらについて少し学ぶことで利点を得ることができるでしょう。
|
||||
しかし、たとえ **FastAPI** をまったく使用しない場合でも、それらについて少し学ぶことで利点を得られます。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
もしあなたがPythonの専門家で、すでに型ヒントについてすべて知っているのであれば、次の章まで読み飛ばしてください。
|
||||
もしあなたが Python の専門家で、すでに型ヒントについてすべて知っているのであれば、次の章まで読み飛ばしてください。
|
||||
|
||||
///
|
||||
|
||||
## 動機
|
||||
## 動機 { #motivation }
|
||||
|
||||
簡単な例から始めてみましょう:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001.py *}
|
||||
{* ../../docs_src/python_types/tutorial001_py310.py *}
|
||||
|
||||
|
||||
このプログラムを実行すると以下が出力されます:
|
||||
このプログラムを呼び出すと、以下が出力されます:
|
||||
|
||||
```
|
||||
John Doe
|
||||
@@ -33,14 +32,13 @@ John Doe
|
||||
|
||||
この関数は以下のようなことを行います:
|
||||
|
||||
* `first_name`と`last_name`を取得します。
|
||||
* `title()`を用いて、それぞれの最初の文字を大文字に変換します。
|
||||
* 真ん中にスペースを入れて<abbr title="次から次へと中身を入れて一つにまとめる">連結</abbr>します。
|
||||
* `first_name` と `last_name` を取得します。
|
||||
* `title()` を用いて、それぞれの最初の文字を大文字に変換します。
|
||||
* 真ん中にスペースを入れて<dfn title="1つにまとめます。片方の内容をもう片方の後ろに続けます。">連結</dfn>します。
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001.py hl[2] *}
|
||||
{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
|
||||
|
||||
|
||||
### 編集
|
||||
### 編集 { #edit-it }
|
||||
|
||||
これはとても簡単なプログラムです。
|
||||
|
||||
@@ -50,21 +48,21 @@ John Doe
|
||||
|
||||
しかし、そうすると「最初の文字を大文字に変換するあのメソッド」を呼び出す必要があります。
|
||||
|
||||
それは`upper`でしたか?`uppercase`でしたか?それとも`first_uppercase`?または`capitalize`?
|
||||
それは `upper` でしたか?`uppercase` でしたか?`first_uppercase`?`capitalize`?
|
||||
|
||||
そして、古くからプログラマーの友人であるエディタで自動補完を試してみます。
|
||||
|
||||
関数の最初のパラメータ`first_name`を入力し、ドット(`.`)を入力してから、`Ctrl+Space`を押すと補完が実行されます。
|
||||
関数の最初のパラメータ `first_name` を入力し、ドット(`.`)を入力してから、`Ctrl+Space` を押すと補完が実行されます。
|
||||
|
||||
しかし、悲しいことに、これはなんの役にも立ちません:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image01.png">
|
||||
<img src="/img/python-types/image01.png">
|
||||
|
||||
### 型の追加
|
||||
### 型の追加 { #add-types }
|
||||
|
||||
先ほどのコードから一行変更してみましょう。
|
||||
|
||||
以下の関数のパラメータ部分を:
|
||||
関数のパラメータである次の断片を、以下から:
|
||||
|
||||
```Python
|
||||
first_name, last_name
|
||||
@@ -80,8 +78,7 @@ John Doe
|
||||
|
||||
それが「型ヒント」です:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial002.py hl[1] *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
|
||||
|
||||
これは、以下のようにデフォルト値を宣言するのと同じではありません:
|
||||
|
||||
@@ -95,41 +92,39 @@ John Doe
|
||||
|
||||
そして、通常、型ヒントを追加しても、それらがない状態と起こることは何も変わりません。
|
||||
|
||||
しかし今、あなたが再びその関数を作成している最中に、型ヒントを使っていると想像してみて下さい。
|
||||
しかし今、あなたが再びその関数を作成している最中に、型ヒントを使っていると想像してみてください。
|
||||
|
||||
同じタイミングで`Ctrl+Space`で自動補完を実行すると、以下のようになります:
|
||||
同じタイミングで `Ctrl+Space` で自動補完を実行すると、以下のようになります:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image02.png">
|
||||
<img src="/img/python-types/image02.png">
|
||||
|
||||
これであれば、あなたは「ベルを鳴らす」一つを見つけるまで、オプションを見て、スクロールすることができます:
|
||||
これであれば、あなたは「ベルを鳴らす」ものを見つけるまで、オプションを見てスクロールできます:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image03.png">
|
||||
<img src="/img/python-types/image03.png">
|
||||
|
||||
## より強い動機
|
||||
## より強い動機 { #more-motivation }
|
||||
|
||||
この関数を見てください。すでに型ヒントを持っています:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial003.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
|
||||
|
||||
エディタは変数の型を知っているので、補完だけでなく、エラーチェックをすることもできます:
|
||||
|
||||
エディタは変数の型を知っているので、補完だけでなく、エラーチェックをすることもできます。
|
||||
<img src="/img/python-types/image04.png">
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image04.png">
|
||||
これで `age` を `str(age)` で文字列に変換して修正する必要があることがわかります:
|
||||
|
||||
これで`age`を`str(age)`で文字列に変換して修正する必要があることがわかります:
|
||||
{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial004.py hl[2] *}
|
||||
## 型の宣言 { #declaring-types }
|
||||
|
||||
|
||||
## 型の宣言
|
||||
|
||||
関数のパラメータとして、型ヒントを宣言している主な場所を確認しました。
|
||||
型ヒントを宣言する主な場所を見てきました。関数のパラメータです。
|
||||
|
||||
これは **FastAPI** で使用する主な場所でもあります。
|
||||
|
||||
### 単純な型
|
||||
### 単純な型 { #simple-types }
|
||||
|
||||
`str`だけでなく、Pythonの標準的な型すべてを宣言することができます。
|
||||
`str` だけでなく、Python の標準的な型すべてを宣言できます。
|
||||
|
||||
例えば、以下を使用可能です:
|
||||
|
||||
@@ -138,177 +133,216 @@ John Doe
|
||||
* `bool`
|
||||
* `bytes`
|
||||
|
||||
{* ../../docs_src/python_types/tutorial005.py hl[1] *}
|
||||
{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}
|
||||
|
||||
### `typing` モジュール { #typing-module }
|
||||
|
||||
いくつかの追加のユースケースでは、標準ライブラリの `typing` モジュールから何かをインポートする必要があるかもしれません。例えば「任意の型」を受け付けることを宣言したい場合、`typing` の `Any` を使えます:
|
||||
|
||||
```python
|
||||
from typing import Any
|
||||
|
||||
|
||||
### 型パラメータを持つジェネリック型
|
||||
def some_function(data: Any):
|
||||
print(data)
|
||||
```
|
||||
|
||||
データ構造の中には、`dict`、`list`、`set`、そして`tuple`のように他の値を含むことができるものがあります。また内部の値も独自の型を持つことができます。
|
||||
### ジェネリック型 { #generic-types }
|
||||
|
||||
これらの型や内部の型を宣言するには、Pythonの標準モジュール`typing`を使用します。
|
||||
一部の型は、角括弧内で「型パラメータ」を受け取り、内部の型を定義できます。例えば「文字列のリスト」は `list[str]` として宣言します。
|
||||
|
||||
これらの型ヒントをサポートするために特別に存在しています。
|
||||
このように型パラメータを取れる型は **Generic types**(ジェネリクス)と呼ばれます。
|
||||
|
||||
#### `List`
|
||||
次の組み込み型をジェネリクスとして(角括弧と内部の型で)使えます:
|
||||
|
||||
例えば、`str`の`list`の変数を定義してみましょう。
|
||||
* `list`
|
||||
* `tuple`
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
`typing`から`List`をインポートします(大文字の`L`を含む):
|
||||
#### List { #list }
|
||||
|
||||
{* ../../docs_src/python_types/tutorial006.py hl[1] *}
|
||||
例えば、`str` の `list` の変数を定義してみましょう。
|
||||
|
||||
同じコロン(`:`)の構文で変数を宣言します。
|
||||
|
||||
同じようにコロン(`:`)の構文で変数を宣言します。
|
||||
型として、`list` を指定します。
|
||||
|
||||
型として、`List`を入力します。
|
||||
リストはいくつかの内部の型を含む型なので、それらを角括弧で囲みます:
|
||||
|
||||
リストはいくつかの内部の型を含む型なので、それらを角括弧で囲んでいます。
|
||||
{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial006.py hl[4] *}
|
||||
|
||||
|
||||
/// tip | 豆知識
|
||||
/// info | 情報
|
||||
|
||||
角括弧内の内部の型は「型パラメータ」と呼ばれています。
|
||||
|
||||
この場合、`str`は`List`に渡される型パラメータです。
|
||||
この場合、`str` は `list` に渡される型パラメータです。
|
||||
|
||||
///
|
||||
|
||||
つまり: 変数`items`は`list`であり、このリストの各項目は`str`です。
|
||||
つまり: 変数 `items` は `list` であり、このリストの各項目は `str` です。
|
||||
|
||||
そうすることで、エディタはリストの項目を処理している間にもサポートを提供できます。
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image05.png">
|
||||
<img src="/img/python-types/image05.png">
|
||||
|
||||
タイプがなければ、それはほぼ不可能です。
|
||||
型がなければ、それはほぼ不可能です。
|
||||
|
||||
変数`item`はリスト`items`の要素の一つであることに注意してください。
|
||||
変数 `item` はリスト `items` の要素の一つであることに注意してください。
|
||||
|
||||
それでも、エディタはそれが`str`であることを知っていて、そのためのサポートを提供しています。
|
||||
それでも、エディタはそれが `str` であることを知っていて、そのためのサポートを提供しています。
|
||||
|
||||
#### `Tuple` と `Set`
|
||||
#### Tuple と Set { #tuple-and-set }
|
||||
|
||||
`tuple`と`set`の宣言も同様です:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial007.py hl[1,4] *}
|
||||
`tuple` と `set` の宣言も同様です:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}
|
||||
|
||||
つまり:
|
||||
|
||||
* 変数`items_t`は`int`、`int`、`str`の3つの項目を持つ`tuple`です
|
||||
* 変数 `items_t` は `int`、別の `int`、`str` の 3 つの項目を持つ `tuple` です。
|
||||
* 変数 `items_s` は `set` であり、その各項目は `bytes` 型です。
|
||||
|
||||
* 変数`items_s`はそれぞれの項目が`bytes`型である`set`です。
|
||||
#### Dict { #dict }
|
||||
|
||||
#### `Dict`
|
||||
`dict` を定義するには、カンマ区切りで 2 つの型パラメータを渡します。
|
||||
|
||||
`dict`を宣言するためには、カンマ区切りで2つの型パラメータを渡します。
|
||||
最初の型パラメータは `dict` のキーです。
|
||||
|
||||
最初の型パラメータは`dict`のキーです。
|
||||
|
||||
2番目の型パラメータは`dict`の値です。
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008.py hl[1,4] *}
|
||||
2 番目の型パラメータは `dict` の値です:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
|
||||
|
||||
つまり:
|
||||
|
||||
* 変数`prices`は`dict`であり:
|
||||
* この`dict`のキーは`str`型です。(つまり、各項目の名前)
|
||||
* この`dict`の値は`float`型です。(つまり、各項目の価格)
|
||||
* 変数 `prices` は `dict` です:
|
||||
* この `dict` のキーは `str` 型です(例えば、各項目の名前)。
|
||||
* この `dict` の値は `float` 型です(例えば、各項目の価格)。
|
||||
|
||||
#### `Optional`
|
||||
#### Union { #union }
|
||||
|
||||
また、`Optional`を使用して、変数が`str`のような型を持つことを宣言することもできますが、それは「オプション」であり、`None`にすることもできます。
|
||||
変数が **複数の型のいずれか** になり得ることを宣言できます。例えば、`int` または `str` です。
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!../../docs_src/python_types/tutorial009.py!}
|
||||
それを定義するには、両方の型を区切るために <dfn title="「ビット単位の OR 演算子」とも呼ばれますが、ここでの意味とは関係ありません。">縦棒(`|`)</dfn> を使います。
|
||||
|
||||
これは「ユニオン(union)」と呼ばれます。変数がそれら 2 つの型の集合の和集合のいずれかになり得るからです。
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
|
||||
```
|
||||
|
||||
ただの`str`の代わりに`Optional[str]`を使用することで、エディタは値が常に`str`であると仮定している場合に実際には`None`である可能性があるエラーを検出するのに役立ちます。
|
||||
これは `item` が `int` または `str` になり得ることを意味します.
|
||||
|
||||
#### ジェネリック型
|
||||
#### `None` の可能性 { #possibly-none }
|
||||
|
||||
以下のように角括弧で型パラメータを取る型を:
|
||||
値が `str` のような型を持つ可能性がある一方で、`None` にもなり得ることを宣言できます。
|
||||
|
||||
* `List`
|
||||
* `Tuple`
|
||||
* `Set`
|
||||
* `Dict`
|
||||
* `Optional`
|
||||
* ...など
|
||||
//// tab | Python 3.10+
|
||||
|
||||
**ジェネリック型** または **ジェネリクス** と呼びます。
|
||||
```Python hl_lines="1"
|
||||
{!> ../../docs_src/python_types/tutorial009_py310.py!}
|
||||
```
|
||||
|
||||
### 型としてのクラス
|
||||
////
|
||||
|
||||
ただの `str` の代わりに `str | None` を使用することで、値が常に `str` であると仮定しているときに、実際には `None` である可能性もあるというエラーをエディタが検出するのに役立ちます。
|
||||
|
||||
### 型としてのクラス { #classes-as-types }
|
||||
|
||||
変数の型としてクラスを宣言することもできます。
|
||||
|
||||
例えば、`Person`クラスという名前のクラスがあるとしましょう:
|
||||
名前を持つ `Person` クラスがあるとしましょう:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010.py hl[1,2,3] *}
|
||||
{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}
|
||||
|
||||
変数を `Person` 型として宣言できます:
|
||||
|
||||
変数の型を`Person`として宣言することができます:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010.py hl[6] *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}
|
||||
|
||||
そして、再び、すべてのエディタのサポートを得ることができます:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/python-types/image06.png">
|
||||
<img src="/img/python-types/image06.png">
|
||||
|
||||
## Pydanticのモデル
|
||||
これは「`one_person` はクラス `Person` の **インスタンス** である」ことを意味します。
|
||||
|
||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> はデータ検証を行うためのPythonライブラリです。
|
||||
「`one_person` は `Person` という名前の **クラス** である」という意味ではありません。
|
||||
|
||||
## Pydantic のモデル { #pydantic-models }
|
||||
|
||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> はデータ検証を行うための Python ライブラリです。
|
||||
|
||||
データの「形」を属性付きのクラスとして宣言します。
|
||||
|
||||
そして、それぞれの属性は型を持ちます。
|
||||
|
||||
さらに、いくつかの値を持つクラスのインスタンスを作成すると、その値を検証し、適切な型に変換して(もしそうであれば)全てのデータを持つオブジェクトを提供してくれます。
|
||||
さらに、いくつかの値を持つクラスのインスタンスを作成すると、その値を検証し、適切な型に変換して(もしそうであれば)すべてのデータを持つオブジェクトを提供してくれます。
|
||||
|
||||
また、その結果のオブジェクトですべてのエディタのサポートを受けることができます。
|
||||
|
||||
Pydanticの公式ドキュメントから引用:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial011.py *}
|
||||
Pydantic の公式ドキュメントからの例:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial011_py310.py *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
Pydanticについてより学びたい方は<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">ドキュメントを参照してください</a>.
|
||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic の詳細はドキュメントを参照してください</a>。
|
||||
|
||||
///
|
||||
|
||||
**FastAPI** はすべてPydanticをベースにしています。
|
||||
**FastAPI** はすべて Pydantic をベースにしています。
|
||||
|
||||
すべてのことは[チュートリアル - ユーザーガイド](tutorial/index.md){.internal-link target=_blank}で実際に見ることができます。
|
||||
すべてのことは [チュートリアル - ユーザーガイド](tutorial/index.md){.internal-link target=_blank} で実際に見ることができます。
|
||||
|
||||
## **FastAPI**での型ヒント
|
||||
## メタデータアノテーション付き型ヒント { #type-hints-with-metadata-annotations }
|
||||
|
||||
Python には、`Annotated` を使って型ヒントに **追加の <dfn title="データに関するデータ。この場合は型に関する情報(例えば説明)。">メタデータ</dfn>** を付与できる機能もあります。
|
||||
|
||||
`Annotated` は `typing` からインポートできます。
|
||||
|
||||
{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}
|
||||
|
||||
Python 自体は、この `Annotated` で何かをするわけではありません。また、エディタや他のツールにとっても、型は依然として `str` です。
|
||||
|
||||
しかし、`Annotated` 内のこのスペースを使って、アプリケーションをどのように動作させたいかについての追加メタデータを **FastAPI** に提供できます。
|
||||
|
||||
覚えておくべき重要な点は、`Annotated` に渡す **最初の「型パラメータ」** が **実際の型** であることです。残りは、他のツール向けのメタデータにすぎません。
|
||||
|
||||
今のところは、`Annotated` が存在し、それが標準の Python であることを知っておけば十分です。😎
|
||||
|
||||
後で、これがどれほど **強力** になり得るかを見ることになります。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これが **標準の Python** であるという事実は、エディタで、使用しているツール(コードの解析やリファクタリングなど)とともに、**可能な限り最高の開発体験** が得られることを意味します。 ✨
|
||||
|
||||
また、あなたのコードが他の多くの Python ツールやライブラリとも非常に互換性が高いことも意味します。 🚀
|
||||
|
||||
///
|
||||
|
||||
## **FastAPI** での型ヒント { #type-hints-in-fastapi }
|
||||
|
||||
**FastAPI** はこれらの型ヒントを利用していくつかのことを行います。
|
||||
|
||||
**FastAPI** では型ヒントを使って型パラメータを宣言すると以下のものが得られます:
|
||||
**FastAPI** では型ヒントを使ってパラメータを宣言すると以下のものが得られます:
|
||||
|
||||
* **エディタサポート**.
|
||||
* **型チェック**.
|
||||
* **エディタサポート**。
|
||||
* **型チェック**。
|
||||
|
||||
...そして **FastAPI** は同じように宣言をすると、以下のことを行います:
|
||||
...そして **FastAPI** は同じ宣言を使って、以下のことを行います:
|
||||
|
||||
* **要件の定義**: リクエストパスパラメータ、クエリパラメータ、ヘッダー、ボディ、依存関係などから要件を定義します。
|
||||
* **データの変換**: リクエストのデータを必要な型に変換します。
|
||||
* **データの検証**: リクエストごとに:
|
||||
* **要件の定義**: リクエストのパスパラメータ、クエリパラメータ、ヘッダー、ボディ、依存関係などから要件を定義します。
|
||||
* **データの変換**: リクエストから必要な型にデータを変換します。
|
||||
* **データの検証**: 各リクエストから来るデータについて:
|
||||
* データが無効な場合にクライアントに返される **自動エラー** を生成します。
|
||||
* **ドキュメント** OpenAPIを使用したAPI:
|
||||
* 自動的に対話型ドキュメントのユーザーインターフェイスで使用されます。
|
||||
* OpenAPI を使用して API を **ドキュメント化** します:
|
||||
* これは自動の対話型ドキュメントのユーザーインターフェイスで使われます。
|
||||
|
||||
すべてが抽象的に聞こえるかもしれません。心配しないでください。 この全ての動作は [チュートリアル - ユーザーガイド](tutorial/index.md){.internal-link target=_blank}で見ることができます。
|
||||
すべてが抽象的に聞こえるかもしれません。心配しないでください。 この全ての動作は [チュートリアル - ユーザーガイド](tutorial/index.md){.internal-link target=_blank} で見ることができます。
|
||||
|
||||
重要なのは、Pythonの標準的な型を使うことで、(クラスやデコレータなどを追加するのではなく)1つの場所で **FastAPI** が多くの作業を代わりにやってくれているということです。
|
||||
重要なのは、Python の標準的な型を使うことで、(クラスやデコレータなどを追加するのではなく)1 つの場所で **FastAPI** が多くの作業を代わりにやってくれているということです。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
すでにすべてのチュートリアルを終えて、型についての詳細を見るためにこのページに戻ってきた場合は、<a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">`mypy`のチートシートを参照してください</a>
|
||||
すでにすべてのチュートリアルを終えて、型についての詳細を見るためにこのページに戻ってきた場合は、良いリソースとして <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">`mypy` の「チートシート」</a> があります。
|
||||
|
||||
///
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# リソース { #resources }
|
||||
|
||||
追加リソース、外部リンクなど。✈️
|
||||
@@ -0,0 +1,11 @@
|
||||
/// details | 🌐 AI と人間による翻訳
|
||||
|
||||
この翻訳は、人間のガイドに基づいて AI によって作成されました。🤝
|
||||
|
||||
原文の意図を取り違えていたり、不自然な表現になっている可能性があります。🤖
|
||||
|
||||
[AI LLM をより適切に誘導するのを手伝う](https://fastapi.tiangolo.com/ja/contributing/#translations) ことで、この翻訳を改善できます。
|
||||
|
||||
[英語版](ENGLISH_VERSION_URL)
|
||||
|
||||
///
|
||||
@@ -1,4 +1,4 @@
|
||||
# バックグラウンドタスク
|
||||
# バックグラウンドタスク { #background-tasks }
|
||||
|
||||
レスポンスを返した *後に* 実行されるバックグラウンドタスクを定義できます。
|
||||
|
||||
@@ -9,17 +9,17 @@
|
||||
* 作業実行後のメール通知:
|
||||
* メールサーバーへの接続とメールの送信は「遅い」(数秒) 傾向があるため、すぐにレスポンスを返し、バックグラウンドでメール通知ができます。
|
||||
* データ処理:
|
||||
* たとえば、時間のかかる処理を必要とするファイル受信時には、「受信済み」(HTTP 202) のレスポンスを返し、バックグラウンドで処理できます。
|
||||
* たとえば、時間のかかる処理を必要とするファイル受信時には、「Accepted」(HTTP 202) のレスポンスを返し、バックグラウンドで処理できます。
|
||||
|
||||
## `BackgroundTasks` の使用
|
||||
## `BackgroundTasks` の使用 { #using-backgroundtasks }
|
||||
|
||||
まず初めに、`BackgroundTasks` をインポートし、` BackgroundTasks` の型宣言と共に、*path operation 関数* のパラメーターを定義します:
|
||||
まず初めに、`BackgroundTasks` をインポートし、`BackgroundTasks` の型宣言と共に、*path operation function* のパラメーターを定義します:
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}
|
||||
|
||||
**FastAPI** は、`BackgroundTasks` 型のオブジェクトを作成し、そのパラメーターに渡します。
|
||||
|
||||
## タスク関数の作成
|
||||
## タスク関数の作成 { #create-a-task-function }
|
||||
|
||||
バックグラウンドタスクとして実行される関数を作成します。
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
|
||||
また、書き込み操作では `async` と `await` を使用しないため、通常の `def` で関数を定義します。
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}
|
||||
|
||||
## バックグラウンドタスクの追加
|
||||
## バックグラウンドタスクの追加 { #add-the-background-task }
|
||||
|
||||
*path operations 関数* 内で、`.add_task()` メソッドを使用してタスク関数を *background tasks* オブジェクトに渡します。
|
||||
*path operation function* 内で、`.add_task()` メソッドを使用してタスク関数を *background tasks* オブジェクトに渡します。
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}
|
||||
|
||||
`.add_task()` は以下の引数を受け取ります:
|
||||
|
||||
@@ -45,40 +45,42 @@
|
||||
* タスク関数に順番に渡す必要のある引数の列 (`email`)。
|
||||
* タスク関数に渡す必要のあるキーワード引数 (`message="some notification"`)。
|
||||
|
||||
## 依存性注入
|
||||
## 依存性注入 { #dependency-injection }
|
||||
|
||||
`BackgroundTasks` の使用は依存性注入システムでも機能し、様々な階層 (*path operations 関数*、依存性 (依存可能性)、サブ依存性など) で `BackgroundTasks` 型のパラメーターを宣言できます。
|
||||
`BackgroundTasks` の使用は依存性注入システムでも機能し、様々な階層 (*path operation function*、依存性 (dependable)、サブ依存性など) で `BackgroundTasks` 型のパラメーターを宣言できます。
|
||||
|
||||
**FastAPI** は、それぞれの場合の処理方法と同じオブジェクトの再利用方法を知っているため、すべてのバックグラウンドタスクがマージされ、バックグラウンドで後で実行されます。
|
||||
**FastAPI** は、それぞれの場合の処理方法と同じオブジェクトの再利用方法を知っているため、すべてのバックグラウンドタスクがマージされ、バックグラウンドで後で実行されます:
|
||||
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial002.py hl[13,15,22,25] *}
|
||||
|
||||
この例では、レスポンスが送信された *後* にメッセージが `log.txt` ファイルに書き込まれます。
|
||||
|
||||
リクエストにクエリがあった場合、バックグラウンドタスクでログに書き込まれます。
|
||||
|
||||
そして、*path operations 関数* で生成された別のバックグラウンドタスクは、`email` パスパラメータを使用してメッセージを書き込みます。
|
||||
そして、*path operation function* で生成された別のバックグラウンドタスクは、`email` パスパラメータを使用してメッセージを書き込みます。
|
||||
|
||||
## 技術的な詳細
|
||||
## 技術的な詳細 { #technical-details }
|
||||
|
||||
`BackgroundTasks` クラスは、<a href="https://www.starlette.dev/background/" class="external-link" target="_blank">`starlette.background`</a>から直接取得されます。
|
||||
|
||||
これは、FastAPI に直接インポート/インクルードされるため、`fastapi` からインポートできる上に、`starlette.background`から別の `BackgroundTask` (末尾に `s` がない) を誤ってインポートすることを回避できます。
|
||||
|
||||
`BackgroundTasks`のみを使用することで (`BackgroundTask` ではなく)、`Request` オブジェクトを直接使用する場合と同様に、それを *path operations 関数* パラメーターとして使用し、**FastAPI** に残りの処理を任せることができます。
|
||||
`BackgroundTasks`のみを使用することで (`BackgroundTask` ではなく)、`Request` オブジェクトを直接使用する場合と同様に、それを *path operation function* パラメーターとして使用し、**FastAPI** に残りの処理を任せることができます。
|
||||
|
||||
それでも、FastAPI で `BackgroundTask` を単独で使用することは可能ですが、コード内でオブジェクトを作成し、それを含むStarlette `Response` を返す必要があります。
|
||||
|
||||
詳細については、<a href="https://www.starlette.dev/background/" class="external-link" target="_blank">バックグラウンドタスクに関する Starlette の公式ドキュメント</a>を参照して下さい。
|
||||
詳細については、<a href="https://www.starlette.dev/background/" class="external-link" target="_blank">Starlette のバックグラウンドタスクに関する公式ドキュメント</a>を参照して下さい。
|
||||
|
||||
## 警告
|
||||
## 注意 { #caveat }
|
||||
|
||||
大量のバックグラウンド計算が必要であり、必ずしも同じプロセスで実行する必要がない場合 (たとえば、メモリや変数などを共有する必要がない場合)、<a href="https://www.celeryproject.org/" class="external-link" target="_blank">Celery</a> のようなより大きな他のツールを使用するとメリットがあるかもしれません。
|
||||
大量のバックグラウンド計算が必要であり、必ずしも同じプロセスで実行する必要がない場合 (たとえば、メモリや変数などを共有する必要がない場合)、<a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a> のようなより大きな他のツールを使用するとメリットがあるかもしれません。
|
||||
|
||||
これらは、より複雑な構成、RabbitMQ や Redis などのメッセージ/ジョブキューマネージャーを必要とする傾向がありますが、複数のプロセス、特に複数のサーバーでバックグラウンドタスクを実行できます。
|
||||
|
||||
ただし、同じ **FastAPI** アプリから変数とオブジェクトにアクセスする必要がある場合、または小さなバックグラウンドタスク (電子メール通知の送信など) を実行する必要がある場合は、単に `BackgroundTasks` を使用できます。
|
||||
|
||||
## まとめ
|
||||
## まとめ { #recap }
|
||||
|
||||
`BackgroundTasks` をインポートして、*path operations 関数* や依存関係のパラメータに `BackgroundTasks`を使用し、バックグラウンドタスクを追加して下さい。
|
||||
*path operation functions* と依存性のパラメータで `BackgroundTasks`をインポートして使用し、バックグラウンドタスクを追加して下さい。
|
||||
|
||||
@@ -0,0 +1,504 @@
|
||||
# 大規模アプリケーション - 複数ファイル { #bigger-applications-multiple-files }
|
||||
|
||||
アプリケーションや Web API を作る場合、すべてを1つのファイルに収められることはほとんどありません。
|
||||
|
||||
**FastAPI** は、柔軟性を保ったままアプリケーションを構造化できる便利なツールを提供します。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
Flask 出身であれば、Flask の Blueprint に相当します。
|
||||
|
||||
///
|
||||
|
||||
## 例のファイル構成 { #an-example-file-structure }
|
||||
|
||||
次のようなファイル構成があるとします:
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ ├── dependencies.py
|
||||
│ └── routers
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── items.py
|
||||
│ │ └── users.py
|
||||
│ └── internal
|
||||
│ ├── __init__.py
|
||||
│ └── admin.py
|
||||
```
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
複数の `__init__.py` ファイルがあります: 各ディレクトリやサブディレクトリに1つずつです。
|
||||
|
||||
これにより、あるファイルから別のファイルへコードをインポートできます。
|
||||
|
||||
例えば、`app/main.py` では次のように書けます:
|
||||
|
||||
```
|
||||
from app.routers import items
|
||||
```
|
||||
|
||||
///
|
||||
|
||||
* `app` ディレクトリはすべてを含みます。そして空のファイル `app/__init__.py` があり、「Python パッケージ」(「Python モジュール」の集合): `app` です。
|
||||
* `app/main.py` ファイルがあります。Python パッケージ(`__init__.py` のあるディレクトリ)の中にあるため、そのパッケージの「モジュール」: `app.main` です。
|
||||
* `app/dependencies.py` ファイルもあり、`app/main.py` と同様に「モジュール」: `app.dependencies` です。
|
||||
* `app/routers/` サブディレクトリに別の `__init__.py` があるので、「Python サブパッケージ」: `app.routers` です。
|
||||
* `app/routers/items.py` はパッケージ `app/routers/` 内のファイルなので、サブモジュール: `app.routers.items` です。
|
||||
* `app/routers/users.py` も同様で、別のサブモジュール: `app.routers.users` です。
|
||||
* `app/internal/` サブディレクトリにも `__init__.py` があるので、別の「Python サブパッケージ」: `app.internal` です。
|
||||
* `app/internal/admin.py` は別のサブモジュール: `app.internal.admin` です。
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
|
||||
|
||||
同じファイル構成にコメントを付けると次のとおりです:
|
||||
|
||||
```bash
|
||||
.
|
||||
├── app # "app" is a Python package
|
||||
│ ├── __init__.py # this file makes "app" a "Python package"
|
||||
│ ├── main.py # "main" module, e.g. import app.main
|
||||
│ ├── dependencies.py # "dependencies" module, e.g. import app.dependencies
|
||||
│ └── routers # "routers" is a "Python subpackage"
|
||||
│ │ ├── __init__.py # makes "routers" a "Python subpackage"
|
||||
│ │ ├── items.py # "items" submodule, e.g. import app.routers.items
|
||||
│ │ └── users.py # "users" submodule, e.g. import app.routers.users
|
||||
│ └── internal # "internal" is a "Python subpackage"
|
||||
│ ├── __init__.py # makes "internal" a "Python subpackage"
|
||||
│ └── admin.py # "admin" submodule, e.g. import app.internal.admin
|
||||
```
|
||||
|
||||
## `APIRouter` { #apirouter }
|
||||
|
||||
ユーザーだけを扱うファイルが `/app/routers/users.py` のサブモジュールだとします。
|
||||
|
||||
ユーザーに関連する *path operations* をほかのコードから分離して整理したいはずです。
|
||||
|
||||
ただし、同じ **FastAPI** アプリケーション / Web API(同じ「Python パッケージ」の一部)である点は変わりません。
|
||||
|
||||
そのモジュールで `APIRouter` を使って *path operations* を作成できます。
|
||||
|
||||
### `APIRouter` のインポート { #import-apirouter }
|
||||
|
||||
クラス `FastAPI` と同様にインポートし、「インスタンス」を作成します:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *}
|
||||
|
||||
### `APIRouter` での *path operations* { #path-operations-with-apirouter }
|
||||
|
||||
これを使って *path operations* を宣言します。
|
||||
|
||||
使い方は `FastAPI` クラスと同じです:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
|
||||
|
||||
`APIRouter` は「ミニ `FastAPI`」のようなクラスと考えられます。
|
||||
|
||||
同じオプションがすべてサポートされています。
|
||||
|
||||
同じ `parameters`、`responses`、`dependencies`、`tags` などが使えます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
この例では変数名は `router` ですが、任意の名前を付けられます。
|
||||
|
||||
///
|
||||
|
||||
この `APIRouter` をメインの `FastAPI` アプリに取り込みますが、その前に依存関係と別の `APIRouter` を確認します。
|
||||
|
||||
## 依存関係 { #dependencies }
|
||||
|
||||
アプリケーションの複数箇所で使う依存関係が必要になります。
|
||||
|
||||
そのため、専用の `dependencies` モジュール(`app/dependencies.py`)に置きます。
|
||||
|
||||
ここではカスタムヘッダー `X-Token` を読む簡単な依存関係を使います:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
この例を簡単にするために架空のヘッダーを使っています。
|
||||
|
||||
しかし実際には、組み込みの [Security utilities](security/index.md){.internal-link target=_blank} を使う方が良い結果になります。
|
||||
|
||||
///
|
||||
|
||||
## 別モジュールでの `APIRouter` { #another-module-with-apirouter }
|
||||
|
||||
アプリケーションの「items」を扱うエンドポイントが `app/routers/items.py` のモジュールにあるとします。
|
||||
|
||||
次の *path operations* があります:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
|
||||
構造は `app/routers/users.py` と同じです。
|
||||
|
||||
しかし、もう少し賢くしてコードを少し簡潔にしたいところです。
|
||||
|
||||
このモジュールのすべての *path operations* には同じものがあると分かっています:
|
||||
|
||||
* パスの `prefix`: `/items`
|
||||
* `tags`(1つのタグ: `items`)
|
||||
* 追加の `responses`
|
||||
* `dependencies`: 先ほど作成した `X-Token` の依存関係が必要
|
||||
|
||||
そこで、各 *path operation* に個別に追加する代わりに、これらを `APIRouter` に追加できます。
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
|
||||
|
||||
各 *path operation* のパスは次のように `/` で始める必要があるため:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@router.get("/{item_id}")
|
||||
async def read_item(item_id: str):
|
||||
...
|
||||
```
|
||||
|
||||
...prefix の末尾に `/` を含めてはいけません。
|
||||
|
||||
この場合の prefix は `/items` です。
|
||||
|
||||
また、`tags` のリストや追加の `responses` を、このルーターに含まれるすべての *path operations* に適用するよう追加できます。
|
||||
|
||||
さらに `dependencies` のリストを追加できます。これはこのルーター内のすべての *path operations* に追加され、それらへの各リクエストごとに実行・解決されます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
[*path operation デコレータ*の依存関係](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} と同様に、*path operation 関数*には値は渡されない点に注意してください。
|
||||
|
||||
///
|
||||
|
||||
最終的に、item のパスは次のとおりになります:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
|
||||
...意図したとおりです。
|
||||
|
||||
* これらには、文字列 `"items"` を1つ含むタグのリストが付きます。
|
||||
* これらの「タグ」は、(OpenAPI を使う)自動インタラクティブドキュメントで特に有用です。
|
||||
* すべてに事前定義した `responses` が含まれます。
|
||||
* これらすべての *path operations* では、実行前に `dependencies` のリストが評価・実行されます。
|
||||
* 特定の *path operation* に依存関係を宣言した場合は、**それらも実行されます**。
|
||||
* ルーターの依存関係が先に実行され、その後に[デコレータ内の `dependencies`](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}、次に通常のパラメータ依存関係が続きます。
|
||||
* [`scopes` を伴う `Security` 依存関係](../advanced/security/oauth2-scopes.md){.internal-link target=_blank} を追加することもできます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`APIRouter` に `dependencies` を置くことで、*path operations* のグループ全体に認証を要求する、といった用途に使えます。個々の *path operation* に依存関係を追加していなくても構いません。
|
||||
|
||||
///
|
||||
|
||||
/// check | 確認
|
||||
|
||||
`prefix`、`tags`、`responses`、`dependencies` の各パラメータは(ほかの多くのケースと同様に)コード重複を避けるための **FastAPI** の機能です。
|
||||
|
||||
///
|
||||
|
||||
### 依存関係をインポート { #import-the-dependencies }
|
||||
|
||||
このコードはモジュール `app.routers.items`(ファイル `app/routers/items.py`)内にあります。
|
||||
|
||||
そして依存関係の関数はモジュール `app.dependencies`(ファイル `app/dependencies.py`)から取得する必要があります。
|
||||
|
||||
そこで、依存関係には `..` を使った相対インポートを使います:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *}
|
||||
|
||||
#### 相対インポートの仕組み { #how-relative-imports-work }
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
インポートの仕組みを十分理解している場合は、次の節に進んでください。
|
||||
|
||||
///
|
||||
|
||||
ドット1つ `.` を使うと、次のような意味になります:
|
||||
|
||||
```Python
|
||||
from .dependencies import get_token_header
|
||||
```
|
||||
|
||||
意味:
|
||||
|
||||
* このモジュール(`app/routers/items.py`)が存在する同じパッケージ(ディレクトリ `app/routers/`)から開始し...
|
||||
* モジュール `dependencies`(仮想的には `app/routers/dependencies.py`)を探し...
|
||||
* そこから関数 `get_token_header` をインポートする。
|
||||
|
||||
しかしそのファイルは存在せず、実際の依存関係は `app/dependencies.py` にあります。
|
||||
|
||||
アプリ/ファイル構成がどうなっていたかを思い出してください:
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
|
||||
|
||||
---
|
||||
|
||||
ドット2つ `..` を使うと、次のようになります:
|
||||
|
||||
```Python
|
||||
from ..dependencies import get_token_header
|
||||
```
|
||||
|
||||
意味:
|
||||
|
||||
* このモジュール(`app/routers/items.py`)が存在する同じパッケージ(ディレクトリ `app/routers/`)から開始し...
|
||||
* 親パッケージ(ディレクトリ `app/`)に移動し...
|
||||
* そこでモジュール `dependencies`(ファイル `app/dependencies.py`)を探し...
|
||||
* そこから関数 `get_token_header` をインポートする。
|
||||
|
||||
これは正しく動作します! 🎉
|
||||
|
||||
---
|
||||
|
||||
同様に、ドット3つ `...` を使うと:
|
||||
|
||||
```Python
|
||||
from ...dependencies import get_token_header
|
||||
```
|
||||
|
||||
意味:
|
||||
|
||||
* このモジュール(`app/routers/items.py`)が存在する同じパッケージ(ディレクトリ `app/routers/`)から開始し...
|
||||
* 親パッケージ(ディレクトリ `app/`)に移動し...
|
||||
* さらにその親パッケージに移動しようとします(`app` は最上位なので親パッケージはありません 😱)...
|
||||
* そこでモジュール `dependencies`(ファイル `app/dependencies.py`)を探し...
|
||||
* そこから関数 `get_token_header` をインポートする。
|
||||
|
||||
これは `app/` より上位のパッケージ(独自の `__init__.py` を持つ)を参照することになります。しかしそのようなものはありません。そのため、この例ではエラーになります。🚨
|
||||
|
||||
これで仕組みが分かったので、どれほど複雑でも自分のアプリで相対インポートを使えます。🤓
|
||||
|
||||
### カスタムの `tags`、`responses`、`dependencies` を追加 { #add-some-custom-tags-responses-and-dependencies }
|
||||
|
||||
`APIRouter` に追加済みなので、各 *path operation* に `/items` の prefix や `tags=["items"]` を付けていません。
|
||||
|
||||
しかし、特定の *path operation* に適用される _追加の_ `tags` や、その *path operation* 固有の追加の `responses` を加えることはできます:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
この最後の *path operation* は、`["items", "custom"]` のタグの組み合わせを持ちます。
|
||||
|
||||
またドキュメントには `404` と `403` の両方のレスポンスが表示されます。
|
||||
|
||||
///
|
||||
|
||||
## メインの `FastAPI` { #the-main-fastapi }
|
||||
|
||||
次に、`app/main.py` のモジュールを見ていきます。
|
||||
|
||||
ここでクラス `FastAPI` をインポートして使用します。
|
||||
|
||||
これはすべてをまとめるアプリケーションのメインファイルになります。
|
||||
|
||||
そして大部分のロジックはそれぞれの専用モジュールに置かれるため、メインファイルはかなりシンプルになります。
|
||||
|
||||
### `FastAPI` のインポート { #import-fastapi }
|
||||
|
||||
通常どおり `FastAPI` クラスをインポートして作成します。
|
||||
|
||||
さらに、各 `APIRouter` の依存関係と組み合わされる[グローバル依存関係](dependencies/global-dependencies.md){.internal-link target=_blank}も宣言できます:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *}
|
||||
|
||||
### `APIRouter` のインポート { #import-the-apirouter }
|
||||
|
||||
次に、`APIRouter` を持つ他のサブモジュールをインポートします:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *}
|
||||
|
||||
`app/routers/users.py` と `app/routers/items.py` は同じ Python パッケージ `app` のサブモジュールなので、1つのドット `.` を使った「相対インポート」でインポートできます。
|
||||
|
||||
### インポートの動作 { #how-the-importing-works }
|
||||
|
||||
次の部分:
|
||||
|
||||
```Python
|
||||
from .routers import items, users
|
||||
```
|
||||
|
||||
は次の意味です:
|
||||
|
||||
* このモジュール(`app/main.py`)が存在する同じパッケージ(ディレクトリ `app/`)から開始し...
|
||||
* サブパッケージ `routers`(ディレクトリ `app/routers/`)を探し...
|
||||
* そこからサブモジュール `items`(ファイル `app/routers/items.py`)と `users`(ファイル `app/routers/users.py`)をインポートする...
|
||||
|
||||
モジュール `items` には変数 `router`(`items.router`)があります。これは `app/routers/items.py` で作成した `APIRouter` オブジェクトと同じものです。
|
||||
|
||||
モジュール `users` についても同様です。
|
||||
|
||||
次のようにインポートすることもできます:
|
||||
|
||||
```Python
|
||||
from app.routers import items, users
|
||||
```
|
||||
|
||||
/// info | 情報
|
||||
|
||||
最初のバージョンは「相対インポート」です:
|
||||
|
||||
```Python
|
||||
from .routers import items, users
|
||||
```
|
||||
|
||||
2つ目のバージョンは「絶対インポート」です:
|
||||
|
||||
```Python
|
||||
from app.routers import items, users
|
||||
```
|
||||
|
||||
Python のパッケージとモジュールについて詳しくは、<a href="https://docs.python.org/3/tutorial/modules.html" class="external-link" target="_blank">公式の Python モジュールに関するドキュメント</a>をご覧ください。
|
||||
|
||||
///
|
||||
|
||||
### 名前衝突の回避 { #avoid-name-collisions }
|
||||
|
||||
サブモジュール `items` の変数 `router` だけをインポートするのではなく、サブモジュール自体を直接インポートしています。
|
||||
|
||||
これは、サブモジュール `users` にも `router` という変数があるためです。
|
||||
|
||||
もし次のように続けてインポートした場合:
|
||||
|
||||
```Python
|
||||
from .routers.items import router
|
||||
from .routers.users import router
|
||||
```
|
||||
|
||||
`users` の `router` が `items` のものを上書きしてしまい、同時に両方を使えなくなります。
|
||||
|
||||
同じファイルで両方を使えるようにするため、サブモジュールを直接インポートします:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *}
|
||||
|
||||
### `users` と `items` の `APIRouter` を取り込む { #include-the-apirouters-for-users-and-items }
|
||||
|
||||
では、サブモジュール `users` と `items` から `router` を取り込みます:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`users.router` は、ファイル `app/routers/users.py` 内の `APIRouter` を含みます。
|
||||
|
||||
`items.router` は、ファイル `app/routers/items.py` 内の `APIRouter` を含みます。
|
||||
|
||||
///
|
||||
|
||||
`app.include_router()` を使って、各 `APIRouter` をメインの `FastAPI` アプリケーションに追加できます。
|
||||
|
||||
そのルーターのすべてのルートがアプリに含まれます。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
実際には、`APIRouter` で宣言された各 *path operation* ごとに内部的に *path operation* が作成されます。
|
||||
|
||||
つまり裏側では、すべてが同じ単一のアプリであるかのように動作します。
|
||||
|
||||
///
|
||||
|
||||
/// check | 確認
|
||||
|
||||
ルーターを取り込んでもパフォーマンスを心配する必要はありません。
|
||||
|
||||
これは起動時にマイクロ秒で行われます。
|
||||
|
||||
したがってパフォーマンスには影響しません。⚡
|
||||
|
||||
///
|
||||
|
||||
### カスタムの `prefix`、`tags`、`responses`、`dependencies` 付きで `APIRouter` を取り込む { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
|
||||
|
||||
あなたの組織から `app/internal/admin.py` ファイルが提供されたとしましょう。
|
||||
|
||||
そこには、組織が複数プロジェクトで共有している管理用の *path operations* を持つ `APIRouter` が含まれています。
|
||||
|
||||
この例ではとてもシンプルですが、組織内の他プロジェクトと共有しているため、`APIRouter` 自体を直接変更して `prefix`、`dependencies`、`tags` などを追加できないとします:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *}
|
||||
|
||||
それでも、`APIRouter` を取り込む際にカスタムの `prefix` を設定してすべての *path operations* を `/admin` で始めたい、既存の `dependencies` で保護したい、さらに `tags` と `responses` も含めたいとします。
|
||||
|
||||
元の `APIRouter` を変更することなく、`app.include_router()` にこれらのパラメータを渡すことで宣言できます:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *}
|
||||
|
||||
このようにすると、元の `APIRouter` は未変更のままなので、同じ `app/internal/admin.py` ファイルを組織内の他プロジェクトとも引き続き共有できます。
|
||||
|
||||
結果として、このアプリ内では `admin` モジュールの各 *path operation* が次のようになります:
|
||||
|
||||
* prefix は `/admin`
|
||||
* タグは `admin`
|
||||
* 依存関係は `get_token_header`
|
||||
* レスポンスは `418` 🍵
|
||||
|
||||
ただし、これはこのアプリ内のその `APIRouter` にのみ影響し、それを使用する他のコードには影響しません。
|
||||
|
||||
例えば、他のプロジェクトでは同じ `APIRouter` を別の認証方式で使うこともできます。
|
||||
|
||||
### *path operation* を追加 { #include-a-path-operation }
|
||||
|
||||
`FastAPI` アプリに *path operations* を直接追加することもできます。
|
||||
|
||||
ここでは(できることを示すためだけに)追加します 🤷:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *}
|
||||
|
||||
そして、`app.include_router()` で追加したほかの *path operations* と一緒に正しく動作します。
|
||||
|
||||
/// info | 非常に技術的な詳細
|
||||
|
||||
注記: これは非常に技術的な詳細で、**読み飛ばして構いません**。
|
||||
|
||||
---
|
||||
|
||||
`APIRouter` は「マウント」されておらず、アプリケーションの他部分から分離されていません。
|
||||
|
||||
これは、それらの *path operations* を OpenAPI スキーマやユーザーインターフェースに含めたいからです。
|
||||
|
||||
完全に分離して独立に「マウント」できないため、*path operations* は直接取り込まれるのではなく「クローン(再作成)」されます。
|
||||
|
||||
///
|
||||
|
||||
## 自動APIドキュメントの確認 { #check-the-automatic-api-docs }
|
||||
|
||||
アプリを実行します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev app/main.py
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
そして <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> を開きます。
|
||||
|
||||
すべてのサブモジュール由来のパスを含む自動 API ドキュメントが表示され、正しいパス(および prefix)と正しいタグが使われているのが分かります:
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/image01.png">
|
||||
|
||||
## 同じルーターを異なる `prefix` で複数回取り込む { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
|
||||
同じルーターに対して、異なる prefix で `.include_router()` を複数回使うこともできます。
|
||||
|
||||
例えば、同じ API を `/api/v1` と `/api/latest` のように異なる prefix で公開する場合に役立ちます。
|
||||
|
||||
高度な使い方なので不要かもしれませんが、必要な場合に備えて用意されています。
|
||||
|
||||
## `APIRouter` を別の `APIRouter` に取り込む { #include-an-apirouter-in-another }
|
||||
|
||||
`APIRouter` を `FastAPI` アプリケーションに取り込めるのと同じように、`APIRouter` を別の `APIRouter` に取り込むこともできます:
|
||||
|
||||
```Python
|
||||
router.include_router(other_router)
|
||||
```
|
||||
|
||||
`router` を `FastAPI` アプリに取り込む前にこれを実行して、`other_router` の *path operations* も含まれるようにしてください。
|
||||
@@ -1,12 +1,13 @@
|
||||
# ボディ - フィールド
|
||||
# ボディ - フィールド { #body-fields }
|
||||
|
||||
`Query`や`Path`、`Body`を使って *path operation関数* のパラメータに追加のバリデーションやメタデータを宣言するのと同じように、Pydanticの`Field`を使ってPydanticモデルの内部でバリデーションやメタデータを宣言することができます。
|
||||
|
||||
## `Field`のインポート
|
||||
## `Field`のインポート { #import-field }
|
||||
|
||||
まず、以下のようにインポートします:
|
||||
|
||||
{* ../../docs_src/body_fields/tutorial001.py hl[4] *}
|
||||
{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}
|
||||
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
@@ -14,11 +15,11 @@
|
||||
|
||||
///
|
||||
|
||||
## モデルの属性の宣言
|
||||
## モデルの属性の宣言 { #declare-model-attributes }
|
||||
|
||||
以下のように`Field`をモデルの属性として使用することができます:
|
||||
|
||||
{* ../../docs_src/body_fields/tutorial001.py hl[11,12,13,14] *}
|
||||
{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}
|
||||
|
||||
`Field`は`Query`や`Path`、`Body`と同じように動作し、全く同様のパラメータなどを持ちます。
|
||||
|
||||
@@ -40,13 +41,20 @@
|
||||
|
||||
///
|
||||
|
||||
## 追加情報の追加
|
||||
## 追加情報の追加 { #add-extra-information }
|
||||
|
||||
追加情報は`Field`や`Query`、`Body`などで宣言することができます。そしてそれは生成されたJSONスキーマに含まれます。
|
||||
|
||||
後に例を用いて宣言を学ぶ際に、追加情報を追加する方法を学べます。
|
||||
|
||||
## まとめ
|
||||
/// warning | 注意
|
||||
|
||||
`Field`に渡された追加のキーは、結果として生成されるアプリケーションのOpenAPIスキーマにも含まれます。
|
||||
これらのキーは必ずしもOpenAPI仕様の一部であるとは限らないため、例えば[OpenAPI validator](https://validator.swagger.io/)などの一部のOpenAPIツールは、生成されたスキーマでは動作しない場合があります。
|
||||
|
||||
///
|
||||
|
||||
## まとめ { #recap }
|
||||
|
||||
Pydanticの`Field`を使用して、モデルの属性に追加のバリデーションやメタデータを宣言することができます。
|
||||
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
# ボディ - 複数のパラメータ
|
||||
# ボディ - 複数のパラメータ { #body-multiple-parameters }
|
||||
|
||||
これまで`Path`と`Query`をどう使うかを見てきましたが、リクエストボディの宣言のより高度な使い方を見てみましょう。
|
||||
これまで`Path`と`Query`をどう使うかを見てきましたが、リクエストボディ宣言のより高度な使い方を見てみましょう。
|
||||
|
||||
## `Path`、`Query`とボディパラメータを混ぜる
|
||||
## `Path`、`Query`とボディパラメータを混ぜる { #mix-path-query-and-body-parameters }
|
||||
|
||||
まず、もちろん、`Path`と`Query`とリクエストボディのパラメータの宣言は自由に混ぜることができ、 **FastAPI** は何をするべきかを知っています。
|
||||
まず、もちろん、`Path`と`Query`とリクエストボディのパラメータ宣言は自由に混ぜることができ、 **FastAPI** は何をするべきかを知っています。
|
||||
|
||||
また、デフォルトの`None`を設定することで、ボディパラメータをオプションとして宣言することもできます:
|
||||
また、デフォルトを`None`に設定することで、ボディパラメータをオプションとして宣言することもできます:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial001.py hl[19,20,21] *}
|
||||
{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
この場合、ボディから取得する`item`はオプションであることに注意してください。デフォルト値は`None`です。
|
||||
この場合、ボディから取得する`item`はオプションであることに注意してください。デフォルト値が`None`になっているためです。
|
||||
|
||||
///
|
||||
|
||||
## 複数のボディパラメータ
|
||||
## 複数のボディパラメータ { #multiple-body-parameters }
|
||||
|
||||
上述の例では、*path operations*は`item`の属性を持つ以下のようなJSONボディを期待していました:
|
||||
上述の例では、*path operations*は`Item`の属性を持つ以下のようなJSONボディを期待していました:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -31,11 +31,12 @@
|
||||
|
||||
しかし、`item`と`user`のように複数のボディパラメータを宣言することもできます:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial002.py hl[22] *}
|
||||
{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
|
||||
|
||||
この場合、**FastAPI**は関数内に複数のボディパラメータ(Pydanticモデルである2つのパラメータ)があることに気付きます。
|
||||
|
||||
そのため、パラメータ名をボディのキー(フィールド名)として使用し、以下のようなボディを期待しています:
|
||||
この場合、**FastAPI**は関数内に複数のボディパラメータがあることに気付きます(Pydanticモデルである2つのパラメータがあります)。
|
||||
|
||||
そのため、パラメータ名をボディのキー(フィールド名)として使用し、以下のようなボディを期待します:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -62,7 +63,7 @@
|
||||
|
||||
複合データの検証を行い、OpenAPIスキーマや自動ドキュメントのように文書化してくれます。
|
||||
|
||||
## ボディ内の単数値
|
||||
## ボディ内の単数値 { #singular-values-in-body }
|
||||
|
||||
クエリとパスパラメータの追加データを定義するための `Query` と `Path` があるのと同じように、 **FastAPI** は同等の `Body` を提供します。
|
||||
|
||||
@@ -72,12 +73,11 @@
|
||||
|
||||
しかし、`Body`を使用して、**FastAPI** に別のボディキーとして扱うように指示することができます:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial003.py hl[23] *}
|
||||
|
||||
この場合、**FastAPI** は以下のようなボディを期待します:
|
||||
|
||||
|
||||
```JSON
|
||||
{
|
||||
"item": {
|
||||
@@ -96,41 +96,42 @@
|
||||
|
||||
繰り返しになりますが、データ型の変換、検証、文書化などを行います。
|
||||
|
||||
## 複数のボディパラメータとクエリ
|
||||
## 複数のボディパラメータとクエリ { #multiple-body-params-and-query }
|
||||
|
||||
もちろん、ボディパラメータに加えて、必要に応じて追加のクエリパラメータを宣言することもできます。
|
||||
|
||||
デフォルトでは、単数値はクエリパラメータとして解釈されるので、明示的に `Query` を追加する必要はありません。
|
||||
デフォルトでは、単数値はクエリパラメータとして解釈されるので、明示的に `Query` を追加する必要はなく、次のようにできます:
|
||||
|
||||
```Python
|
||||
q: str = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
以下において:
|
||||
例えば:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial004.py hl[27] *}
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`Body`もまた、後述する `Query` や `Path` などと同様に、すべての検証パラメータとメタデータパラメータを持っています。
|
||||
`Body`もまた、後述する `Query` や `Path` などと同様に、すべての追加検証パラメータとメタデータパラメータを持っています。
|
||||
|
||||
///
|
||||
|
||||
## 単一のボディパラメータの埋め込み
|
||||
## 単一のボディパラメータの埋め込み { #embed-a-single-body-parameter }
|
||||
|
||||
Pydanticモデル`Item`のボディパラメータ`item`を1つだけ持っているとしましょう。
|
||||
Pydanticモデル`Item`の単一の`item`ボディパラメータしかないとしましょう。
|
||||
|
||||
デフォルトでは、**FastAPI**はそのボディを直接期待します。
|
||||
|
||||
しかし、追加のボディパラメータを宣言したときのように、キー `item` を持つ JSON とその中のモデルの内容を期待したい場合は、特別な `Body` パラメータ `embed` を使うことができます:
|
||||
しかし、追加のボディパラメータを宣言したときのように、キー `item` を持つ JSON と、その中のモデル内容を期待したい場合は、特別な `Body` パラメータ `embed` を使うことができます:
|
||||
|
||||
```Python
|
||||
item: Item = Body(..., embed=True)
|
||||
item: Item = Body(embed=True)
|
||||
```
|
||||
|
||||
以下において:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial005.py hl[17] *}
|
||||
{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
|
||||
|
||||
|
||||
この場合、**FastAPI** は以下のようなボディを期待します:
|
||||
|
||||
@@ -156,9 +157,9 @@ item: Item = Body(..., embed=True)
|
||||
}
|
||||
```
|
||||
|
||||
## まとめ
|
||||
## まとめ { #recap }
|
||||
|
||||
リクエストが単一のボディしか持てない場合でも、*path operation関数*に複数のボディパラメータを追加することができます。
|
||||
リクエストが単一のボディしか持てない場合でも、*path operation function*に複数のボディパラメータを追加することができます。
|
||||
|
||||
しかし、**FastAPI** はそれを処理し、関数内の正しいデータを与え、*path operation*内の正しいスキーマを検証し、文書化します。
|
||||
|
||||
|
||||
@@ -1,36 +1,26 @@
|
||||
# ボディ - ネストされたモデル
|
||||
# ボディ - ネストされたモデル { #body-nested-models }
|
||||
|
||||
**FastAPI** を使用すると、深くネストされた任意のモデルを定義、検証、文書化、使用することができます(Pydanticのおかげです)。
|
||||
|
||||
## リストのフィールド
|
||||
## リストのフィールド { #list-fields }
|
||||
|
||||
属性をサブタイプとして定義することができます。例えば、Pythonの`list`は以下のように定義できます:
|
||||
属性をサブタイプとして定義することができます。例えば、Pythonの`list`:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial001.py hl[12] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
|
||||
|
||||
これにより、各項目の型は宣言されていませんが、`tags`はある項目のリストになります。
|
||||
これにより、各項目の型は宣言されていませんが、`tags`はリストになります。
|
||||
|
||||
## タイプパラメータを持つリストのフィールド
|
||||
## タイプパラメータを持つリストのフィールド { #list-fields-with-type-parameter }
|
||||
|
||||
しかし、Pythonには型や「タイプパラメータ」を使ってリストを宣言する方法があります:
|
||||
しかし、Pythonには内部の型、または「タイプパラメータ」を使ってリストを宣言するための特定の方法があります:
|
||||
|
||||
### typingの`List`をインポート
|
||||
### タイプパラメータを持つ`list`の宣言 { #declare-a-list-with-a-type-parameter }
|
||||
|
||||
まず、Pythonの標準の`typing`モジュールから`List`をインポートします:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
|
||||
|
||||
### タイプパラメータを持つ`List`の宣言
|
||||
|
||||
`list`や`dict`、`tuple`のようなタイプパラメータ(内部の型)を持つ型を宣言するには:
|
||||
|
||||
* `typing`モジュールからそれらをインストールします。
|
||||
* 角括弧(`[`と`]`)を使って「タイプパラメータ」として内部の型を渡します:
|
||||
`list`、`dict`、`tuple`のようにタイプパラメータ(内部の型)を持つ型を宣言するには、
|
||||
角括弧(`[`と`]`)を使って内部の型を「タイプパラメータ」として渡します。
|
||||
|
||||
```Python
|
||||
from typing import List
|
||||
|
||||
my_list: List[str]
|
||||
my_list: list[str]
|
||||
```
|
||||
|
||||
型宣言の標準的なPythonの構文はこれだけです。
|
||||
@@ -39,17 +29,17 @@ my_list: List[str]
|
||||
|
||||
そのため、以下の例では`tags`を具体的な「文字列のリスト」にすることができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial002.py hl[14] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
|
||||
|
||||
## セット型
|
||||
## セット型 { #set-types }
|
||||
|
||||
しかし、よく考えてみると、タグは繰り返すべきではなく、おそらくユニークな文字列になるのではないかと気付いたとします。
|
||||
|
||||
そして、Pythonにはユニークな項目のセットのための特別なデータ型`set`があります。
|
||||
|
||||
そのため、以下のように、`Set`をインポートして`str`の`set`として`tags`を宣言することができます:
|
||||
そして、`tags`を文字列のセットとして宣言できます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial003.py hl[1,14] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}
|
||||
|
||||
これを使えば、データが重複しているリクエストを受けた場合でも、ユニークな項目のセットに変換されます。
|
||||
|
||||
@@ -57,27 +47,27 @@ my_list: List[str]
|
||||
|
||||
また、それに応じて注釈をつけたり、文書化したりします。
|
||||
|
||||
## ネストされたモデル
|
||||
## ネストされたモデル { #nested-models }
|
||||
|
||||
Pydanticモデルの各属性には型があります。
|
||||
|
||||
しかし、その型はそれ自体が別のPydanticモデルである可能性があります。
|
||||
|
||||
そのため、特定の属性名、型、バリデーションを指定して、深くネストしたJSON`object`を宣言することができます。
|
||||
そのため、特定の属性名、型、バリデーションを指定して、深くネストしたJSON「オブジェクト」を宣言することができます。
|
||||
|
||||
すべては、任意のネストにされています。
|
||||
|
||||
### サブモデルの定義
|
||||
### サブモデルの定義 { #define-a-submodel }
|
||||
|
||||
例えば、`Image`モデルを定義することができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial004.py hl[9,10,11] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}
|
||||
|
||||
### サブモデルを型として使用
|
||||
### サブモデルを型として使用 { #use-the-submodel-as-a-type }
|
||||
|
||||
そして、それを属性の型として使用することができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial004.py hl[20] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
|
||||
|
||||
これは **FastAPI** が以下のようなボディを期待することを意味します:
|
||||
|
||||
@@ -102,23 +92,23 @@ Pydanticモデルの各属性には型があります。
|
||||
* データの検証
|
||||
* 自動文書化
|
||||
|
||||
## 特殊な型とバリデーション
|
||||
## 特殊な型とバリデーション { #special-types-and-validation }
|
||||
|
||||
`str`や`int`、`float`のような通常の単数型の他にも、`str`を継承したより複雑な単数型を使うこともできます。
|
||||
`str`や`int`、`float`などの通常の単数型の他にも、`str`を継承したより複雑な単数型を使うこともできます。
|
||||
|
||||
すべてのオプションをみるには、<a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">Pydanticのエキゾチック な型</a>のドキュメントを確認してください。次の章でいくつかの例をみることができます。
|
||||
すべてのオプションをみるには、<a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">Pydanticの型の概要</a>を確認してください。次の章でいくつかの例をみることができます。
|
||||
|
||||
例えば、`Image`モデルのように`url`フィールドがある場合、`str`の代わりにPydanticの`HttpUrl`を指定することができます:
|
||||
例えば、`Image`モデルのように`url`フィールドがある場合、`str`の代わりにPydanticの`HttpUrl`のインスタンスとして宣言することができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial005.py hl[4,10] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
|
||||
|
||||
文字列は有効なURLであることが確認され、そのようにJSONスキーマ・OpenAPIで文書化されます。
|
||||
文字列は有効なURLであることが確認され、そのようにJSON Schema / OpenAPIで文書化されます。
|
||||
|
||||
## サブモデルのリストを持つ属性
|
||||
## サブモデルのリストを持つ属性 { #attributes-with-lists-of-submodels }
|
||||
|
||||
Pydanticモデルを`list`や`set`などのサブタイプとして使用することもできます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial006.py hl[20] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
|
||||
|
||||
これは、次のようなJSONボディを期待します(変換、検証、ドキュメントなど):
|
||||
|
||||
@@ -152,59 +142,59 @@ Pydanticモデルを`list`や`set`などのサブタイプとして使用する
|
||||
|
||||
///
|
||||
|
||||
## 深くネストされたモデル
|
||||
## 深くネストされたモデル { #deeply-nested-models }
|
||||
|
||||
深くネストされた任意のモデルを定義することができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial007.py hl[9,14,20,23,27] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`Offer`は`Item`のリストであり、オプションの`Image`のリストを持っていることに注目してください。
|
||||
`Offer`は`Item`のリストであり、それらがさらにオプションの`Image`のリストを持っていることに注目してください。
|
||||
|
||||
///
|
||||
|
||||
## 純粋なリストのボディ
|
||||
## 純粋なリストのボディ { #bodies-of-pure-lists }
|
||||
|
||||
期待するJSONボディのトップレベルの値がJSON`array`(Pythonの`list`)であれば、Pydanticモデルと同じように、関数のパラメータで型を宣言することができます:
|
||||
|
||||
```Python
|
||||
images: List[Image]
|
||||
images: list[Image]
|
||||
```
|
||||
|
||||
以下のように:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial008.py hl[15] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}
|
||||
|
||||
## あらゆる場所でのエディタサポート
|
||||
## あらゆる場所でのエディタサポート { #editor-support-everywhere }
|
||||
|
||||
エディタのサポートもどこでも受けることができます。
|
||||
そして、あらゆる場所でエディタサポートを得られます。
|
||||
|
||||
以下のようにリストの中の項目でも:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/body-nested-models/image01.png">
|
||||
<img src="/img/tutorial/body-nested-models/image01.png">
|
||||
|
||||
Pydanticモデルではなく、`dict`を直接使用している場合はこのようなエディタのサポートは得られません。
|
||||
|
||||
しかし、それらについて心配する必要はありません。入力された辞書は自動的に変換され、出力も自動的にJSONに変換されます。
|
||||
しかし、それらについて心配する必要はありません。入力されたdictは自動的に変換され、出力も自動的にJSONに変換されます。
|
||||
|
||||
## 任意の`dict`のボディ
|
||||
## 任意の`dict`のボディ { #bodies-of-arbitrary-dicts }
|
||||
|
||||
また、ある型のキーと別の型の値を持つ`dict`としてボディを宣言することもできます。
|
||||
|
||||
有効なフィールド・属性名を事前に知る必要がありません(Pydanticモデルの場合のように)。
|
||||
この方法で、有効なフィールド/属性名を事前に知る必要がありません(Pydanticモデルの場合のように)。
|
||||
|
||||
これは、まだ知らないキーを受け取りたいときに便利だと思います。
|
||||
これは、まだ知らないキーを受け取りたいときに便利です。
|
||||
|
||||
---
|
||||
|
||||
他にも、`int`のように他の型のキーを持ちたい場合などに便利です。
|
||||
もうひとつ便利なケースは、別の型(例: `int`)のキーを持ちたい場合です。
|
||||
|
||||
それをここで見ていきましょう。
|
||||
それをここで見ていきます。
|
||||
|
||||
この場合、`int`のキーと`float`の値を持つものであれば、どんな`dict`でも受け入れることができます:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial009.py hl[15] *}
|
||||
{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -218,14 +208,14 @@ JSONはキーとして`str`しかサポートしていないことに注意し
|
||||
|
||||
///
|
||||
|
||||
## まとめ
|
||||
## まとめ { #recap }
|
||||
|
||||
**FastAPI** を使用すると、Pydanticモデルが提供する最大限の柔軟性を持ちながら、コードをシンプルに短く、エレガントに保つことができます。
|
||||
|
||||
以下のような利点があります:
|
||||
しかし、以下のような利点があります:
|
||||
|
||||
* エディタのサポート(どこでも補完!)
|
||||
* データ変換(別名:構文解析・シリアライズ)
|
||||
* データ変換(別名:構文解析 / シリアライズ)
|
||||
* データの検証
|
||||
* スキーマ文書
|
||||
* 自動文書化
|
||||
* 自動ドキュメント
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# ボディ - 更新
|
||||
# ボディ - 更新 { #body-updates }
|
||||
|
||||
## `PUT`による置換での更新
|
||||
## `PUT`による置換での更新 { #update-replacing-with-put }
|
||||
|
||||
項目を更新するには<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTPの`PUT`</a>操作を使用することができます。
|
||||
|
||||
`jsonable_encoder`を用いて、入力データをJSON形式で保存できるデータに変換することができます(例:NoSQLデータベース)。例えば、`datetime`を`str`に変換します。
|
||||
`jsonable_encoder`を用いて、入力データをJSONとして保存できるデータに変換することができます(例:NoSQLデータベース)。例えば、`datetime`を`str`に変換します。
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial001.py hl[30,31,32,33,34,35] *}
|
||||
{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
|
||||
|
||||
既存のデータを置き換えるべきデータを受け取るために`PUT`は使用されます。
|
||||
`PUT`は、既存のデータを置き換えるべきデータを受け取るために使用されます。
|
||||
|
||||
### 置換についての注意
|
||||
### 置換についての注意 { #warning-about-replacing }
|
||||
|
||||
つまり、`PUT`を使用して以下のボディで項目`bar`を更新したい場合は:
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
}
|
||||
```
|
||||
|
||||
すでに格納されている属性`"tax": 20.2`を含まないため、入力モデルのデフォルト値は`"tax": 10.5`です。
|
||||
すでに格納されている属性`"tax": 20.2`を含まないため、入力モデルは`"tax": 10.5`のデフォルト値を取ります。
|
||||
|
||||
そして、データはその「新しい」`10.5`の`tax`と共に保存されます。
|
||||
|
||||
## `PATCH`による部分的な更新
|
||||
## `PATCH`による部分的な更新 { #partial-updates-with-patch }
|
||||
|
||||
また、<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTPの`PATCH`</a>操作でデータを*部分的に*更新することもできます。
|
||||
|
||||
@@ -44,42 +44,42 @@
|
||||
|
||||
///
|
||||
|
||||
### Pydanticの`exclude_unset`パラメータの使用
|
||||
### Pydanticの`exclude_unset`パラメータの使用 { #using-pydantics-exclude-unset-parameter }
|
||||
|
||||
部分的な更新を受け取りたい場合は、Pydanticモデルの`.dict()`の`exclude_unset`パラメータを使用すると非常に便利です。
|
||||
部分的な更新を受け取りたい場合は、Pydanticモデルの`.model_dump()`の`exclude_unset`パラメータを使用すると非常に便利です。
|
||||
|
||||
`item.dict(exclude_unset=True)`のように。
|
||||
`item.model_dump(exclude_unset=True)`のように。
|
||||
|
||||
これにより、`item`モデルの作成時に設定されたデータのみを持つ`dict`が生成され、デフォルト値は除外されます。
|
||||
|
||||
これを使うことで、デフォルト値を省略して、設定された(リクエストで送られた)データのみを含む`dict`を生成することができます:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002.py hl[34] *}
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
|
||||
|
||||
### Pydanticの`update`パラメータ
|
||||
### Pydanticの`update`パラメータの使用 { #using-pydantics-update-parameter }
|
||||
|
||||
ここで、`.copy()`を用いて既存のモデルのコピーを作成し、`update`パラメータに更新するデータを含む`dict`を渡すことができます。
|
||||
ここで、`.model_copy()`を用いて既存のモデルのコピーを作成し、`update`パラメータに更新するデータを含む`dict`を渡すことができます。
|
||||
|
||||
`stored_item_model.copy(update=update_data)`のように:
|
||||
`stored_item_model.model_copy(update=update_data)`のように:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002.py hl[35] *}
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
|
||||
|
||||
### 部分的更新のまとめ
|
||||
### 部分的更新のまとめ { #partial-updates-recap }
|
||||
|
||||
まとめると、部分的な更新を適用するには、次のようにします:
|
||||
|
||||
* (オプションで)`PUT`の代わりに`PATCH`を使用します。
|
||||
* (オプションで)`PATCH`の代わりに`PUT`を使用します。
|
||||
* 保存されているデータを取得します。
|
||||
* そのデータをPydanticモデルにいれます。
|
||||
* 入力モデルからデフォルト値を含まない`dict`を生成します(`exclude_unset`を使用します)。
|
||||
* この方法では、モデル内のデフォルト値ですでに保存されている値を上書きするのではなく、ユーザーが実際に設定した値のみを更新することができます。
|
||||
* 保存されているモデルのコピーを作成し、受け取った部分的な更新で属性を更新します(`update`パラメータを使用します)。
|
||||
* コピーしたモデルをDBに保存できるものに変換します(例えば、`jsonable_encoder`を使用します)。
|
||||
* これはモデルの`.dict()`メソッドを再度利用することに匹敵しますが、値をJSONに変換できるデータ型、例えば`datetime`を`str`に変換します。
|
||||
* これはモデルの`.model_dump()`メソッドを再度利用することに匹敵しますが、値をJSONに変換できるデータ型になるようにし(変換し)、例えば`datetime`を`str`に変換します。
|
||||
* データをDBに保存します。
|
||||
* 更新されたモデルを返します。
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002.py hl[30,31,32,33,34,35,36,37] *}
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
|
||||
@@ -1,40 +1,41 @@
|
||||
# リクエストボディ
|
||||
# リクエストボディ { #request-body }
|
||||
|
||||
クライアント (ブラウザなど) からAPIにデータを送信する必要があるとき、データを **リクエストボディ (request body)** として送ります。
|
||||
クライアント(例えばブラウザ)からAPIにデータを送信する必要がある場合、**リクエストボディ**として送信します。
|
||||
|
||||
**リクエスト** ボディはクライアントによってAPIへ送られます。**レスポンス** ボディはAPIがクライアントに送るデータです。
|
||||
**リクエスト**ボディは、クライアントからAPIへ送信されるデータです。**レスポンス**ボディは、APIがクライアントに送信するデータです。
|
||||
|
||||
APIはほとんどの場合 **レスポンス** ボディを送らなければなりません。しかし、クライアントは必ずしも **リクエスト** ボディを送らなければいけないわけではありません。
|
||||
APIはほとんどの場合 **レスポンス** ボディを送信する必要があります。しかしクライアントは、常に **リクエストボディ** を送信する必要があるとは限りません。場合によっては、クエリパラメータ付きのパスだけをリクエストして、ボディを送信しないこともあります。
|
||||
|
||||
**リクエスト** ボディを宣言するために <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> モデルを使用します。そして、その全てのパワーとメリットを利用します。
|
||||
**リクエスト**ボディを宣言するには、<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> モデルを使用し、その強力な機能とメリットをすべて利用します。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
データを送るには、`POST` (もっともよく使われる)、`PUT`、`DELETE` または `PATCH` を使うべきです。
|
||||
データを送信するには、`POST`(より一般的)、`PUT`、`DELETE`、`PATCH` のいずれかを使用すべきです。
|
||||
|
||||
GET リクエストでボディを送信することは、仕様では未定義の動作ですが、FastAPI でサポートされており、非常に複雑な(極端な)ユースケースにのみ対応しています。
|
||||
`GET` リクエストでボディを送信することは仕様上は未定義の動作ですが、それでもFastAPIではサポートされています。ただし、非常に複雑/極端なユースケースのためだけです。
|
||||
|
||||
非推奨なので、Swagger UIを使った対話型のドキュメントにはGETのボディ情報は表示されません。さらに、中継するプロキシが対応していない可能性があります。
|
||||
推奨されないため、Swagger UIによる対話的ドキュメントでは `GET` 使用時のボディのドキュメントは表示されず、途中のプロキシが対応していない可能性もあります。
|
||||
|
||||
///
|
||||
|
||||
## Pydanticの `BaseModel` をインポート
|
||||
## Pydanticの `BaseModel` をインポート { #import-pydantics-basemodel }
|
||||
|
||||
ます初めに、 `pydantic` から `BaseModel` をインポートする必要があります:
|
||||
まず、`pydantic` から `BaseModel` をインポートする必要があります:
|
||||
|
||||
{* ../../docs_src/body/tutorial001.py hl[4] *}
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
|
||||
|
||||
## データモデルの作成
|
||||
## データモデルの作成 { #create-your-data-model }
|
||||
|
||||
そして、`BaseModel` を継承したクラスとしてデータモデルを宣言します。
|
||||
次に、`BaseModel` を継承するクラスとしてデータモデルを宣言します。
|
||||
|
||||
すべての属性にpython標準の型を使用します:
|
||||
すべての属性に標準のPython型を使用します:
|
||||
|
||||
{* ../../docs_src/body/tutorial001.py hl[7:11] *}
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
|
||||
クエリパラメータの宣言と同様に、モデル属性がデフォルト値をもつとき、必須な属性ではなくなります。それ以外は必須になります。オプショナルな属性にしたい場合は `None` を使用してください。
|
||||
|
||||
例えば、上記のモデルは以下の様なJSON「`オブジェクト`」(もしくはPythonの `dict` ) を宣言しています:
|
||||
クエリパラメータの宣言と同様に、モデル属性がデフォルト値を持つ場合は必須ではありません。そうでなければ必須です。単にオプションにするには `None` を使用してください。
|
||||
|
||||
例えば、上記のモデルは次のようなJSON「`object`」(またはPythonの `dict`)を宣言します:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -45,7 +46,7 @@ GET リクエストでボディを送信することは、仕様では未定義
|
||||
}
|
||||
```
|
||||
|
||||
...`description` と `tax` はオプショナル (デフォルト値は `None`) なので、以下のJSON「`オブジェクト`」も有効です:
|
||||
...`description` と `tax` はオプション(デフォルト値が `None`)なので、このJSON「`object`」も有効です:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -54,109 +55,112 @@ GET リクエストでボディを送信することは、仕様では未定義
|
||||
}
|
||||
```
|
||||
|
||||
## パラメータとして宣言
|
||||
## パラメータとして宣言 { #declare-it-as-a-parameter }
|
||||
|
||||
*パスオペレーション* に加えるために、パスパラメータやクエリパラメータと同じ様に宣言します:
|
||||
*path operation* に追加するには、パスパラメータやクエリパラメータを宣言したのと同じ方法で宣言します:
|
||||
|
||||
{* ../../docs_src/body/tutorial001.py hl[18] *}
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
|
||||
|
||||
...そして、作成したモデル `Item` で型を宣言します。
|
||||
...そして、作成したモデル `Item` を型として宣言します。
|
||||
|
||||
## 結果
|
||||
## 結果 { #results }
|
||||
|
||||
そのPythonの型宣言だけで **FastAPI** は以下のことを行います:
|
||||
そのPythonの型宣言だけで **FastAPI** は以下を行います:
|
||||
|
||||
* リクエストボディをJSONとして読み取ります。
|
||||
* 適当な型に変換します(必要な場合)。
|
||||
* リクエストのボディをJSONとして読み取ります。
|
||||
* 対応する型に変換します(必要な場合)。
|
||||
* データを検証します。
|
||||
* データが無効な場合は、明確なエラーが返され、どこが不正なデータであったかを示します。
|
||||
* 受け取ったデータをパラメータ `item` に変換します。
|
||||
* 関数内で `Item` 型であると宣言したので、すべての属性とその型に対するエディタサポート(補完など)をすべて使用できます。
|
||||
* モデルの<a href="http://json-schema.org" class="external-link" target="_blank">JSONスキーマ</a>定義を生成し、好きな場所で使用することができます。
|
||||
* これらのスキーマは、生成されたOpenAPIスキーマの一部となり、自動ドキュメントの<abbr title = "User Interfaces">UI</abbr>に使用されます。
|
||||
* データが無効な場合は、どこで何が不正なデータだったのかを正確に示す、分かりやすい明確なエラーを返します。
|
||||
* 受け取ったデータをパラメータ `item` に渡します。
|
||||
* 関数内で `Item` 型として宣言したため、すべての属性とその型について、エディタサポート(補完など)も利用できます。
|
||||
* モデル向けの <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> 定義を生成します。プロジェクトにとって意味があるなら、他の場所でも好きなように利用できます。
|
||||
* それらのスキーマは生成されるOpenAPIスキーマの一部となり、自動ドキュメントの <abbr title="User Interfaces - ユーザーインターフェース">UIs</abbr> で使用されます。
|
||||
|
||||
## 自動ドキュメント生成
|
||||
## 自動ドキュメント { #automatic-docs }
|
||||
|
||||
モデルのJSONスキーマはOpenAPIで生成されたスキーマの一部になり、対話的なAPIドキュメントに表示されます:
|
||||
モデルのJSON Schemaは、OpenAPIで生成されたスキーマの一部になり、対話的なAPIドキュメントに表示されます:
|
||||
|
||||
<img src="/img/tutorial/body/image01.png">
|
||||
|
||||
そして、それらが使われる *パスオペレーション* のそれぞれのAPIドキュメントにも表示されます:
|
||||
また、それらが必要な各 *path operation* 内のAPIドキュメントでも使用されます:
|
||||
|
||||
<img src="/img/tutorial/body/image02.png">
|
||||
|
||||
## エディターサポート
|
||||
## エディタサポート { #editor-support }
|
||||
|
||||
エディターによる型ヒントと補完が関数内で利用できます (Pydanticモデルではなく `dict` を受け取ると、同じサポートは受けられません):
|
||||
エディタ上で、関数内のあらゆる場所で型ヒントと補完が得られます(Pydanticモデルの代わりに `dict` を受け取った場合は起きません):
|
||||
|
||||
<img src="/img/tutorial/body/image03.png">
|
||||
|
||||
型によるエラーチェックも可能です:
|
||||
不正な型操作に対するエラーチェックも得られます:
|
||||
|
||||
<img src="/img/tutorial/body/image04.png">
|
||||
|
||||
これは偶然ではなく、このデザインに基づいてフレームワークが作られています。
|
||||
これは偶然ではなく、フレームワーク全体がその設計を中心に構築されています。
|
||||
|
||||
全てのエディターで機能することを確認するために、実装前の設計時に徹底的にテストしました。
|
||||
そして、すべてのエディタで動作することを確実にするために、実装前の設計フェーズで徹底的にテストされました。
|
||||
|
||||
これをサポートするためにPydantic自体にもいくつかの変更がありました。
|
||||
これをサポートするために、Pydantic自体にもいくつかの変更が加えられました。
|
||||
|
||||
上記のスクリーンショットは<a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>を撮ったものです。
|
||||
前述のスクリーンショットは <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a> で撮影されたものです。
|
||||
|
||||
しかし、<a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>やほとんどのPythonエディタでも同様なエディターサポートを受けられます:
|
||||
ただし、<a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> や、他のほとんどのPythonエディタでも同じエディタサポートを得られます:
|
||||
|
||||
<img src="/img/tutorial/body/image05.png">
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
<a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>エディタを使用している場合は、<a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>が使用可能です。
|
||||
エディタとして <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> を使用している場合、<a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a> を使用できます。
|
||||
|
||||
以下のエディターサポートが強化されます:
|
||||
以下により、Pydanticモデルに対するエディタサポートが改善されます:
|
||||
|
||||
* 自動補完
|
||||
* 型チェック
|
||||
* リファクタリング
|
||||
* 検索
|
||||
* インスペクション
|
||||
* auto-completion
|
||||
* type checks
|
||||
* refactoring
|
||||
* searching
|
||||
* inspections
|
||||
|
||||
///
|
||||
|
||||
## モデルの使用
|
||||
## モデルを使用する { #use-the-model }
|
||||
|
||||
関数内部で、モデルの全ての属性に直接アクセスできます:
|
||||
関数内では、モデルオブジェクトのすべての属性に直接アクセスできます:
|
||||
|
||||
{* ../../docs_src/body/tutorial002.py hl[21] *}
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
|
||||
## リクエストボディ + パスパラメータ
|
||||
## リクエストボディ + パスパラメータ { #request-body-path-parameters }
|
||||
|
||||
パスパラメータとリクエストボディを同時に宣言できます。
|
||||
|
||||
**FastAPI** はパスパラメータである関数パラメータは**パスから受け取り**、Pydanticモデルによって宣言された関数パラメータは**リクエストボディから受け取る**ということを認識します。
|
||||
**FastAPI** は、パスパラメータに一致する関数パラメータは **パスから取得** し、Pydanticモデルとして宣言された関数パラメータは **リクエストボディから取得** すべきだと認識します。
|
||||
|
||||
{* ../../docs_src/body/tutorial003.py hl[17:18] *}
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
|
||||
## リクエストボディ + パスパラメータ + クエリパラメータ
|
||||
|
||||
また、**ボディ**と**パス**と**クエリ**のパラメータも同時に宣言できます。
|
||||
## リクエストボディ + パス + クエリパラメータ { #request-body-path-query-parameters }
|
||||
|
||||
**FastAPI** はそれぞれを認識し、適切な場所からデータを取得します。
|
||||
**body**、**path**、**query** パラメータもすべて同時に宣言できます。
|
||||
|
||||
{* ../../docs_src/body/tutorial004.py hl[18] *}
|
||||
**FastAPI** はそれぞれを認識し、正しい場所からデータを取得します。
|
||||
|
||||
関数パラメータは以下の様に認識されます:
|
||||
{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
|
||||
|
||||
* パラメータが**パス**で宣言されている場合は、優先的にパスパラメータとして扱われます。
|
||||
* パラメータが**単数型** (`int`、`float`、`str`、`bool` など)の場合は**クエリ**パラメータとして解釈されます。
|
||||
* パラメータが **Pydantic モデル**型で宣言された場合、リクエスト**ボディ**として解釈されます。
|
||||
関数パラメータは以下のように認識されます:
|
||||
|
||||
* パラメータが **path** でも宣言されている場合、パスパラメータとして使用されます。
|
||||
* パラメータが **単数型**(`int`、`float`、`str`、`bool` など)の場合、**query** パラメータとして解釈されます。
|
||||
* パラメータが **Pydanticモデル** の型として宣言されている場合、リクエスト **body** として解釈されます。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
FastAPIは、`= None`があるおかげで、`q`がオプショナルだとわかります。
|
||||
FastAPIは、デフォルト値 `= None` があるため、`q` の値が必須ではないことを認識します。
|
||||
|
||||
`Optional[str]` の`Optional` はFastAPIでは使用されていません(FastAPIは`str`の部分のみ使用します)。しかし、`Optional[str]` はエディタがコードのエラーを見つけるのを助けてくれます。
|
||||
`str | None` は、値が必須ではないことを判断するためにFastAPIでは使用されません。`= None` というデフォルト値があるため、必須ではないことを認識します。
|
||||
|
||||
しかし、型アノテーションを追加すると、エディタがより良いサポートを提供し、エラーを検出できるようになります。
|
||||
|
||||
///
|
||||
|
||||
## Pydanticを使わない方法
|
||||
## Pydanticを使わない方法 { #without-pydantic }
|
||||
|
||||
もしPydanticモデルを使用したくない場合は、**Body**パラメータが利用できます。[Body - Multiple Parameters: Singular values in body](body-multiple-params.md#_2){.internal-link target=_blank}を確認してください。
|
||||
Pydanticモデルを使いたくない場合は、**Body** パラメータも使用できます。[Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank} のドキュメントを参照してください。
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# クッキーパラメータモデル
|
||||
# クッキーパラメータモデル { #cookie-parameter-models }
|
||||
|
||||
もし関連する**複数のクッキー**から成るグループがあるなら、それらを宣言するために、**Pydanticモデル**を作成できます。🍪
|
||||
|
||||
こうすることで、**複数の場所**で**そのPydanticモデルを再利用**でき、バリデーションやメタデータを、すべてのクッキーパラメータに対して一度に宣言できます。😎
|
||||
こうすることで、**複数の場所**で**そのPydanticモデルを再利用**でき、バリデーションやメタデータを、すべてのパラメータに対して一度に宣言できます。😎
|
||||
|
||||
/// note | 備考
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
|
||||
///
|
||||
|
||||
## クッキーにPydanticモデルを使用する
|
||||
## Pydanticモデルを使用したクッキー { #cookies-with-a-pydantic-model }
|
||||
|
||||
必要な複数の**クッキー**パラメータを**Pydanticモデル**で宣言し、さらに、それを `Cookie` として宣言しましょう:
|
||||
必要な複数の**クッキー**パラメータを**Pydanticモデル**で宣言し、さらに、パラメータを `Cookie` として宣言しましょう:
|
||||
|
||||
{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}
|
||||
|
||||
**FastAPI**は、リクエストの**クッキー**から**それぞれのフィールド**のデータを**抽出**し、定義された**Pydanticモデル**を提供します。
|
||||
**FastAPI**は、リクエストで受け取った**クッキー**から**それぞれのフィールド**のデータを**抽出**し、定義したPydanticモデルを提供します。
|
||||
|
||||
## ドキュメントの確認
|
||||
## ドキュメントの確認 { #check-the-docs }
|
||||
|
||||
対話的APIドキュメントUI `/docs` で、定義されているクッキーを確認できます:
|
||||
|
||||
@@ -32,32 +32,31 @@
|
||||
<img src="/img/tutorial/cookie-param-models/image01.png">
|
||||
</div>
|
||||
|
||||
/// info | 備考
|
||||
|
||||
/// info | 情報
|
||||
|
||||
**ブラウザがクッキーを処理し**ていますが、特別な方法で内部的に処理を行っているために、**JavaScript**からは簡単に操作**できない**ことに留意してください。
|
||||
|
||||
**対話的APIドキュメントUI** `/docs` にアクセスすれば、*パスオペレーション*に関するクッキーの**ドキュメンテーション**を確認できます。
|
||||
**APIドキュメントUI** `/docs` にアクセスすれば、*path operation*に関するクッキーの**ドキュメンテーション**を確認できます。
|
||||
|
||||
しかし、たとえ**クッキーデータを入力して**「Execute」をクリックしても、対話的APIドキュメントUIは**JavaScript**で動作しているためクッキーは送信されず、まるで値を入力しなかったかのような**エラー**メッセージが表示されます。
|
||||
しかし、たとえ**データを入力して**「Execute」をクリックしても、ドキュメントUIは**JavaScript**で動作しているためクッキーは送信されず、まるで値を入力しなかったかのような**エラー**メッセージが表示されます。
|
||||
|
||||
///
|
||||
|
||||
## 余分なクッキーを禁止する
|
||||
## 余分なクッキーを禁止する { #forbid-extra-cookies }
|
||||
|
||||
特定の(あまり一般的ではないかもしれない)ケースで、受け付けるクッキーを**制限**する必要があるかもしれません。
|
||||
|
||||
あなたのAPIは独自の <abbr title="念のためですが、これはジョークです。クッキー同意とは関係ありませんが、APIでさえ不適切なクッキーを拒否できるとは愉快ですね。クッキーでも食べてください。🍪 (原文: This is a joke, just in case. It has nothing to do with cookie consents, but it's funny that even the API can now reject the poor cookies. Have a cookie. 🍪)">クッキー同意</abbr> を管理する能力を持っています。 🤪🍪
|
||||
あなたのAPIは独自の <dfn title="念のためですが、これはジョークです。クッキー同意とは関係ありませんが、APIでさえ今やかわいそうなクッキーを拒否できるのは面白いですね。クッキーでもどうぞ。🍪">クッキー同意</dfn> を管理する能力を持っています。 🤪🍪
|
||||
|
||||
Pydanticのモデルの Configuration を利用して、 `extra` フィールドを `forbid` とすることができます。
|
||||
|
||||
{* ../../docs_src/cookie_param_models/tutorial002_an_py39.py hl[10] *}
|
||||
{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}
|
||||
|
||||
もしクライアントが**余分なクッキー**を送ろうとすると、**エラー**レスポンスが返されます。
|
||||
|
||||
<abbr title="これもジョークです。気にしないでください。クッキーのお供にコーヒーでも飲んでください。☕ (原文: This is another joke. Don't pay attention to me. Have some coffee for your cookie. ☕)">どうせAPIに拒否されるのに</abbr>あなたの同意を得ようと精一杯努力する可哀想なクッキーバナーたち... 🍪
|
||||
<dfn title="これもジョークです。気にしないでください。クッキーのお供にコーヒーでもどうぞ。☕">どうせAPIに拒否されるのに</dfn>あなたの同意を得ようと精一杯努力する可哀想なクッキーバナーたち... 🍪
|
||||
|
||||
例えば、クライアントがクッキー `santa_tracker` を `good-list-please` という値で送ろうとすると、`santa_tracker` という <abbr title="サンタはクッキー不足を良しとはしないでしょう。🎅 はい、クッキージョークはもう止めておきます。(原文: Santa disapproves the lack of cookies. 🎅 Okay, no more cookie jokes.)">クッキーが許可されていない</abbr> ことを通知する**エラー**レスポンスが返されます:
|
||||
例えば、クライアントがクッキー `santa_tracker` を `good-list-please` という値で送ろうとすると、`santa_tracker` という <dfn title="サンタはクッキー不足を良しとしません。🎅 はい、クッキージョークはこれでおしまい。">クッキーが許可されていない</dfn> ことを通知する**エラー**レスポンスが返されます:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -72,6 +71,6 @@ Pydanticのモデルの Configuration を利用して、 `extra` フィールド
|
||||
}
|
||||
```
|
||||
|
||||
## まとめ
|
||||
## まとめ { #summary }
|
||||
|
||||
**FastAPI**では、<abbr title="帰ってしまう前に最後のクッキーをどうぞ。🍪 (原文: Have a last cookie before you go. 🍪)">**クッキー**</abbr>を宣言するために、**Pydanticモデル**を使用できます。😎
|
||||
**FastAPI**では、<dfn title="帰る前に最後のクッキーをどうぞ。🍪">**クッキー**</dfn>を宣言するために、**Pydanticモデル**を使用できます。😎
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
# クッキーのパラメータ
|
||||
# クッキーのパラメータ { #cookie-parameters }
|
||||
|
||||
クッキーのパラメータは、`Query`や`Path`のパラメータを定義するのと同じ方法で定義できます。
|
||||
|
||||
## `Cookie`をインポート
|
||||
## `Cookie`をインポート { #import-cookie }
|
||||
|
||||
まず、`Cookie`をインポートします:
|
||||
|
||||
{* ../../docs_src/cookie_params/tutorial001.py hl[3] *}
|
||||
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}
|
||||
|
||||
## `Cookie`のパラメータを宣言
|
||||
## `Cookie`のパラメータを宣言 { #declare-cookie-parameters }
|
||||
|
||||
次に、`Path`や`Query`と同じ構造を使ってクッキーのパラメータを宣言します。
|
||||
|
||||
最初の値がデフォルト値で、追加の検証パラメータや注釈パラメータをすべて渡すことができます:
|
||||
|
||||
{* ../../docs_src/cookie_params/tutorial001.py hl[9] *}
|
||||
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
@@ -30,6 +30,16 @@
|
||||
|
||||
///
|
||||
|
||||
## まとめ
|
||||
/// info | 情報
|
||||
|
||||
クッキーは`Cookie`を使って宣言し、`Query`や`Path`と同じパターンを使用する。
|
||||
**ブラウザがクッキーを**特殊な方法で裏側で扱うため、**JavaScript** から簡単には触れられないことを念頭に置いてください。
|
||||
|
||||
`/docs` の **API docs UI** に移動すると、*path operation* のクッキーに関する **documentation** を確認できます。
|
||||
|
||||
しかし、データを **入力** して「Execute」をクリックしても、docs UI は **JavaScript** で動作するためクッキーは送信されず、値を何も書かなかったかのような **error** メッセージが表示されます。
|
||||
|
||||
///
|
||||
|
||||
## まとめ { #recap }
|
||||
|
||||
クッキーは`Cookie`を使って宣言し、`Query`や`Path`と同じ共通のパターンを使用する。
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# CORS (オリジン間リソース共有)
|
||||
# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }
|
||||
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORSまたは「オリジン間リソース共有」</a> は、ブラウザで実行されているフロントエンドにバックエンドと通信するJavaScriptコードがあり、そのバックエンドがフロントエンドとは異なる「オリジン」にある状況を指します。
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORSまたは「Cross-Origin Resource Sharing」</a> は、ブラウザで実行されているフロントエンドにバックエンドと通信するJavaScriptコードがあり、そのバックエンドがフロントエンドとは異なる「オリジン」にある状況を指します。
|
||||
|
||||
## オリジン
|
||||
## オリジン { #origin }
|
||||
|
||||
オリジンはプロトコル (`http`、`https`) とドメイン (`myapp.com`、`localhost`、`localhost.tiangolo.com`) とポート (`80`、`443`、`8080`) の組み合わせです。
|
||||
|
||||
@@ -14,25 +14,25 @@
|
||||
|
||||
すべて `localhost` であっても、異なるプロトコルやポートを使用するので、異なる「オリジン」です。
|
||||
|
||||
## ステップ
|
||||
## ステップ { #steps }
|
||||
|
||||
そして、ブラウザ上で実行されているフロントエンド (`http://localhost:8080`) があり、そのJavaScriptが `http://localhost` で実行されているバックエンドと通信するとします。(ポートを指定していないので、ブラウザはデフォルトの`80`ポートを使用します)
|
||||
|
||||
次に、ブラウザはHTTPの `OPTIONS` リクエストをバックエンドに送信します。そして、バックエンドがこの異なるオリジン (`http://localhost:8080`) からの通信を許可する適切なヘッダーを送信すると、ブラウザはフロントエンドのJavaScriptにバックエンドへのリクエストを送信させます。
|
||||
次に、ブラウザはHTTPの `OPTIONS` リクエストを `:80` のバックエンドに送信します。そして、バックエンドがこの異なるオリジン (`http://localhost:8080`) からの通信を許可する適切なヘッダーを送信すると、`:8080` のブラウザはフロントエンドのJavaScriptに `:80` のバックエンドへのリクエストを送信させます。
|
||||
|
||||
これを実現するには、バックエンドに「許可されたオリジン」のリストがなければなりません。
|
||||
これを実現するには、`:80` のバックエンドに「許可されたオリジン」のリストがなければなりません。
|
||||
|
||||
この場合、フロントエンドを正しく機能させるには、そのリストに `http://localhost:8080` を含める必要があります。
|
||||
この場合、`:8080` のフロントエンドを正しく機能させるには、そのリストに `http://localhost:8080` を含める必要があります。
|
||||
|
||||
## ワイルドカード
|
||||
## ワイルドカード { #wildcards }
|
||||
|
||||
リストを `"*"` (ワイルドカード) と宣言して、すべてを許可することもできます。
|
||||
リストを `"*"` (「ワイルドカード」) と宣言して、すべてを許可することもできます。
|
||||
|
||||
ただし、Bearer Tokenで使用されるような認証ヘッダーやCookieなどのクレデンシャル情報に関するものを除いて、特定の種類の通信のみが許可されます。
|
||||
ただし、クレデンシャル情報に関するもの、つまりCookie、Bearer Tokenで使用されるようなAuthorizationヘッダーなどを含むものは除外され、特定の種類の通信のみが許可されます。
|
||||
|
||||
したがって、すべてを正しく機能させるために、許可されたオリジンの明示的な指定をお勧めします。
|
||||
|
||||
## `CORSMiddleware` の使用
|
||||
## `CORSMiddleware` の使用 { #use-corsmiddleware }
|
||||
|
||||
**FastAPI** アプリケーションでは `CORSMiddleware` を使用して、CORSに関する設定ができます。
|
||||
|
||||
@@ -42,39 +42,43 @@
|
||||
|
||||
以下も、バックエンドに許可させるかどうか指定できます:
|
||||
|
||||
* クレデンシャル情報 (認証ヘッダー、Cookieなど) 。
|
||||
* クレデンシャル情報 (Authorizationヘッダー、Cookieなど) 。
|
||||
* 特定のHTTPメソッド (`POST`、`PUT`) またはワイルドカード `"*"` を使用してすべて許可。
|
||||
* 特定のHTTPヘッダー、またはワイルドカード `"*"`を使用してすべて許可。
|
||||
|
||||
{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *}
|
||||
{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}
|
||||
|
||||
`CORSMiddleware` 実装のデフォルトのパラメータはCORSに関して制限を与えるものになっているので、ブラウザにドメインを跨いで特定のオリジン、メソッド、またはヘッダーを使用可能にするためには、それらを明示的に有効にする必要があります
|
||||
|
||||
`CORSMiddleware` 実装で使用されるデフォルトのパラメータはデフォルトで制限が厳しいため、ブラウザがクロスドメインのコンテキストでそれらを使用できるようにするには、特定のオリジン、メソッド、またはヘッダーを明示的に有効にする必要があります。
|
||||
|
||||
以下の引数がサポートされています:
|
||||
|
||||
* `allow_origins` - オリジン間リクエストを許可するオリジンのリスト。例えば、`['https://example.org', 'https://www.example.org']`。`['*']`を使用して任意のオリジンを許可できます。
|
||||
* `allow_origin_regex` - オリジン間リクエストを許可するオリジンの正規表現文字列。例えば、`'https://.*\.example\.org'`。
|
||||
* `allow_methods` - オリジン間リクエストで許可するHTTPメソッドのリスト。デフォルトは `['GET']` です。`['*']`を使用してすべての標準メソッドを許可できます。
|
||||
* `allow_headers` - オリジン間リクエストでサポートするHTTPリクエストヘッダーのリスト。デフォルトは `[]` です。`['*']`を使用して、すべてのヘッダーを許可できます。CORSリクエストでは、 `Accept` 、 `Accept-Language` 、 `Content-Language` 、 `Content-Type` ヘッダーが常に許可されます。
|
||||
* `allow_headers` - オリジン間リクエストでサポートするHTTPリクエストヘッダーのリスト。デフォルトは `[]` です。`['*']`を使用して、すべてのヘッダーを許可できます。<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">シンプルなCORSリクエスト</a>では、 `Accept` 、 `Accept-Language` 、 `Content-Language` 、 `Content-Type` ヘッダーが常に許可されます。
|
||||
* `allow_credentials` - オリジン間リクエストでCookieをサポートする必要があることを示します。デフォルトは `False` です。
|
||||
|
||||
`allow_credentials` が `True` に設定されている場合、`allow_origins`、`allow_methods`、`allow_headers` のいずれも `['*']` に設定できません。これらはすべて<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards" class="external-link" rel="noopener" target="_blank">明示的に指定</a>する必要があります。
|
||||
|
||||
* `expose_headers` - ブラウザからアクセスできるようにするレスポンスヘッダーを示します。デフォルトは `[]` です。
|
||||
* `max_age` - ブラウザがCORSレスポンスをキャッシュする最大時間を秒単位で設定します。デフォルトは `600` です。
|
||||
|
||||
このミドルウェアは2種類のHTTPリクエストに応答します...
|
||||
|
||||
### CORSプリフライトリクエスト
|
||||
### CORSプリフライトリクエスト { #cors-preflight-requests }
|
||||
|
||||
これらは、 `Origin` ヘッダーと `Access-Control-Request-Method` ヘッダーを持つ `OPTIONS` リクエストです。
|
||||
|
||||
この場合、ミドルウェアはリクエストを横取りし、適切なCORSヘッダーと共に情報提供のために `200` または `400` のレスポンスを返します。
|
||||
|
||||
### シンプルなリクエスト
|
||||
### シンプルなリクエスト { #simple-requests }
|
||||
|
||||
`Origin` ヘッダーのあるリクエスト。この場合、ミドルウェアは通常どおりリクエストに何もしないですが、レスポンスに適切なCORSヘッダーを加えます。
|
||||
|
||||
## より詳しい情報
|
||||
## より詳しい情報 { #more-info }
|
||||
|
||||
<abbr title="Cross-Origin Resource Sharing (オリジン間リソース共有)">CORS</abbr>についてより詳しい情報は、<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Mozilla CORS documentation</a> を参照して下さい。
|
||||
<abbr title="Cross-Origin Resource Sharing – オリジン間リソース共有">CORS</abbr>についてより詳しい情報は、<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Mozilla CORS documentation</a> を参照して下さい。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# デバッグ
|
||||
# デバッグ { #debugging }
|
||||
|
||||
Visual Studio CodeやPyCharmなどを使用して、エディター上でデバッガーと連携できます。
|
||||
|
||||
## `uvicorn` の実行
|
||||
## `uvicorn` を呼び出す { #call-uvicorn }
|
||||
|
||||
FastAPIアプリケーション上で、`uvicorn` を直接インポートして実行します:
|
||||
|
||||
{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
|
||||
{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}
|
||||
|
||||
### `__name__ == "__main__"` について
|
||||
### `__name__ == "__main__"` について { #about-name-main }
|
||||
|
||||
`__name__ == "__main__"` の主な目的は、ファイルが次のコマンドで呼び出されたときに実行されるコードを用意することです:
|
||||
|
||||
@@ -26,7 +26,7 @@ $ python myapp.py
|
||||
from myapp import app
|
||||
```
|
||||
|
||||
#### より詳しい説明
|
||||
#### より詳しい説明 { #more-details }
|
||||
|
||||
ファイルの名前が `myapp.py` だとします。
|
||||
|
||||
@@ -62,7 +62,7 @@ from myapp import app
|
||||
# Some more code
|
||||
```
|
||||
|
||||
`myapp.py` 内の自動変数には、値が `"__main __"` の変数 `__name__` はありません。
|
||||
その場合、`myapp.py` 内の自動的に作成された変数 `__name__` は、値として `"__main__"` を持ちません。
|
||||
|
||||
したがって、以下の行:
|
||||
|
||||
@@ -78,7 +78,7 @@ from myapp import app
|
||||
|
||||
///
|
||||
|
||||
## デバッガーでコードを実行
|
||||
## デバッガーでコードを実行 { #run-your-code-with-your-debugger }
|
||||
|
||||
コードから直接Uvicornサーバーを実行しているため、デバッガーから直接Pythonプログラム (FastAPIアプリケーション) を呼び出せます。
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# 依存関係としてのクラス
|
||||
# 依存関係としてのクラス { #classes-as-dependencies }
|
||||
|
||||
**依存性注入** システムを深く掘り下げる前に、先ほどの例をアップグレードしてみましょう。
|
||||
|
||||
## 前の例の`dict`
|
||||
## 前の例の`dict` { #a-dict-from-the-previous-example }
|
||||
|
||||
前の例では、依存関係("dependable")から`dict`を返していました:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001.py hl[9] *}
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
|
||||
|
||||
しかし、*path operation関数*のパラメータ`commons`に`dict`が含まれています。
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
もっとうまくやれるはずです...。
|
||||
|
||||
## 依存関係を作るもの
|
||||
## 依存関係を作るもの { #what-makes-a-dependency }
|
||||
|
||||
これまでは、依存関係が関数として宣言されているのを見てきました。
|
||||
|
||||
@@ -38,7 +38,7 @@ something(some_argument, some_keyword_argument="foo")
|
||||
|
||||
これを「呼び出し可能」なものと呼びます。
|
||||
|
||||
## 依存関係としてのクラス
|
||||
## 依存関係としてのクラス { #classes-as-dependencies_1 }
|
||||
|
||||
Pythonのクラスのインスタンスを作成する際に、同じ構文を使用していることに気づくかもしれません。
|
||||
|
||||
@@ -67,48 +67,66 @@ FastAPIが実際にチェックしているのは、それが「呼び出し可
|
||||
|
||||
それは、パラメータが全くない呼び出し可能なものにも適用されます。パラメータのない*path operation関数*と同じように。
|
||||
|
||||
そこで、上で紹介した依存関係の`common_parameters`を`CommonQueryParams`クラスに変更します:
|
||||
そこで、上で紹介した依存関係の"dependable" `common_parameters`を`CommonQueryParams`クラスに変更します:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial002.py hl[11,12,13,14,15] *}
|
||||
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}
|
||||
|
||||
クラスのインスタンスを作成するために使用される`__init__`メソッドに注目してください:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial002.py hl[12] *}
|
||||
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}
|
||||
|
||||
...以前の`common_parameters`と同じパラメータを持っています:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001.py hl[8] *}
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}
|
||||
|
||||
これらのパラメータは **FastAPI** が依存関係を「解決」するために使用するものです。
|
||||
|
||||
どちらの場合も以下を持っています:
|
||||
|
||||
* オプショナルの`q`クエリパラメータ。
|
||||
* `skip`クエリパラメータ、デフォルトは`0`。
|
||||
* `limit`クエリパラメータ、デフォルトは`100`。
|
||||
* `str`であるオプショナルの`q`クエリパラメータ。
|
||||
* デフォルトが`0`である`int`の`skip`クエリパラメータ。
|
||||
* デフォルトが`100`である`int`の`limit`クエリパラメータ。
|
||||
|
||||
どちらの場合も、データは変換され、検証され、OpenAPIスキーマなどで文書化されます。
|
||||
|
||||
## 使用
|
||||
## 使用 { #use-it }
|
||||
|
||||
これで、このクラスを使用して依存関係を宣言することができます。
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial002.py hl[19] *}
|
||||
{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}
|
||||
|
||||
**FastAPI** は`CommonQueryParams`クラスを呼び出します。これにより、そのクラスの「インスタンス」が作成され、インスタンスはパラメータ`commons`として関数に渡されます。
|
||||
|
||||
## 型注釈と`Depends`
|
||||
## 型注釈と`Depends` { #type-annotation-vs-depends }
|
||||
|
||||
上のコードでは`CommonQueryParams`を2回書いていることに注目してください:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
以下にある最後の`CommonQueryParams`:
|
||||
|
||||
```Python
|
||||
... = Depends(CommonQueryParams)
|
||||
... Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
...は、**FastAPI** が依存関係を知るために実際に使用するものです。
|
||||
@@ -119,55 +137,145 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
|
||||
この場合、以下にある最初の`CommonQueryParams`:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, ...
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams ...
|
||||
```
|
||||
|
||||
...は **FastAPI** に対して特別な意味をもちません。FastAPIはデータ変換や検証などには使用しません(それらのためには`= Depends(CommonQueryParams)`を使用しています)。
|
||||
////
|
||||
|
||||
...は **FastAPI** に対して特別な意味をもちません。FastAPIはデータ変換や検証などには使用しません(それらのためには`Depends(CommonQueryParams)`を使用しています)。
|
||||
|
||||
実際には以下のように書けばいいだけです:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[Any, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
以下にあるように:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial003.py hl[19] *}
|
||||
{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}
|
||||
|
||||
しかし、型を宣言することは推奨されています。そうすれば、エディタは`commons`のパラメータとして何が渡されるかを知ることができ、コードの補完や型チェックなどを行うのに役立ちます:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/dependencies/image02.png">
|
||||
<img src="/img/tutorial/dependencies/image02.png">
|
||||
|
||||
## ショートカット
|
||||
## ショートカット { #shortcut }
|
||||
|
||||
しかし、ここでは`CommonQueryParams`を2回書くというコードの繰り返しが発生していることがわかります:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
依存関係が、クラス自体のインスタンスを作成するために**FastAPI**が「呼び出す」*特定の*クラスである場合、**FastAPI** はこれらのケースのショートカットを提供しています。
|
||||
|
||||
それらの具体的なケースについては以下のようにします:
|
||||
|
||||
以下のように書く代わりに:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
...以下のように書きます:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python
|
||||
commons: Annotated[CommonQueryParams, Depends()]
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ 注釈なし
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`バージョンを使用することを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python
|
||||
commons: CommonQueryParams = Depends()
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
パラメータの型として依存関係を宣言し、`Depends()`の中でパラメータを指定せず、`Depends()`をその関数のパラメータの「デフォルト」値(`=`のあとの値)として使用することで、`Depends(CommonQueryParams)`の中でクラス全体を*もう一度*書かなくてもよくなります。
|
||||
|
||||
同じ例では以下のようになります:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial004.py hl[19] *}
|
||||
{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}
|
||||
|
||||
...そして **FastAPI** は何をすべきか知っています。
|
||||
|
||||
|
||||
@@ -1,57 +1,69 @@
|
||||
# path operationデコレータの依存関係
|
||||
# path operation デコレータの依存関係 { #dependencies-in-path-operation-decorators }
|
||||
|
||||
場合によっては*path operation関数*の中で依存関係の戻り値を本当に必要としないこともあります。
|
||||
場合によっては、*path operation 関数*の中で依存関係の戻り値を実際には必要としないことがあります。
|
||||
|
||||
もしくは、依存関係が値を返さない場合もあります。
|
||||
または、依存関係が値を返さない場合もあります。
|
||||
|
||||
しかし、それでも実行・解決する必要があります。
|
||||
しかし、それでも実行・解決される必要があります。
|
||||
|
||||
このような場合、*path operation関数*のパラメータを`Depends`で宣言する代わりに、*path operation decorator*に`dependencies`の`list`を追加することができます。
|
||||
そのような場合、`Depends` で *path operation 関数* のパラメータを宣言する代わりに、*path operation デコレータ*に `dependencies` の `list` を追加できます。
|
||||
|
||||
## *path operationデコレータ*への`dependencies`の追加
|
||||
## *path operation デコレータ*に`dependencies`を追加 { #add-dependencies-to-the-path-operation-decorator }
|
||||
|
||||
*path operationデコレータ*はオプショナルの引数`dependencies`を受け取ります。
|
||||
*path operation デコレータ*はオプション引数`dependencies`を受け取ります。
|
||||
|
||||
それは`Depends()`の`list`であるべきです:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006.py hl[17] *}
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}
|
||||
|
||||
これらの依存関係は、通常の依存関係と同様に実行・解決されます。しかし、それらの値(何かを返す場合)は*path operation関数*には渡されません。
|
||||
これらの依存関係は、通常の依存関係と同様に実行・解決されます。しかし、それらの値(何かを返す場合)は*path operation 関数*には渡されません。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
エディタによっては、未使用の関数パラメータをチェックしてエラーとして表示するものもあります。
|
||||
一部のエディタは、未使用の関数パラメータをチェックしてエラーとして表示します。
|
||||
|
||||
`dependencies`を`path operationデコレータ`で使用することで、エディタやツールのエラーを回避しながら確実に実行することができます。
|
||||
これらの`dependencies`を*path operation デコレータ*で使用することで、エディタ/ツールのエラーを回避しつつ、確実に実行されるようにできます。
|
||||
|
||||
また、コードの未使用のパラメータがあるのを見て、それが不要だと思ってしまうような新しい開発者の混乱を避けるのにも役立つかもしれません。
|
||||
また、コード内の未使用のパラメータを見た新しい開発者が、それを不要だと思って混乱するのを避ける助けにもなるかもしれません。
|
||||
|
||||
///
|
||||
|
||||
## 依存関係のエラーと戻り値
|
||||
/// info | 情報
|
||||
|
||||
通常使用している依存関係の*関数*と同じものを使用することができます。
|
||||
この例では、架空のカスタムヘッダー `X-Key` と `X-Token` を使用しています。
|
||||
|
||||
### 依存関係の要件
|
||||
しかし実際のケースでセキュリティを実装する際は、統合された[Security utilities(次の章)](../security/index.md){.internal-link target=_blank}を使うことで、より多くの利点を得られます。
|
||||
|
||||
これらはリクエストの要件(ヘッダのようなもの)やその他のサブ依存関係を宣言することができます:
|
||||
///
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006.py hl[6,11] *}
|
||||
## 依存関係のエラーと戻り値 { #dependencies-errors-and-return-values }
|
||||
|
||||
### 例外の発生
|
||||
通常使用している依存関係の*関数*と同じものを使用できます。
|
||||
|
||||
これらの依存関係は通常の依存関係と同じように、例外を`raise`発生させることができます:
|
||||
### 依存関係の要件 { #dependency-requirements }
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006.py hl[8,13] *}
|
||||
これらはリクエストの要件(ヘッダーのようなもの)やその他のサブ依存関係を宣言できます:
|
||||
|
||||
### 戻り値
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}
|
||||
|
||||
### 例外の発生 { #raise-exceptions }
|
||||
|
||||
これらの依存関係は、通常の依存関係と同じように例外を`raise`できます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}
|
||||
|
||||
### 戻り値 { #return-values }
|
||||
|
||||
そして、値を返すことも返さないこともできますが、値は使われません。
|
||||
|
||||
つまり、すでにどこかで使っている通常の依存関係(値を返すもの)を再利用することができ、値は使われなくても依存関係は実行されます:
|
||||
つまり、すでにどこかで使っている通常の依存関係(値を返すもの)を再利用でき、値は使われなくても依存関係は実行されます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial006.py hl[9,14] *}
|
||||
{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}
|
||||
|
||||
## *path operations*のグループに対する依存関係
|
||||
## *path operation*のグループに対する依存関係 { #dependencies-for-a-group-of-path-operations }
|
||||
|
||||
後で、より大きなアプリケーションの構造([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank})について読む時に、おそらく複数のファイルを使用して、*path operations*のグループに対して単一の`dependencies`パラメータを宣言する方法を学ぶでしょう。
|
||||
後で、より大きなアプリケーションを(おそらく複数ファイルで)構造化する方法([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank})について読むときに、*path operation*のグループに対して単一の`dependencies`パラメータを宣言する方法を学びます。
|
||||
|
||||
## グローバル依存関係 { #global-dependencies }
|
||||
|
||||
次に、`FastAPI`アプリケーション全体に依存関係を追加して、各*path operation*に適用する方法を見ていきます。
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
# yieldを持つ依存関係
|
||||
# `yield`を持つ依存関係 { #dependencies-with-yield }
|
||||
|
||||
FastAPIは、いくつかの<abbr title='時々"exit"、"cleanup"、"teardown"、"close"、"context managers"、 ...のように呼ばれる'>終了後の追加のステップ</abbr>を行う依存関係をサポートしています。
|
||||
FastAPIは、いくつかの<dfn title="「終了コード」「クリーンアップコード」「ティアダウンコード」「クローズコード」「コンテキストマネージャの終了コード」などと呼ばれることもあります">終了後の追加のステップ</dfn>を行う依存関係をサポートしています。
|
||||
|
||||
これを行うには、`return`の代わりに`yield`を使い、その後に追加のステップを書きます。
|
||||
これを行うには、`return`の代わりに`yield`を使い、その後に追加のステップ(コード)を書きます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`yield`は必ず一度だけ使用するようにしてください。
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
|
||||
これを動作させるには、**Python 3.7** 以上を使用するか、**Python 3.6** では"backports"をインストールする必要があります:
|
||||
|
||||
```
|
||||
pip install async-exit-stack async-generator
|
||||
```
|
||||
|
||||
これにより<a href="https://github.com/sorcio/async_exit_stack" class="external-link" target="_blank">async-exit-stack</a>と<a href="https://github.com/python-trio/async_generator" class="external-link" target="_blank">async-generator</a>がインストールされます。
|
||||
`yield`は必ず依存関係ごとに1回だけ使用するようにしてください。
|
||||
|
||||
///
|
||||
|
||||
@@ -35,21 +23,21 @@ pip install async-exit-stack async-generator
|
||||
|
||||
///
|
||||
|
||||
## `yield`を持つデータベースの依存関係
|
||||
## `yield`を持つデータベースの依存関係 { #a-database-dependency-with-yield }
|
||||
|
||||
例えば、これを使ってデータベースセッションを作成し、終了後にそれを閉じることができます。
|
||||
|
||||
レスポンスを送信する前に`yield`文を含む前のコードのみが実行されます。
|
||||
レスポンスを作成する前に、`yield`文より前のコード(および`yield`文を含む)が実行されます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007.py hl[2,3,4] *}
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}
|
||||
|
||||
生成された値は、*path operations*や他の依存関係に注入されるものです:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007.py hl[4] *}
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}
|
||||
|
||||
`yield`文に続くコードは、レスポンスが送信された後に実行されます:
|
||||
`yield`文に続くコードは、レスポンスの後に実行されます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007.py hl[5,6] *}
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -59,27 +47,27 @@ pip install async-exit-stack async-generator
|
||||
|
||||
///
|
||||
|
||||
## `yield`と`try`を持つ依存関係
|
||||
## `yield`と`try`を持つ依存関係 { #a-dependency-with-yield-and-try }
|
||||
|
||||
`yield`を持つ依存関係で`try`ブロックを使用した場合、その依存関係を使用した際に発生した例外を受け取ることになります。
|
||||
`yield`を持つ依存関係で`try`ブロックを使用した場合、その依存関係を使用した際にスローされたあらゆる例外を受け取ることになります。
|
||||
|
||||
例えば、途中のどこかの時点で、別の依存関係や*path operation*の中で、データベーストランザクションを「ロールバック」したり、その他のエラーを作成したりするコードがあった場合、依存関係の中で例外を受け取ることになります。
|
||||
例えば、途中のどこかの時点で、別の依存関係や*path operation*の中で、データベーストランザクションを「ロールバック」したり、その他の例外を作成したりするコードがあった場合、依存関係の中で例外を受け取ることになります。
|
||||
|
||||
そのため、依存関係の中にある特定の例外を`except SomeException`で探すことができます。
|
||||
|
||||
同様に、`finally`を用いて例外があったかどうかにかかわらず、終了ステップを確実に実行することができます。
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *}
|
||||
{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}
|
||||
|
||||
## `yield`を持つサブ依存関係
|
||||
## `yield`を持つサブ依存関係 { #sub-dependencies-with-yield }
|
||||
|
||||
任意の大きさや形のサブ依存関係やサブ依存関係の「ツリー」を持つことができ、その中で`yield`を使用することができます。
|
||||
|
||||
**FastAPI** は、`yield`を持つ各依存関係の「終了コード」が正しい順番で実行されていることを確認します。
|
||||
|
||||
例えば、`dependency_c`は`dependency_b`と`dependency_b`に依存する`dependency_a`に、依存することができます:
|
||||
例えば、`dependency_c`は`dependency_b`に、そして`dependency_b`は`dependency_a`に依存することができます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008.py hl[4,12,20] *}
|
||||
{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}
|
||||
|
||||
そして、それらはすべて`yield`を使用することができます。
|
||||
|
||||
@@ -87,11 +75,11 @@ pip install async-exit-stack async-generator
|
||||
|
||||
そして、`dependency_b`は`dependency_a`(ここでは`dep_a`という名前)の値を終了コードで利用できるようにする必要があります。
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008.py hl[16,17,24,25] *}
|
||||
{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}
|
||||
|
||||
同様に、`yield`と`return`が混在した依存関係を持つこともできます。
|
||||
同様に、`yield`を持つ依存関係と`return`を持つ他の依存関係をいくつか持ち、それらの一部が他の一部に依存するようにもできます。
|
||||
|
||||
また、単一の依存関係を持っていて、`yield`などの他の依存関係をいくつか必要とすることもできます。
|
||||
また、単一の依存関係を持っていて、`yield`を持つ他の依存関係をいくつか必要とすることもできます。
|
||||
|
||||
依存関係の組み合わせは自由です。
|
||||
|
||||
@@ -105,32 +93,46 @@ pip install async-exit-stack async-generator
|
||||
|
||||
///
|
||||
|
||||
## `yield`と`HTTPException`を持つ依存関係
|
||||
## `yield`と`HTTPException`を持つ依存関係 { #dependencies-with-yield-and-httpexception }
|
||||
|
||||
`yield`と例外をキャッチする`try`ブロックを持つことができる依存関係を使用することができることがわかりました。
|
||||
`yield`を持つ依存関係を使い、何らかのコードを実行し、その後に`finally`の後で終了コードを実行しようとする`try`ブロックを持てることが分かりました。
|
||||
|
||||
`yield`の後の終了コードで`HTTPException`などを発生させたくなるかもしれません。しかし**それはうまくいきません**
|
||||
また、`except`を使って発生した例外をキャッチし、それに対して何かをすることもできます。
|
||||
|
||||
`yield`を持つ依存関係の終了コードは[例外ハンドラ](../handling-errors.md#_4){.internal-link target=_blank}の*後に*実行されます。依存関係によって投げられた例外を終了コード(`yield`の後)でキャッチするものはなにもありません。
|
||||
|
||||
つまり、`yield`の後に`HTTPException`を発生させた場合、`HTTTPException`をキャッチしてHTTP 400のレスポンスを返すデフォルトの(あるいは任意のカスタムの)例外ハンドラは、その例外をキャッチすることができなくなります。
|
||||
|
||||
これは、依存関係に設定されているもの(例えば、DBセッション)を、例えば、バックグラウンドタスクで使用できるようにするものです。
|
||||
|
||||
バックグラウンドタスクはレスポンスが送信された*後*に実行されます。そのため、*すでに送信されている*レスポンスを変更する方法すらないので、`HTTPException`を発生させる方法はありません。
|
||||
|
||||
しかし、バックグラウンドタスクがDBエラーを発生させた場合、少なくとも`yield`で依存関係のセッションをロールバックしたり、きれいに閉じたりすることができ、エラーをログに記録したり、リモートのトラッキングシステムに報告したりすることができます。
|
||||
|
||||
例外が発生する可能性があるコードがある場合は、最も普通の「Python流」なことをして、コードのその部分に`try`ブロックを追加してください。
|
||||
|
||||
レスポンスを返したり、レスポンスを変更したり、`HTTPException`を発生させたりする*前に*処理したいカスタム例外がある場合は、[カスタム例外ハンドラ](../handling-errors.md#_4){.internal-link target=_blank}を作成してください。
|
||||
例えば、`HTTPException`のように別の例外を発生させることができます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`HTTPException`を含む例外は、`yield`の*前*でも発生させることができます。ただし、後ではできません。
|
||||
これはやや高度なテクニックで、ほとんどの場合は本当に必要にはなりません。例えば、*path operation 関数*など、アプリケーションコードの他の場所から(`HTTPException`を含む)例外を発生させられるためです。
|
||||
|
||||
ただし必要であれば使えます。 🤓
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}
|
||||
|
||||
例外をキャッチして、それに基づいてカスタムレスポンスを作成したい場合は、[カスタム例外ハンドラ](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}を作成してください。
|
||||
|
||||
## `yield`と`except`を持つ依存関係 { #dependencies-with-yield-and-except }
|
||||
|
||||
`yield`を持つ依存関係で`except`を使って例外をキャッチし、それを再度raiseしない(または新しい例外をraiseしない)場合、通常のPythonと同じように、FastAPIは例外があったことに気づけません:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}
|
||||
|
||||
この場合、(`HTTPException`やそれに類するものをraiseしていないため)クライアントには適切に*HTTP 500 Internal Server Error*レスポンスが返りますが、サーバーには**ログが一切残らず**、何がエラーだったのかを示す他の手がかりもありません。 😱
|
||||
|
||||
### `yield`と`except`を持つ依存関係では常に`raise`する { #always-raise-in-dependencies-with-yield-and-except }
|
||||
|
||||
`yield`を持つ依存関係で例外をキャッチした場合、別の`HTTPException`などをraiseするのでない限り、**元の例外を再raiseすべきです**。
|
||||
|
||||
`raise`を使うと同じ例外を再raiseできます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}
|
||||
|
||||
これでクライアントは同じ*HTTP 500 Internal Server Error*レスポンスを受け取りますが、サーバーのログにはカスタムの`InternalError`が残ります。 😎
|
||||
|
||||
## `yield`を持つ依存関係の実行 { #execution-of-dependencies-with-yield }
|
||||
|
||||
実行の順序は多かれ少なかれ以下の図のようになります。時間は上から下へと流れていきます。そして、各列はコードを相互作用させたり、実行したりしている部分の一つです。
|
||||
|
||||
```mermaid
|
||||
@@ -142,32 +144,29 @@ participant dep as Dep with yield
|
||||
participant operation as Path Operation
|
||||
participant tasks as Background tasks
|
||||
|
||||
Note over client,tasks: Can raise exception for dependency, handled after response is sent
|
||||
Note over client,operation: Can raise HTTPException and can change the response
|
||||
Note over client,operation: Can raise exceptions, including HTTPException
|
||||
client ->> dep: Start request
|
||||
Note over dep: Run code up to yield
|
||||
opt raise
|
||||
dep -->> handler: Raise HTTPException
|
||||
opt raise Exception
|
||||
dep -->> handler: Raise Exception
|
||||
handler -->> client: HTTP error response
|
||||
dep -->> dep: Raise other exception
|
||||
end
|
||||
dep ->> operation: Run dependency, e.g. DB session
|
||||
opt raise
|
||||
operation -->> handler: Raise HTTPException
|
||||
operation -->> dep: Raise Exception (e.g. HTTPException)
|
||||
opt handle
|
||||
dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception
|
||||
end
|
||||
handler -->> client: HTTP error response
|
||||
operation -->> dep: Raise other exception
|
||||
end
|
||||
|
||||
operation ->> client: Return response to client
|
||||
Note over client,operation: Response is already sent, can't change it anymore
|
||||
opt Tasks
|
||||
operation -->> tasks: Send background tasks
|
||||
end
|
||||
opt Raise other exception
|
||||
tasks -->> dep: Raise other exception
|
||||
end
|
||||
Note over dep: After yield
|
||||
opt Handle other exception
|
||||
dep -->> dep: Handle exception, can't change response. E.g. close DB session.
|
||||
tasks -->> tasks: Handle exceptions in the background task code
|
||||
end
|
||||
```
|
||||
|
||||
@@ -181,15 +180,63 @@ participant tasks as Background tasks
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
この図は`HTTPException`を示していますが、[カスタム例外ハンドラ](../handling-errors.md#_4){.internal-link target=_blank}を作成することで、他の例外を発生させることもできます。そして、その例外は依存関係の終了コードではなく、そのカスタム例外ハンドラによって処理されます。
|
||||
|
||||
しかし例外ハンドラで処理されない例外を発生させた場合は、依存関係の終了コードで処理されます。
|
||||
*path operation 関数*のコードで例外をraiseした場合、`HTTPException`を含め、それはyieldを持つ依存関係に渡されます。ほとんどの場合、その例外が正しく処理されるように、`yield`を持つ依存関係から同じ例外、または新しい例外を再raiseしたくなるでしょう。
|
||||
|
||||
///
|
||||
|
||||
## コンテキストマネージャ
|
||||
## 早期終了と`scope` { #early-exit-and-scope }
|
||||
|
||||
### 「コンテキストマネージャ」とは
|
||||
通常、`yield`を持つ依存関係の終了コードは、クライアントに**レスポンスが送信された後**に実行されます。
|
||||
|
||||
しかし、*path operation 関数*からreturnした後に依存関係を使う必要がないと分かっている場合は、`Depends(scope="function")`を使って、**レスポンスが送信される前**に、*path operation 関数*のreturn後に依存関係を閉じるべきだとFastAPIに伝えられます。
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}
|
||||
|
||||
`Depends()`は、以下のいずれかを取る`scope`パラメータを受け取ります:
|
||||
|
||||
* `"function"`: リクエストを処理する*path operation 関数*の前に依存関係を開始し、*path operation 関数*の終了後に依存関係を終了しますが、クライアントにレスポンスが返される**前**に終了します。つまり、依存関係関数は*path operation 関数*の**周囲**で実行されます。
|
||||
* `"request"`: リクエストを処理する*path operation 関数*の前に依存関係を開始し(`"function"`を使用する場合と同様)、クライアントにレスポンスが返された**後**に終了します。つまり、依存関係関数は**リクエスト**とレスポンスのサイクルの**周囲**で実行されます。
|
||||
|
||||
指定されておらず、依存関係に`yield`がある場合、デフォルトで`scope`は`"request"`になります。
|
||||
|
||||
### サブ依存関係の`scope` { #scope-for-sub-dependencies }
|
||||
|
||||
`scope="request"`(デフォルト)を持つ依存関係を宣言する場合、どのサブ依存関係も`"request"`の`scope`を持つ必要があります。
|
||||
|
||||
しかし、`"function"`の`scope`を持つ依存関係は、`"function"`と`"request"`の`scope`を持つ依存関係を持てます。
|
||||
|
||||
これは、いずれの依存関係も、サブ依存関係より前に終了コードを実行できる必要があるためです(終了コードの実行中にサブ依存関係をまだ使う必要がある可能性があるためです)。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
participant client as Client
|
||||
participant dep_req as Dep scope="request"
|
||||
participant dep_func as Dep scope="function"
|
||||
participant operation as Path Operation
|
||||
|
||||
client ->> dep_req: Start request
|
||||
Note over dep_req: Run code up to yield
|
||||
dep_req ->> dep_func: Pass dependency
|
||||
Note over dep_func: Run code up to yield
|
||||
dep_func ->> operation: Run path operation with dependency
|
||||
operation ->> dep_func: Return from path operation
|
||||
Note over dep_func: Run code after yield
|
||||
Note over dep_func: ✅ Dependency closed
|
||||
dep_func ->> client: Send response to client
|
||||
Note over client: Response sent
|
||||
Note over dep_req: Run code after yield
|
||||
Note over dep_req: ✅ Dependency closed
|
||||
```
|
||||
|
||||
## `yield`、`HTTPException`、`except`、バックグラウンドタスクを持つ依存関係 { #dependencies-with-yield-httpexception-except-and-background-tasks }
|
||||
|
||||
`yield`を持つ依存関係は、さまざまなユースケースをカバーし、いくつかの問題を修正するために、時間とともに進化してきました。
|
||||
|
||||
FastAPIの異なるバージョンで何が変わったのかを知りたい場合は、上級ガイドの[上級の依存関係 - `yield`、`HTTPException`、`except`、バックグラウンドタスクを持つ依存関係](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}で詳しく読めます。
|
||||
## コンテキストマネージャ { #context-managers }
|
||||
|
||||
### 「コンテキストマネージャ」とは { #what-are-context-managers }
|
||||
|
||||
「コンテキストマネージャ」とは、`with`文の中で使用できるPythonオブジェクトのことです。
|
||||
|
||||
@@ -205,9 +252,9 @@ with open("./somefile.txt") as f:
|
||||
|
||||
`with`ブロックが終了すると、例外があったとしてもファイルを確かに閉じます。
|
||||
|
||||
`yield`を依存関係を作成すると、**FastAPI** は内部的にそれをコンテキストマネージャに変換し、他の関連ツールと組み合わせます。
|
||||
`yield`を持つ依存関係を作成すると、**FastAPI** は内部的にそれをコンテキストマネージャに変換し、他の関連ツールと組み合わせます。
|
||||
|
||||
### `yield`を持つ依存関係でのコンテキストマネージャの使用
|
||||
### `yield`を持つ依存関係でのコンテキストマネージャの使用 { #using-context-managers-in-dependencies-with-yield }
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
@@ -221,7 +268,7 @@ Pythonでは、<a href="https://docs.python.org/3/reference/datamodel.html#conte
|
||||
|
||||
また、依存関数の中で`with`や`async with`文を使用することによって`yield`を持つ **FastAPI** の依存関係の中でそれらを使用することができます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial010.py hl[1,2,3,4,5,6,7,8,9,13] *}
|
||||
{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# グローバルな依存関係 { #global-dependencies }
|
||||
|
||||
アプリケーションの種類によっては、アプリ全体に依存関係を追加したい場合があります。
|
||||
|
||||
[`dependencies` を path operation のデコレータに追加](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}できるのと同様に、`FastAPI` アプリケーション自体にも追加できます。
|
||||
|
||||
その場合、アプリケーション内のすべての path operation に適用されます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}
|
||||
|
||||
また、[`dependencies` を path operation のデコレータに追加](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}する節で説明した考え方はすべて引き続き当てはまりますが、この場合はアプリ内のすべての path operation に対して適用されます。
|
||||
|
||||
## path operation のグループに対する依存関係 { #dependencies-for-groups-of-path-operations }
|
||||
|
||||
後で、複数ファイルを含む大規模アプリケーションの構成方法([大規模アプリケーション - 複数ファイル](../../tutorial/bigger-applications.md){.internal-link target=_blank})を読むと、path operation のグループに対して 1 つの `dependencies` パラメータを宣言する方法を学びます。
|
||||
@@ -1,12 +1,12 @@
|
||||
# 依存関係 - 最初のステップ
|
||||
# 依存関係 { #dependencies }
|
||||
|
||||
** FastAPI** は非常に強力でありながら直感的な **<abbr title="コンポーネント、リソース、プロバイダ、サービス、インジェクタブルとしても知られている">依存性注入</abbr>** システムを持っています。
|
||||
**FastAPI** は非常に強力でありながら直感的な **<dfn title="別名: コンポーネント、リソース、プロバイダ、サービス、インジェクタブル">依存性注入</dfn>** システムを持っています。
|
||||
|
||||
それは非常にシンプルに使用できるように設計されており、開発者が他のコンポーネント **FastAPI** と統合するのが非常に簡単になるように設計されています。
|
||||
|
||||
## 「依存性注入」とは
|
||||
## 「Dependency Injection」とは { #what-is-dependency-injection }
|
||||
|
||||
**「依存性注入」** とは、プログラミングにおいて、コード(この場合は、*path operation関数*)が動作したり使用したりするために必要なもの(「依存関係」)を宣言する方法があることを意味します:
|
||||
**「Dependency Injection」** とは、プログラミングにおいて、コード(この場合は、*path operation 関数*)が動作したり使用したりするために必要なもの(「依存関係」)を宣言する方法があることを意味します:
|
||||
|
||||
そして、そのシステム(この場合は、**FastAPI**)は、必要な依存関係をコードに提供するために必要なことは何でも行います(依存関係を「注入」します)。
|
||||
|
||||
@@ -19,27 +19,27 @@
|
||||
|
||||
これらすべてを、コードの繰り返しを最小限に抑えながら行います。
|
||||
|
||||
## 最初のステップ
|
||||
## 最初のステップ { #first-steps }
|
||||
|
||||
非常にシンプルな例を見てみましょう。あまりにもシンプルなので、今のところはあまり参考にならないでしょう。
|
||||
|
||||
しかし、この方法では **依存性注入** システムがどのように機能するかに焦点を当てることができます。
|
||||
しかし、この方法では **Dependency Injection** システムがどのように機能するかに焦点を当てることができます。
|
||||
|
||||
### 依存関係の作成
|
||||
### 依存関係(「dependable」)の作成 { #create-a-dependency-or-dependable }
|
||||
|
||||
まずは依存関係に注目してみましょう。
|
||||
|
||||
以下のように、*path operation関数*と同じパラメータを全て取ることができる関数にすぎません:
|
||||
以下のように、*path operation 関数*と同じパラメータを全て取ることができる関数にすぎません:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001.py hl[8,9] *}
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
|
||||
|
||||
これだけです。
|
||||
|
||||
**2行**。
|
||||
|
||||
そして、それはすべての*path operation関数*が持っているのと同じ形と構造を持っています。
|
||||
そして、それはすべての*path operation 関数*が持っているのと同じ形と構造を持っています。
|
||||
|
||||
「デコレータ」を含まない(`@app.get("/some-path")`を含まない)*path operation関数*と考えることもできます。
|
||||
「デコレータ」を含まない(`@app.get("/some-path")`を含まない)*path operation 関数*と考えることもできます。
|
||||
|
||||
そして何でも返すことができます。
|
||||
|
||||
@@ -51,15 +51,25 @@
|
||||
|
||||
そして、これらの値を含む`dict`を返します。
|
||||
|
||||
### `Depends`のインポート
|
||||
/// info | 情報
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001.py hl[3] *}
|
||||
FastAPI はバージョン 0.95.0 で `Annotated` のサポートを追加し(そして推奨し始めました)。
|
||||
|
||||
### "dependant"での依存関係の宣言
|
||||
古いバージョンを使用している場合、`Annotated` を使おうとするとエラーになります。
|
||||
|
||||
*path operation関数*のパラメータに`Body`や`Query`などを使用するのと同じように、新しいパラメータに`Depends`を使用することができます:
|
||||
`Annotated` を使用する前に、少なくとも 0.95.1 まで [FastAPI のバージョンをアップグレード](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} してください。
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001.py hl[13,18] *}
|
||||
///
|
||||
|
||||
### `Depends`のインポート { #import-depends }
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
|
||||
|
||||
### 「dependant」での依存関係の宣言 { #declare-the-dependency-in-the-dependant }
|
||||
|
||||
*path operation 関数*のパラメータに`Body`や`Query`などを使用するのと同じように、新しいパラメータに`Depends`を使用することができます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
|
||||
|
||||
関数のパラメータに`Depends`を使用するのは`Body`や`Query`などと同じですが、`Depends`の動作は少し異なります。
|
||||
|
||||
@@ -67,7 +77,9 @@
|
||||
|
||||
このパラメータは関数のようなものである必要があります。
|
||||
|
||||
そして、その関数は、*path operation関数*が行うのと同じ方法でパラメータを取ります。
|
||||
直接**呼び出しません**(末尾に括弧を付けません)。`Depends()` のパラメータとして渡すだけです。
|
||||
|
||||
そして、その関数は、*path operation 関数*が行うのと同じ方法でパラメータを取ります。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -79,7 +91,7 @@
|
||||
|
||||
* 依存関係("dependable")関数を正しいパラメータで呼び出します。
|
||||
* 関数の結果を取得します。
|
||||
* *path operation関数*のパラメータにその結果を代入してください。
|
||||
* *path operation 関数*のパラメータにその結果を代入してください。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
@@ -92,7 +104,7 @@ common_parameters --> read_items
|
||||
common_parameters --> read_users
|
||||
```
|
||||
|
||||
この方法では、共有されるコードを一度書き、**FastAPI** が*path operations*のための呼び出しを行います。
|
||||
この方法では、共有されるコードを一度書き、**FastAPI** が*path operation*のための呼び出しを行います。
|
||||
|
||||
/// check | 確認
|
||||
|
||||
@@ -102,59 +114,85 @@ common_parameters --> read_users
|
||||
|
||||
///
|
||||
|
||||
## `async`にするかどうか
|
||||
## `Annotated` 依存関係の共有 { #share-annotated-dependencies }
|
||||
|
||||
依存関係は **FastAPI**(*path operation関数*と同じ)からも呼び出されるため、関数を定義する際にも同じルールが適用されます。
|
||||
上の例では、ほんの少し **コードの重複** があることがわかります。
|
||||
|
||||
`common_parameters()` 依存関係を使う必要があるときは、型アノテーションと `Depends()` を含むパラメータ全体を書く必要があります:
|
||||
|
||||
```Python
|
||||
commons: Annotated[dict, Depends(common_parameters)]
|
||||
```
|
||||
|
||||
しかし、`Annotated` を使用しているので、その `Annotated` 値を変数に格納して複数箇所で使えます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
これはただの標準 Python で、「type alias」と呼ばれ、**FastAPI** 固有のものではありません。
|
||||
|
||||
しかし **FastAPI** は `Annotated` を含む Python 標準に基づいているため、このテクニックをコードで使えます。 😎
|
||||
|
||||
///
|
||||
|
||||
依存関係は期待どおりに動作し続け、**一番良い点** は **型情報が保持される** ことです。つまり、エディタは **自動補完**、**インラインエラー** などを提供し続けられます。`mypy` のような他のツールでも同様です。
|
||||
|
||||
これは **大規模なコードベース** で、**同じ依存関係** を **多くの *path operation*** で何度も使う場合に特に役立ちます。
|
||||
|
||||
## `async`にするかどうか { #to-async-or-not-to-async }
|
||||
|
||||
依存関係は **FastAPI**(*path operation 関数*と同じ)からも呼び出されるため、関数を定義する際にも同じルールが適用されます。
|
||||
|
||||
`async def`や通常の`def`を使用することができます。
|
||||
|
||||
また、通常の`def`*path operation関数*の中に`async def`を入れて依存関係を宣言したり、`async def`*path operation関数*の中に`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`についてのセクションを確認してください。
|
||||
わからない場合は、ドキュメントの[Async: *"In a hurry?"*](../../async.md#in-a-hurry){.internal-link target=_blank}の中の`async`と`await`についてのセクションを確認してください。
|
||||
|
||||
///
|
||||
|
||||
## OpenAPIとの統合
|
||||
## OpenAPIとの統合 { #integrated-with-openapi }
|
||||
|
||||
依存関係(およびサブ依存関係)のすべてのリクエスト宣言、検証、および要件は、同じOpenAPIスキーマに統合されます。
|
||||
|
||||
つまり、対話型ドキュメントにはこれらの依存関係から得られる全ての情報も含まれているということです:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/dependencies/image01.png">
|
||||
<img src="/img/tutorial/dependencies/image01.png">
|
||||
|
||||
## 簡単な使い方
|
||||
## 簡単な使い方 { #simple-usage }
|
||||
|
||||
見てみると、*path*と*operation*が一致した時に*path operation関数*が宣言されていて、**FastAPI** が正しいパラメータで関数を呼び出してリクエストからデータを抽出する処理をしています。
|
||||
見てみると、*path*と*operation*が一致した時に*path operation 関数*が宣言されていて、**FastAPI** が正しいパラメータで関数を呼び出してリクエストからデータを抽出する処理をしています。
|
||||
|
||||
実は、すべての(あるいはほとんどの)Webフレームワークは、このように動作します。
|
||||
|
||||
これらの関数を直接呼び出すことはありません。これらの関数はフレームワーク(この場合は、**FastAPI**)によって呼び出されます。
|
||||
|
||||
依存性注入システムでは、**FastAPI** に*path operation*もまた、*path operation関数*の前に実行されるべき他の何かに「依存」していることを伝えることができ、**FastAPI** がそれを実行し、結果を「注入」することを引き受けます。
|
||||
Dependency Injection システムでは、**FastAPI** に*path operation 関数*もまた、*path operation 関数*の前に実行されるべき他の何かに「依存」していることを伝えることができ、**FastAPI** がそれを実行し、結果を「注入」することを引き受けます。
|
||||
|
||||
他にも、「依存性注入」と同じような考えの一般的な用語があります:
|
||||
他にも、「dependency injection」と同じような考えの一般的な用語があります:
|
||||
|
||||
* リソース
|
||||
* プロバイダ
|
||||
* サービス
|
||||
* インジェクタブル
|
||||
* コンポーネント
|
||||
* resources
|
||||
* providers
|
||||
* services
|
||||
* injectables
|
||||
* components
|
||||
|
||||
## **FastAPI** プラグイン
|
||||
## **FastAPI** プラグイン { #fastapi-plug-ins }
|
||||
|
||||
統合や「プラグイン」は **依存性注入** システムを使って構築することができます。しかし、実際には、**「プラグイン」を作成する必要はありません**。依存関係を使用することで、無限の数の統合やインタラクションを宣言することができ、それが**path operation関数*で利用可能になるからです。
|
||||
統合や「プラグイン」は **Dependency Injection** システムを使って構築することができます。しかし、実際には、**「プラグイン」を作成する必要はありません**。依存関係を使用することで、無限の数の統合やインタラクションを宣言することができ、それが*path operation 関数*で利用可能になるからです。
|
||||
|
||||
依存関係は非常にシンプルで直感的な方法で作成することができ、必要なPythonパッケージをインポートするだけで、*文字通り*数行のコードでAPI関数と統合することができます。
|
||||
|
||||
次の章では、リレーショナルデータベースやNoSQLデータベース、セキュリティなどについて、その例を見ていきます。
|
||||
|
||||
## **FastAPI** 互換性
|
||||
## **FastAPI** 互換性 { #fastapi-compatibility }
|
||||
|
||||
依存性注入システムがシンプルなので、**FastAPI** は以下のようなものと互換性があります:
|
||||
dependency injection システムがシンプルなので、**FastAPI** は以下のようなものと互換性があります:
|
||||
|
||||
* すべてのリレーショナルデータベース
|
||||
* NoSQLデータベース
|
||||
@@ -165,15 +203,15 @@ common_parameters --> read_users
|
||||
* レスポンスデータ注入システム
|
||||
* など。
|
||||
|
||||
## シンプルでパワフル
|
||||
## シンプルでパワフル { #simple-and-powerful }
|
||||
|
||||
階層依存性注入システムは、定義や使用方法が非常にシンプルであるにもかかわらず、非常に強力なものとなっています。
|
||||
階層的な dependency injection システムは、定義や使用方法が非常にシンプルであるにもかかわらず、非常に強力なものとなっています。
|
||||
|
||||
依存関係事態を定義する依存関係を定義することができます。
|
||||
依存関係が、さらに依存関係を定義することもできます。
|
||||
|
||||
最終的には、依存関係の階層ツリーが構築され、**依存性注入**システムが、これらの依存関係(およびそのサブ依存関係)をすべて解決し、各ステップで結果を提供(注入)します。
|
||||
最終的には、依存関係の階層ツリーが構築され、**Dependency Injection**システムが、これらの依存関係(およびそのサブ依存関係)をすべて解決し、各ステップで結果を提供(注入)します。
|
||||
|
||||
例えば、4つのAPIエンドポイント(*path operations*)があるとします:
|
||||
例えば、4つのAPIエンドポイント(*path operation*)があるとします:
|
||||
|
||||
* `/items/public/`
|
||||
* `/items/private/`
|
||||
@@ -205,8 +243,8 @@ admin_user --> activate_user
|
||||
paying_user --> pro_items
|
||||
```
|
||||
|
||||
## **OpenAPI** との統合
|
||||
## **OpenAPI** との統合 { #integrated-with-openapi_1 }
|
||||
|
||||
これら全ての依存関係は、要件を宣言すると同時に、*path operations*にパラメータやバリデーションを追加します。
|
||||
これら全ての依存関係は、要件を宣言すると同時に、*path operation*にパラメータやバリデーションを追加します。
|
||||
|
||||
**FastAPI** はそれをすべてOpenAPIスキーマに追加して、対話型のドキュメントシステムに表示されるようにします。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# サブ依存関係
|
||||
# サブ依存関係 { #sub-dependencies }
|
||||
|
||||
**サブ依存関係** を持つ依存関係を作成することができます。
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
|
||||
**FastAPI** はそれらを解決してくれます。
|
||||
|
||||
### 最初の依存関係「依存可能なもの」
|
||||
## 最初の依存関係「依存可能なもの」 { #first-dependency-dependable }
|
||||
|
||||
以下のような最初の依存関係(「依存可能なもの」)を作成することができます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005.py hl[8,9] *}
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}
|
||||
|
||||
これはオプショナルのクエリパラメータ`q`を`str`として宣言し、それを返すだけです。
|
||||
|
||||
これは非常にシンプルです(あまり便利ではありません)が、サブ依存関係がどのように機能するかに焦点を当てるのに役立ちます。
|
||||
|
||||
### 第二の依存関係 「依存可能なもの」と「依存」
|
||||
## 第二の依存関係 「依存可能なもの」と「依存」 { #second-dependency-dependable-and-dependant }
|
||||
|
||||
そして、別の依存関数(「依存可能なもの」)を作成して、同時にそれ自身の依存関係を宣言することができます(つまりそれ自身も「依存」です):
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005.py hl[13] *}
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}
|
||||
|
||||
宣言されたパラメータに注目してみましょう:
|
||||
|
||||
@@ -29,15 +29,15 @@
|
||||
* また、オプショナルの`last_query`クッキーを`str`として宣言します。
|
||||
* ユーザーがクエリ`q`を提供しなかった場合、クッキーに保存していた最後に使用したクエリを使用します。
|
||||
|
||||
### 依存関係の使用
|
||||
## 依存関係の使用 { #use-the-dependency }
|
||||
|
||||
以下のように依存関係を使用することができます:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005.py hl[21] *}
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
*path operation関数*の中で宣言している依存関係は`query_or_cookie_extractor`の1つだけであることに注意してください。
|
||||
*path operation 関数*の中で宣言している依存関係は`query_or_cookie_extractor`の1つだけであることに注意してください。
|
||||
|
||||
しかし、**FastAPI** は`query_extractor`を最初に解決し、その結果を`query_or_cookie_extractor`を呼び出す時に渡す必要があることを知っています。
|
||||
|
||||
@@ -54,24 +54,43 @@ read_query["/items/"]
|
||||
query_extractor --> query_or_cookie_extractor --> read_query
|
||||
```
|
||||
|
||||
## 同じ依存関係の複数回の使用
|
||||
## 同じ依存関係の複数回の使用 { #using-the-same-dependency-multiple-times }
|
||||
|
||||
依存関係の1つが同じ*path operation*に対して複数回宣言されている場合、例えば、複数の依存関係が共通のサブ依存関係を持っている場合、**FastAPI** はリクエストごとに1回だけそのサブ依存関係を呼び出します。
|
||||
依存関係の1つが同じ*path operation*に対して複数回宣言されている場合、例えば、複数の依存関係が共通のサブ依存関係を持っている場合、**FastAPI** はリクエストごとに1回だけそのサブ依存関係を呼び出します。
|
||||
|
||||
そして、返された値を<abbr title="計算された値・生成された値を保存するユーティリティまたはシステム、再計算する代わりに再利用するためのもの">「キャッシュ」</abbr>に保存し、同じリクエストに対して依存関係を何度も呼び出す代わりに、特定のリクエストでそれを必要とする全ての「依存関係」に渡すことになります。
|
||||
そして、返された値を<dfn title="計算/生成された値を保存し、再計算する代わりに再利用するためのユーティリティ/システム">「キャッシュ」</dfn>に保存し、同じリクエストに対して依存関係を何度も呼び出す代わりに、その特定のリクエストでそれを必要とする全ての「依存」に渡すことになります。
|
||||
|
||||
高度なシナリオでは、「キャッシュされた」値を使うのではなく、同じリクエストの各ステップ(おそらく複数回)で依存関係を呼び出す必要があることがわかっている場合、`Depens`を使用する際に、`use_cache=False`というパラメータを設定することができます。
|
||||
高度なシナリオでは、「キャッシュされた」値を使うのではなく、同じリクエストの各ステップ(おそらく複数回)で依存関係を呼び出す必要があることがわかっている場合、`Depends`を使用する際に、`use_cache=False`というパラメータを設定することができます:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
|
||||
return {"fresh_value": fresh_value}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ 非Annotated
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
可能であれば`Annotated`版を使うことを推奨します。
|
||||
|
||||
///
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
|
||||
return {"fresh_value": fresh_value}
|
||||
```
|
||||
|
||||
## まとめ
|
||||
////
|
||||
|
||||
ここで使われている派手な言葉は別にして、**依存性注入** システムは非常にシンプルです。
|
||||
## まとめ { #recap }
|
||||
|
||||
*path operation関数*と同じように見えるただの関数です。
|
||||
ここで使われている派手な言葉は別にして、**Dependency Injection** システムは非常にシンプルです。
|
||||
|
||||
*path operation 関数*と同じように見えるただの関数です。
|
||||
|
||||
しかし、それでも非常に強力で、任意の深くネストされた依存関係「グラフ」(ツリー)を宣言することができます。
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# JSON互換エンコーダ
|
||||
# JSON互換エンコーダ { #json-compatible-encoder }
|
||||
|
||||
データ型(Pydanticモデルのような)をJSONと互換性のあるもの(`dict`や`list`など)に変更する必要がある場合があります。
|
||||
データ型(Pydanticモデルのような)をJSONと互換性のあるもの(`dict`や`list`など)に変換する必要があるケースがあります。
|
||||
|
||||
例えば、データベースに保存する必要がある場合です。
|
||||
|
||||
そのために、**FastAPI** は`jsonable_encoder()`関数を提供しています。
|
||||
|
||||
## `jsonable_encoder`の使用
|
||||
## `jsonable_encoder`の使用 { #using-the-jsonable-encoder }
|
||||
|
||||
JSON互換のデータのみを受信するデータベース`fake_db`があるとしましょう。
|
||||
|
||||
例えば、`datetime`オブジェクトはJSONと互換性がないので、このデーターベースには受け取られません。
|
||||
例えば、`datetime`オブジェクトはJSONと互換性がないので、受け取られません。
|
||||
|
||||
そのため、`datetime`オブジェクトは<a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">ISO形式</a>のデータを含む`str`に変換されなければなりません。
|
||||
|
||||
@@ -20,7 +20,7 @@ JSON互換のデータのみを受信するデータベース`fake_db`がある
|
||||
|
||||
Pydanticモデルのようなオブジェクトを受け取り、JSON互換版を返します:
|
||||
|
||||
{* ../../docs_src/encoder/tutorial001.py hl[5,22] *}
|
||||
{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}
|
||||
|
||||
この例では、Pydanticモデルを`dict`に、`datetime`を`str`に変換します。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 追加データ型
|
||||
# 追加データ型 { #extra-data-types }
|
||||
|
||||
今までは、以下のような一般的なデータ型を使用してきました:
|
||||
今まで、以下のような一般的なデータ型を使用してきました:
|
||||
|
||||
* `int`
|
||||
* `float`
|
||||
@@ -11,13 +11,13 @@
|
||||
|
||||
そして、今まで見てきたのと同じ機能を持つことになります:
|
||||
|
||||
* 素晴らしいエディタのサポート
|
||||
* 受信したリクエストからのデータ変換
|
||||
* レスポンスデータのデータ変換
|
||||
* データの検証
|
||||
* 自動注釈と文書化
|
||||
* 素晴らしいエディタのサポート。
|
||||
* 受信したリクエストからのデータ変換。
|
||||
* レスポンスデータのデータ変換。
|
||||
* データの検証。
|
||||
* 自動注釈と文書化。
|
||||
|
||||
## 他のデータ型
|
||||
## 他のデータ型 { #other-data-types }
|
||||
|
||||
ここでは、使用できる追加のデータ型のいくつかを紹介します:
|
||||
|
||||
@@ -26,17 +26,17 @@
|
||||
* リクエストとレスポンスでは`str`として表現されます。
|
||||
* `datetime.datetime`:
|
||||
* Pythonの`datetime.datetime`です。
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます: `2008-09-15T15:53:00+05:00`
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます(例: `2008-09-15T15:53:00+05:00`)。
|
||||
* `datetime.date`:
|
||||
* Pythonの`datetime.date`です。
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます: `2008-09-15`
|
||||
* Python `datetime.date`。
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます(例: `2008-09-15`)。
|
||||
* `datetime.time`:
|
||||
* Pythonの`datetime.time`.
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます: `14:23:55.003`
|
||||
* Pythonの`datetime.time`。
|
||||
* リクエストとレスポンスはISO 8601形式の`str`で表現されます(例: `14:23:55.003`)。
|
||||
* `datetime.timedelta`:
|
||||
* Pythonの`datetime.timedelta`です。
|
||||
* リクエストとレスポンスでは合計秒数の`float`で表現されます。
|
||||
* Pydanticでは「ISO 8601 time diff encoding」として表現することも可能です。<a href="https://docs.pydantic.dev/latest/concepts/serialization/" class="external-link" target="_blank">詳細はドキュメントを参照してください</a>。
|
||||
* Pydanticでは「ISO 8601 time diff encoding」として表現することも可能です。<a href="https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers" class="external-link" target="_blank">詳細はドキュメントを参照してください</a>。
|
||||
* `frozenset`:
|
||||
* リクエストとレスポンスでは`set`と同じように扱われます:
|
||||
* リクエストでは、リストが読み込まれ、重複を排除して`set`に変換されます。
|
||||
@@ -45,18 +45,18 @@
|
||||
* `bytes`:
|
||||
* Pythonの標準的な`bytes`です。
|
||||
* リクエストとレスポンスでは`str`として扱われます。
|
||||
* 生成されたスキーマは`str`で`binary`の「フォーマット」持つことを指定します。
|
||||
* 生成されたスキーマは`str`で`binary`の「フォーマット」を持つことを指定します。
|
||||
* `Decimal`:
|
||||
* Pythonの標準的な`Decimal`です。
|
||||
* リクエストやレスポンスでは`float`と同じように扱います。
|
||||
* リクエストとレスポンスでは`float`と同じように扱われます。
|
||||
* Pydanticの全ての有効な型はこちらで確認できます: <a href="https://docs.pydantic.dev/latest/usage/types/types/" class="external-link" target="_blank">Pydantic data types</a>。
|
||||
|
||||
* Pydanticの全ての有効な型はこちらで確認できます: <a href="https://docs.pydantic.dev/latest/concepts/types/" class="external-link" target="_blank">Pydantic data types</a>。
|
||||
## 例
|
||||
## 例 { #example }
|
||||
|
||||
ここでは、上記の型のいくつかを使用したパラメータを持つ*path operation*の例を示します。
|
||||
|
||||
{* ../../docs_src/extra_data_types/tutorial001.py hl[1,2,12:16] *}
|
||||
{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}
|
||||
|
||||
関数内のパラメータは自然なデータ型を持っていることに注意してください。そして、以下のように通常の日付操作を行うことができます:
|
||||
関数内のパラメータは自然なデータ型を持っていることに注意してください。そして、例えば、以下のように通常の日付操作を行うことができます:
|
||||
|
||||
{* ../../docs_src/extra_data_types/tutorial001.py hl[18,19] *}
|
||||
{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# モデル - より詳しく
|
||||
# 追加のモデル { #extra-models }
|
||||
|
||||
先ほどの例に続き、複数の関連モデルを持つことが一般的です。
|
||||
先ほどの例に続き、複数の関連モデルを持つことは一般的です。
|
||||
|
||||
これはユーザーモデルの場合は特にそうです。なぜなら:
|
||||
|
||||
@@ -8,27 +8,27 @@
|
||||
* **出力モデル**はパスワードをもつべきではありません。
|
||||
* **データベースモデル**はおそらくハッシュ化されたパスワードが必要になるでしょう。
|
||||
|
||||
/// danger | 危険
|
||||
/// danger | 警告
|
||||
|
||||
ユーザーの平文のパスワードは絶対に保存しないでください。常に認証に利用可能な「安全なハッシュ」を保存してください。
|
||||
ユーザーの平文のパスワードは絶対に保存しないでください。常に検証できる「安全なハッシュ」を保存してください。
|
||||
|
||||
知らない方は、[セキュリティの章](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}で「パスワードハッシュ」とは何かを学ぶことができます。
|
||||
|
||||
///
|
||||
|
||||
## 複数のモデル
|
||||
## 複数のモデル { #multiple-models }
|
||||
|
||||
ここでは、パスワードフィールドをもつモデルがどのように見えるのか、また、どこで使われるのか、大まかなイメージを紹介します:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial001.py hl[9,11,16,22,24,29:30,33:35,40:41] *}
|
||||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
|
||||
|
||||
### `**user_in.dict()`について
|
||||
### `**user_in.model_dump()` について { #about-user-in-model-dump }
|
||||
|
||||
#### Pydanticの`.dict()`
|
||||
#### Pydanticの`.model_dump()` { #pydantics-model-dump }
|
||||
|
||||
`user_in`は`UserIn`クラスのPydanticモデルです。
|
||||
|
||||
Pydanticモデルには、モデルのデータを含む`dict`を返す`.dict()`メソッドがあります。
|
||||
Pydanticモデルには、モデルのデータを含む`dict`を返す`.model_dump()`メソッドがあります。
|
||||
|
||||
そこで、以下のようなPydanticオブジェクト`user_in`を作成すると:
|
||||
|
||||
@@ -39,7 +39,7 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
|
||||
そして呼び出すと:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
```
|
||||
|
||||
これで変数`user_dict`のデータを持つ`dict`ができました。(これはPydanticモデルのオブジェクトの代わりに`dict`です)。
|
||||
@@ -61,7 +61,7 @@ print(user_dict)
|
||||
}
|
||||
```
|
||||
|
||||
#### `dict`の展開
|
||||
#### `dict`の展開 { #unpacking-a-dict }
|
||||
|
||||
`user_dict`のような`dict`を受け取り、それを`**user_dict`を持つ関数(またはクラス)に渡すと、Pythonはそれを「展開」します。これは`user_dict`のキーと値を直接キー・バリューの引数として渡します。
|
||||
|
||||
@@ -93,31 +93,31 @@ UserInDB(
|
||||
)
|
||||
```
|
||||
|
||||
#### 別のモデルからつくるPydanticモデル
|
||||
#### 別のモデルの内容からつくるPydanticモデル { #a-pydantic-model-from-the-contents-of-another }
|
||||
|
||||
上述の例では`user_in.dict()`から`user_dict`をこのコードのように取得していますが:
|
||||
上述の例では`user_in.model_dump()`から`user_dict`をこのコードのように取得していますが:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
これは以下と同等です:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict())
|
||||
UserInDB(**user_in.model_dump())
|
||||
```
|
||||
|
||||
...なぜなら`user_in.dict()`は`dict`であり、`**`を付与して`UserInDB`を渡してPythonに「展開」させているからです。
|
||||
...なぜなら`user_in.model_dump()`は`dict`であり、`**`を付与して`UserInDB`を渡してPythonに「展開」させているからです。
|
||||
|
||||
そこで、別のPydanticモデルのデータからPydanticモデルを取得します。
|
||||
|
||||
#### `dict`の展開と追加引数
|
||||
#### `dict`の展開と追加キーワード { #unpacking-a-dict-and-extra-keywords }
|
||||
|
||||
そして、追加のキーワード引数`hashed_password=hashed_password`を以下のように追加すると:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict(), hashed_password=hashed_password)
|
||||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
|
||||
```
|
||||
|
||||
...以下のようになります:
|
||||
@@ -134,11 +134,11 @@ UserInDB(
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
サポートしている追加機能は、データの可能な流れをデモするだけであり、もちろん本当のセキュリティを提供しているわけではありません。
|
||||
追加のサポート関数`fake_password_hasher`と`fake_save_user`は、データの可能な流れをデモするだけであり、もちろん本当のセキュリティを提供しているわけではありません。
|
||||
|
||||
///
|
||||
|
||||
## 重複の削減
|
||||
## 重複の削減 { #reduce-duplication }
|
||||
|
||||
コードの重複を減らすことは、**FastAPI**の中核的なアイデアの1つです。
|
||||
|
||||
@@ -152,40 +152,60 @@ UserInDB(
|
||||
|
||||
データの変換、検証、文書化などはすべて通常通りに動作します。
|
||||
|
||||
このようにして、モデル間の違いだけを宣言することができます:
|
||||
このようにして、モデル間の違いだけを宣言することができます(平文の`password`、`hashed_password`、パスワードなし):
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial002.py hl[9,15,16,19,20,23,24] *}
|
||||
{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
|
||||
|
||||
## `Union`または`anyOf`
|
||||
## `Union` または `anyOf` { #union-or-anyof }
|
||||
|
||||
レスポンスを2つの型の`Union`として宣言することができます。
|
||||
レスポンスを2つ以上の型の`Union`として宣言できます。つまり、そのレスポンスはそれらのいずれかになります。
|
||||
|
||||
OpenAPIでは`anyOf`で定義されます。
|
||||
|
||||
そのためには、標準的なPythonの型ヒント<a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>を使用します:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial003.py hl[1,14,15,18,19,20,33] *}
|
||||
/// note | 備考
|
||||
|
||||
## モデルのリスト
|
||||
<a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a>を定義する場合は、最も具体的な型を先に、その後により具体性の低い型を含めてください。以下の例では、より具体的な`PlaneItem`が`Union[PlaneItem, CarItem]`内で`CarItem`より前に来ています。
|
||||
|
||||
同じように、オブジェクトのリストのレスポンスを宣言することができます。
|
||||
///
|
||||
|
||||
そのためには、標準のPythonの`typing.List`を使用する:
|
||||
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial004.py hl[1,20] *}
|
||||
### Python 3.10の`Union` { #union-in-python-3-10 }
|
||||
|
||||
## 任意の`dict`を持つレスポンス
|
||||
この例では、引数`response_model`の値として`Union[PlaneItem, CarItem]`を渡しています。
|
||||
|
||||
**型アノテーション**に書くのではなく、**引数の値**として渡しているため、Python 3.10でも`Union`を使う必要があります。
|
||||
|
||||
型アノテーションであれば、次のように縦棒を使用できました:
|
||||
|
||||
```Python
|
||||
some_variable: PlaneItem | CarItem
|
||||
```
|
||||
|
||||
しかし、これを代入で`response_model=PlaneItem | CarItem`のように書くと、Pythonはそれを型アノテーションとして解釈するのではなく、`PlaneItem`と`CarItem`の間で**無効な操作**を行おうとしてしまうため、エラーになります。
|
||||
|
||||
## モデルのリスト { #list-of-models }
|
||||
|
||||
同じように、オブジェクトのリストのレスポンスを宣言できます。
|
||||
|
||||
そのためには、標準のPythonの`list`を使用します:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}
|
||||
|
||||
## 任意の`dict`によるレスポンス { #response-with-arbitrary-dict }
|
||||
|
||||
また、Pydanticモデルを使用せずに、キーと値の型だけを定義した任意の`dict`を使ってレスポンスを宣言することもできます。
|
||||
|
||||
これは、有効なフィールド・属性名(Pydanticモデルに必要なもの)を事前に知らない場合に便利です。
|
||||
|
||||
この場合、`typing.Dict`を使用することができます:
|
||||
この場合、`dict`を使用できます:
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial005.py hl[1,8] *}
|
||||
{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}
|
||||
|
||||
## まとめ
|
||||
## まとめ { #recap }
|
||||
|
||||
複数のPydanticモデルを使用し、ケースごとに自由に継承します。
|
||||
|
||||
エンティティが異なる「状態」を持たなければならない場合は、エンティティごとに単一のデータモデルを持つ必要はありません。`password` や `password_hash` やパスワードなしなどのいくつかの「状態」をもつユーザー「エンティティ」の場合の様にすれば良いです。
|
||||
エンティティが異なる「状態」を持たなければならない場合は、エンティティごとに単一のデータモデルを持つ必要はありません。`password`、`password_hash`、パスワードなしを含む状態を持つユーザー「エンティティ」の場合と同様です。
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 最初のステップ
|
||||
# 最初のステップ { #first-steps }
|
||||
|
||||
最もシンプルなFastAPIファイルは以下のようになります:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py *}
|
||||
|
||||
これを`main.py`にコピーします。
|
||||
|
||||
@@ -11,27 +11,43 @@
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
<span style="color: green;">INFO</span>: Started reloader process [28720]
|
||||
<span style="color: green;">INFO</span>: Started server process [28722]
|
||||
<span style="color: green;">INFO</span>: Waiting for application startup.
|
||||
<span style="color: green;">INFO</span>: Application startup complete.
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// note | 備考
|
||||
|
||||
`uvicorn main:app`は以下を示します:
|
||||
|
||||
* `main`: `main.py`ファイル (Python "module")。
|
||||
* `app`: `main.py`内部で作られるobject(`app = FastAPI()`のように記述される)。
|
||||
* `--reload`: コードの変更時にサーバーを再起動させる。開発用。
|
||||
|
||||
///
|
||||
|
||||
出力には次のような行があります:
|
||||
|
||||
```hl_lines="4"
|
||||
@@ -40,7 +56,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
|
||||
この行はローカルマシンでアプリが提供されているURLを示しています。
|
||||
|
||||
### チェック
|
||||
### チェック { #check-it }
|
||||
|
||||
ブラウザで<a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>を開きます。
|
||||
|
||||
@@ -50,7 +66,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
### 対話的APIドキュメント
|
||||
### 対話的APIドキュメント { #interactive-api-docs }
|
||||
|
||||
次に、<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>にアクセスします。
|
||||
|
||||
@@ -58,7 +74,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
|
||||

|
||||
|
||||
### 他のAPIドキュメント
|
||||
### 代替APIドキュメント { #alternative-api-docs }
|
||||
|
||||
次に、<a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>にアクセスします。
|
||||
|
||||
@@ -66,31 +82,31 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
|
||||

|
||||
|
||||
### OpenAPI
|
||||
### OpenAPI { #openapi }
|
||||
|
||||
**FastAPI**は、APIを定義するための**OpenAPI**標準規格を使用して、すべてのAPIの「スキーマ」を生成します。
|
||||
|
||||
#### 「スキーマ」
|
||||
#### 「スキーマ」 { #schema }
|
||||
|
||||
「スキーマ」は定義または説明です。実装コードではなく、単なる抽象的な説明です。
|
||||
|
||||
#### API「スキーマ」
|
||||
#### API「スキーマ」 { #api-schema }
|
||||
|
||||
ここでは、<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>はAPIのスキーマ定義の方法を規定する仕様です。
|
||||
|
||||
このスキーマ定義はAPIパス、受け取り可能なパラメータなどが含まれます。
|
||||
|
||||
#### データ「スキーマ」
|
||||
#### データ「スキーマ」 { #data-schema }
|
||||
|
||||
「スキーマ」という用語は、JSONコンテンツなどの一部のデータの形状を指す場合もあります。
|
||||
|
||||
そのような場合、スキーマはJSON属性とそれらが持つデータ型などを意味します。
|
||||
|
||||
#### OpenAPIおよびJSONスキーマ
|
||||
#### OpenAPIおよびJSONスキーマ { #openapi-and-json-schema }
|
||||
|
||||
OpenAPIはAPIのためのAPIスキーマを定義します。そして、そのスキーマは**JSONデータスキーマ**の標準規格に準拠したJSONスキーマを利用するAPIによって送受されるデータの定義(または「スキーマ」)を含んでいます。
|
||||
OpenAPIはAPIのためのAPIスキーマを定義します。そして、そのスキーマは**JSONデータスキーマ**の標準規格である**JSON Schema**を利用するAPIによって送受されるデータの定義(または「スキーマ」)を含んでいます。
|
||||
|
||||
#### `openapi.json`を確認
|
||||
#### `openapi.json`を確認 { #check-the-openapi-json }
|
||||
|
||||
素のOpenAPIスキーマがどのようなものか興味がある場合、FastAPIはすべてのAPIの説明を含むJSON(スキーマ)を自動的に生成します。
|
||||
|
||||
@@ -100,7 +116,7 @@ OpenAPIはAPIのためのAPIスキーマを定義します。そして、その
|
||||
|
||||
```JSON
|
||||
{
|
||||
"openapi": "3.0.2",
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
@@ -119,7 +135,7 @@ OpenAPIはAPIのためのAPIスキーマを定義します。そして、その
|
||||
...
|
||||
```
|
||||
|
||||
#### OpenAPIの目的
|
||||
#### OpenAPIの目的 { #what-is-openapi-for }
|
||||
|
||||
OpenAPIスキーマは、FastAPIに含まれている2つのインタラクティブなドキュメントシステムの動力源です。
|
||||
|
||||
@@ -127,11 +143,47 @@ OpenAPIスキーマは、FastAPIに含まれている2つのインタラクテ
|
||||
|
||||
また、APIと通信するクライアント用のコードを自動的に生成するために使用することもできます。たとえば、フロントエンド、モバイル、またはIoTアプリケーションです。
|
||||
|
||||
## ステップ毎の要約
|
||||
### アプリをデプロイ(任意) { #deploy-your-app-optional }
|
||||
|
||||
### Step 1: `FastAPI`をインポート
|
||||
任意でFastAPIアプリを<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>にデプロイできます。まだなら、待機リストに登録してください。 🚀
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
|
||||
すでに**FastAPI Cloud**アカウントがある場合(待機リストから招待済みの場合😉)、1コマンドでアプリケーションをデプロイできます。
|
||||
|
||||
デプロイする前に、ログインしていることを確認してください:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
その後、アプリをデプロイします:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi deploy
|
||||
|
||||
Deploying to FastAPI Cloud...
|
||||
|
||||
✅ Deployment successful!
|
||||
|
||||
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
以上です!これで、そのURLでアプリにアクセスできます。 ✨
|
||||
|
||||
## ステップ毎の要約 { #recap-step-by-step }
|
||||
|
||||
### Step 1: `FastAPI`をインポート { #step-1-import-fastapi }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}
|
||||
|
||||
`FastAPI`は、APIのすべての機能を提供するPythonクラスです。
|
||||
|
||||
@@ -143,44 +195,16 @@ OpenAPIスキーマは、FastAPIに含まれている2つのインタラクテ
|
||||
|
||||
///
|
||||
|
||||
### Step 2: `FastAPI`の「インスタンス」を生成
|
||||
### Step 2: `FastAPI`の「インスタンス」を生成 { #step-2-create-a-fastapi-instance }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}
|
||||
ここで、`app`変数が`FastAPI`クラスの「インスタンス」になります。
|
||||
|
||||
これが、すべてのAPIを作成するための主要なポイントになります。
|
||||
|
||||
この`app`はコマンドで`uvicorn`が参照するものと同じです:
|
||||
### Step 3: *path operation*を作成 { #step-3-create-a-path-operation }
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
以下のようなアプリを作成したとき:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
|
||||
|
||||
そして、それを`main.py`ファイルに置き、次のように`uvicorn`を呼び出します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:my_awesome_api --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Step 3: *path operation*を作成
|
||||
|
||||
#### パス
|
||||
#### パス { #path }
|
||||
|
||||
ここでの「パス」とは、最初の`/`から始まるURLの最後の部分を指します。
|
||||
|
||||
@@ -204,7 +228,7 @@ https://example.com/items/foo
|
||||
|
||||
APIを構築する際、「パス」は「関心事」と「リソース」を分離するための主要な方法です。
|
||||
|
||||
#### Operation
|
||||
#### Operation { #operation }
|
||||
|
||||
ここでの「オペレーション」とは、HTTPの「メソッド」の1つを指します。
|
||||
|
||||
@@ -239,15 +263,16 @@ APIを構築するときは、通常、これらの特定のHTTPメソッドを
|
||||
|
||||
「**オペレーションズ**」とも呼ぶことにします。
|
||||
|
||||
#### *パスオペレーションデコレータ*を定義
|
||||
#### *path operation デコレータ*を定義 { #define-a-path-operation-decorator }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
|
||||
`@app.get("/")`は直下の関数が下記のリクエストの処理を担当することを**FastAPI**に伝えます:
|
||||
|
||||
* パス `/`
|
||||
* <abbr title="an HTTP GET method"><code>get</code> オペレーション</abbr>
|
||||
* <dfn title="HTTP GET メソッド"><code>get</code> オペレーション</dfn>
|
||||
|
||||
/// info | `@decorator` について
|
||||
/// info | `@decorator` Info
|
||||
|
||||
Pythonにおける`@something`シンタックスはデコレータと呼ばれます。
|
||||
|
||||
@@ -255,9 +280,9 @@ Pythonにおける`@something`シンタックスはデコレータと呼ばれ
|
||||
|
||||
「デコレータ」は直下の関数を受け取り、それを使って何かを行います。
|
||||
|
||||
私たちの場合、このデコレーターは直下の関数が**オペレーション** `get`を使用した**パス**` / `に対応することを**FastAPI** に通知します。
|
||||
私たちの場合、このデコレーターは直下の関数が**オペレーション** `get`を使用した**パス** `/`に対応することを**FastAPI** に通知します。
|
||||
|
||||
これが「*パスオペレーションデコレータ*」です。
|
||||
これが「*path operation デコレータ*」です。
|
||||
|
||||
///
|
||||
|
||||
@@ -286,15 +311,15 @@ Pythonにおける`@something`シンタックスはデコレータと呼ばれ
|
||||
|
||||
///
|
||||
|
||||
### Step 4: **パスオペレーション**を定義
|
||||
### Step 4: **path operation 関数**を定義 { #step-4-define-the-path-operation-function }
|
||||
|
||||
以下は「**パスオペレーション関数**」です:
|
||||
以下は「**path operation 関数**」です:
|
||||
|
||||
* **パス**: は`/`です。
|
||||
* **オペレーション**: は`get`です。
|
||||
* **関数**: 「デコレータ」の直下にある関数 (`@app.get("/")`の直下) です。
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}
|
||||
|
||||
これは、Pythonの関数です。
|
||||
|
||||
@@ -306,28 +331,49 @@ Pythonにおける`@something`シンタックスはデコレータと呼ばれ
|
||||
|
||||
`async def`の代わりに通常の関数として定義することもできます:
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
違いが分からない場合は、[Async: *"急いでいますか?"*](../async.md#_1){.internal-link target=_blank}を確認してください。
|
||||
違いが分からない場合は、[Async: *"急いでいますか?"*](../async.md#in-a-hurry){.internal-link target=_blank}を確認してください。
|
||||
|
||||
///
|
||||
|
||||
### Step 5: コンテンツの返信
|
||||
### Step 5: コンテンツの返信 { #step-5-return-the-content }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}
|
||||
|
||||
`dict`、`list`、`str`、`int`などを返すことができます。
|
||||
`dict`、`list`、`str`、`int`などの単一の値を返すことができます。
|
||||
|
||||
Pydanticモデルを返すこともできます(後で詳しく説明します)。
|
||||
|
||||
JSONに自動的に変換されるオブジェクトやモデルは他にもたくさんあります(ORMなど)。 お気に入りのものを使ってみてください。すでにサポートされている可能性が高いです。
|
||||
|
||||
## まとめ
|
||||
### Step 6: デプロイする { #step-6-deploy-it }
|
||||
|
||||
* `FastAPI`をインポート
|
||||
* `app`インスタンスを生成
|
||||
* **パスオペレーションデコレータ**を記述 (`@app.get("/")`)
|
||||
* **パスオペレーション関数**を定義 (上記の`def root(): ...`のように)
|
||||
* 開発サーバーを起動 (`uvicorn main:app --reload`)
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**に1コマンドでアプリをデプロイします: `fastapi deploy`. 🎉
|
||||
|
||||
#### FastAPI Cloudについて { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>**は、**FastAPI**の作者とそのチームによって開発されています。
|
||||
|
||||
最小限の労力でAPIの**構築**、**デプロイ**、**アクセス**を行うプロセスを合理化します。
|
||||
|
||||
FastAPIでアプリを構築するのと同じ**開発体験**を、クラウドへの**デプロイ**にもたらします。 🎉
|
||||
|
||||
FastAPI Cloudは、*FastAPI and friends*のオープンソースプロジェクトに対する主要スポンサーであり、資金提供元です。 ✨
|
||||
|
||||
#### 他のクラウドプロバイダにデプロイする { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPIはオープンソースで、標準に基づいています。選択した任意のクラウドプロバイダにFastAPIアプリをデプロイできます。
|
||||
|
||||
クラウドプロバイダのガイドに従って、FastAPIアプリをデプロイしてください。 🤓
|
||||
|
||||
## まとめ { #recap }
|
||||
|
||||
* `FastAPI`をインポートします。
|
||||
* `app`インスタンスを生成します。
|
||||
* `@app.get("/")`のようなデコレータを使用して、**path operation デコレータ**を記述します。
|
||||
* **path operation 関数**を定義します。例: `def root(): ...`。
|
||||
* `fastapi dev`コマンドで開発サーバーを起動します。
|
||||
* 任意で`fastapi deploy`を使ってアプリをデプロイします。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# エラーハンドリング
|
||||
# エラーハンドリング { #handling-errors }
|
||||
|
||||
APIを使用しているクライアントにエラーを通知する必要がある状況はたくさんあります。
|
||||
|
||||
@@ -19,15 +19,15 @@ APIを使用しているクライアントにエラーを通知する必要が
|
||||
|
||||
**"404 Not Found"** のエラー(およびジョーク)を覚えていますか?
|
||||
|
||||
## `HTTPException`の使用
|
||||
## `HTTPException`の使用 { #use-httpexception }
|
||||
|
||||
HTTPレスポンスをエラーでクライアントに返すには、`HTTPException`を使用します。
|
||||
|
||||
### `HTTPException`のインポート
|
||||
### `HTTPException`のインポート { #import-httpexception }
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001.py hl[1] *}
|
||||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
|
||||
|
||||
### コード内での`HTTPException`の発生
|
||||
### コード内での`HTTPException`の発生 { #raise-an-httpexception-in-your-code }
|
||||
|
||||
`HTTPException`は通常のPythonの例外であり、APIに関連するデータを追加したものです。
|
||||
|
||||
@@ -39,9 +39,9 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
この例では、クライアントが存在しないIDでアイテムを要求した場合、`404`のステータスコードを持つ例外を発生させます:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001.py hl[11] *}
|
||||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
|
||||
|
||||
### レスポンス結果
|
||||
### レスポンス結果 { #the-resulting-response }
|
||||
|
||||
クライアントが`http://example.com/items/foo`(`item_id` `"foo"`)をリクエストすると、HTTPステータスコードが200で、以下のJSONレスポンスが返されます:
|
||||
|
||||
@@ -69,7 +69,7 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
///
|
||||
|
||||
## カスタムヘッダーの追加
|
||||
## カスタムヘッダーの追加 { #add-custom-headers }
|
||||
|
||||
例えば、いくつかのタイプのセキュリティのために、HTTPエラーにカスタムヘッダを追加できると便利な状況がいくつかあります。
|
||||
|
||||
@@ -77,9 +77,9 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
しかし、高度なシナリオのために必要な場合には、カスタムヘッダーを追加することができます:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial002.py hl[14] *}
|
||||
{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
|
||||
|
||||
## カスタム例外ハンドラのインストール
|
||||
## カスタム例外ハンドラのインストール { #install-custom-exception-handlers }
|
||||
|
||||
カスタム例外ハンドラは<a href="https://www.starlette.dev/exceptions/" class="external-link" target="_blank">Starletteと同じ例外ユーティリティ</a>を使用して追加することができます。
|
||||
|
||||
@@ -89,7 +89,7 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
カスタム例外ハンドラを`@app.exception_handler()`で追加することができます:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial003.py hl[5,6,7,13,14,15,16,17,18,24] *}
|
||||
{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}
|
||||
|
||||
ここで、`/unicorns/yolo`をリクエストすると、*path operation*は`UnicornException`を`raise`します。
|
||||
|
||||
@@ -109,7 +109,7 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
///
|
||||
|
||||
## デフォルトの例外ハンドラのオーバーライド
|
||||
## デフォルトの例外ハンドラのオーバーライド { #override-the-default-exception-handlers }
|
||||
|
||||
**FastAPI** にはいくつかのデフォルトの例外ハンドラがあります。
|
||||
|
||||
@@ -117,7 +117,7 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
これらの例外ハンドラを独自のものでオーバーライドすることができます。
|
||||
|
||||
### リクエスト検証の例外のオーバーライド
|
||||
### リクエスト検証の例外のオーバーライド { #override-request-validation-exceptions }
|
||||
|
||||
リクエストに無効なデータが含まれている場合、**FastAPI** は内部的に`RequestValidationError`を発生させます。
|
||||
|
||||
@@ -125,11 +125,11 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
|
||||
これをオーバーライドするには`RequestValidationError`をインポートして`@app.exception_handler(RequestValidationError)`と一緒に使用して例外ハンドラをデコレートします。
|
||||
|
||||
この例外ハンドラは`Requset`と例外を受け取ります。
|
||||
この例外ハンドラは`Request`と例外を受け取ります。
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial004.py hl[2,14,15,16] *}
|
||||
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
|
||||
|
||||
これで、`/items/foo`にアクセスすると、デフォルトのJSONエラーの代わりに以下が返されます:
|
||||
これで、`/items/foo`にアクセスすると、以下のデフォルトのJSONエラーの代わりに:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -146,39 +146,20 @@ Pythonの例外なので、`return`ではなく、`raise`です。
|
||||
}
|
||||
```
|
||||
|
||||
以下のようなテキスト版を取得します:
|
||||
以下のテキスト版を取得します:
|
||||
|
||||
```
|
||||
1 validation error
|
||||
path -> item_id
|
||||
value is not a valid integer (type=type_error.integer)
|
||||
Validation errors:
|
||||
Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer
|
||||
```
|
||||
|
||||
#### `RequestValidationError`と`ValidationError`
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
これらは今のあなたにとって重要でない場合は省略しても良い技術的な詳細です。
|
||||
|
||||
///
|
||||
|
||||
`RequestValidationError`はPydanticの<a href="https://docs.pydantic.dev/latest/concepts/models/#error-handling" class="external-link" target="_blank">`ValidationError`</a>のサブクラスです。
|
||||
|
||||
**FastAPI** は`response_model`でPydanticモデルを使用していて、データにエラーがあった場合、ログにエラーが表示されるようにこれを使用しています。
|
||||
|
||||
しかし、クライアントやユーザーはそれを見ることはありません。その代わりに、クライアントはHTTPステータスコード`500`の「Internal Server Error」を受け取ります。
|
||||
|
||||
*レスポンス*やコードのどこか(クライアントの*リクエスト*ではなく)にPydanticの`ValidationError`がある場合、それは実際にはコードのバグなのでこのようにすべきです。
|
||||
|
||||
また、あなたがそれを修正している間は、セキュリティの脆弱性が露呈する場合があるため、クライアントやユーザーがエラーに関する内部情報にアクセスできないようにしてください。
|
||||
|
||||
### エラーハンドラ`HTTPException`のオーバーライド
|
||||
### `HTTPException`エラーハンドラのオーバーライド { #override-the-httpexception-error-handler }
|
||||
|
||||
同様に、`HTTPException`ハンドラをオーバーライドすることもできます。
|
||||
|
||||
例えば、これらのエラーに対しては、JSONではなくプレーンテキストを返すようにすることができます:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial004.py hl[3,4,9,10,11,22] *}
|
||||
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
@@ -188,13 +169,21 @@ path -> item_id
|
||||
|
||||
///
|
||||
|
||||
### `RequestValidationError`のボディの使用
|
||||
/// warning | 注意
|
||||
|
||||
`RequestValidationError`には、検証エラーが発生したファイル名と行番号の情報が含まれているため、必要であれば関連情報と一緒にログに表示できます。
|
||||
|
||||
しかし、そのまま文字列に変換して直接その情報を返すと、システムに関する情報が多少漏えいする可能性があります。そのため、ここではコードが各エラーを個別に抽出して表示します。
|
||||
|
||||
///
|
||||
|
||||
### `RequestValidationError`のボディの使用 { #use-the-requestvalidationerror-body }
|
||||
|
||||
`RequestValidationError`には無効なデータを含む`body`が含まれています。
|
||||
|
||||
アプリ開発中に本体のログを取ってデバッグしたり、ユーザーに返したりなどに使用することができます。
|
||||
アプリ開発中にボディのログを取ってデバッグしたり、ユーザーに返したりなどに使用することができます。
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial005.py hl[14] *}
|
||||
{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
|
||||
|
||||
ここで、以下のような無効な項目を送信してみてください:
|
||||
|
||||
@@ -207,7 +196,7 @@ path -> item_id
|
||||
|
||||
受信したボディを含むデータが無効であることを示すレスポンスが表示されます:
|
||||
|
||||
```JSON hl_lines="12 13 14 15"
|
||||
```JSON hl_lines="12-15"
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
@@ -226,36 +215,30 @@ path -> item_id
|
||||
}
|
||||
```
|
||||
|
||||
#### FastAPIの`HTTPException`とStarletteの`HTTPException`
|
||||
#### FastAPIの`HTTPException`とStarletteの`HTTPException` { #fastapis-httpexception-vs-starlettes-httpexception }
|
||||
|
||||
**FastAPI**は独自の`HTTPException`を持っています。
|
||||
|
||||
また、 **FastAPI**のエラークラス`HTTPException`はStarletteのエラークラス`HTTPException`を継承しています。
|
||||
また、 **FastAPI**の`HTTPException`エラークラスはStarletteの`HTTPException`エラークラスを継承しています。
|
||||
|
||||
唯一の違いは、**FastAPI** の`HTTPException`はレスポンスに含まれるヘッダを追加できることです。
|
||||
|
||||
これはOAuth 2.0といくつかのセキュリティユーティリティのために内部的に必要とされ、使用されています。
|
||||
唯一の違いは、**FastAPI** の`HTTPException`は`detail`フィールドにJSONに変換可能な任意のデータを受け付けるのに対し、Starletteの`HTTPException`は文字列のみを受け付けることです。
|
||||
|
||||
そのため、コード内では通常通り **FastAPI** の`HTTPException`を発生させ続けることができます。
|
||||
|
||||
しかし、例外ハンドラを登録する際には、Starletteの`HTTPException`を登録しておく必要があります。
|
||||
しかし、例外ハンドラを登録する際には、Starletteの`HTTPException`に対して登録しておく必要があります。
|
||||
|
||||
これにより、Starletteの内部コードやStarletteの拡張機能やプラグインの一部が`HTTPException`を発生させた場合、ハンドラがそれをキャッチして処理することができるようになります。
|
||||
これにより、Starletteの内部コードやStarletteの拡張機能やプラグインの一部がStarletteの`HTTPException`を発生させた場合、ハンドラがそれをキャッチして処理できるようになります。
|
||||
|
||||
以下の例では、同じコード内で両方の`HTTPException`を使用できるようにするために、Starletteの例外の名前を`StarletteHTTPException`に変更しています:
|
||||
この例では、同じコード内で両方の`HTTPException`を使用できるようにするために、Starletteの例外を`StarletteHTTPException`にリネームしています:
|
||||
|
||||
```Python
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
```
|
||||
|
||||
### **FastAPI** の例外ハンドラの再利用
|
||||
### **FastAPI** の例外ハンドラの再利用 { #reuse-fastapis-exception-handlers }
|
||||
|
||||
また、何らかの方法で例外を使用することもできますが、**FastAPI** から同じデフォルトの例外ハンドラを使用することもできます。
|
||||
**FastAPI** から同じデフォルトの例外ハンドラと一緒に例外を使用したい場合は、`fastapi.exception_handlers`からデフォルトの例外ハンドラをインポートして再利用できます:
|
||||
|
||||
デフォルトの例外ハンドラを`fastapi.exception_handlers`からインポートして再利用することができます:
|
||||
{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial006.py hl[2,3,4,5,15,21] *}
|
||||
|
||||
この例では、非常に表現力のあるメッセージでエラーを`print`しています。
|
||||
|
||||
しかし、例外を使用して、デフォルトの例外ハンドラを再利用することができるということが理解できます。
|
||||
この例では、非常に表現力のあるメッセージでエラーを`print`しているだけですが、要点は理解できるはずです。例外を使用し、その後デフォルトの例外ハンドラを再利用できます。
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# ヘッダーパラメータのモデル { #header-parameter-models }
|
||||
|
||||
関連する**ヘッダーパラメータ**が一式ある場合、それらを宣言するための**Pydantic モデル**を作成できます。
|
||||
|
||||
これにより、モデルを**複数箇所**で**再利用**でき、さらにすべてのパラメータに対するバリデーションやメタデータを一括で宣言できます。😎
|
||||
|
||||
/// note | 備考
|
||||
|
||||
これは FastAPI バージョン `0.115.0` 以降でサポートされています。🤓
|
||||
|
||||
///
|
||||
|
||||
## Pydantic モデルによるヘッダーパラメータ { #header-parameters-with-a-pydantic-model }
|
||||
|
||||
必要な**ヘッダーパラメータ**を**Pydantic モデル**内で宣言し、関数引数ではそのパラメータを `Header` として宣言します:
|
||||
|
||||
{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}
|
||||
|
||||
**FastAPI** はリクエストの**ヘッダー**から**各フィールド**の値を**抽出**し、定義した Pydantic モデルとして渡します。
|
||||
|
||||
## ドキュメントの確認 { #check-the-docs }
|
||||
|
||||
`/docs` のドキュメント UI で必要なヘッダーを確認できます:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/header-param-models/image01.png">
|
||||
</div>
|
||||
|
||||
## 余分なヘッダーを禁止 { #forbid-extra-headers }
|
||||
|
||||
特殊なユースケース(あまり一般的ではありません)では、受け付けるヘッダーを**制限**したい場合があります。
|
||||
|
||||
Pydantic のモデル設定で `extra` フィールドを `forbid` にして禁止できます:
|
||||
|
||||
{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}
|
||||
|
||||
クライアントが**余分なヘッダー**を送信しようとすると、**エラー**レスポンスが返されます。
|
||||
|
||||
例えば、クライアントが値 `plumbus` の `tool` ヘッダーを送ろうとすると、ヘッダーパラメータ `tool` は許可されていない旨の**エラー**レスポンスが返されます:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"type": "extra_forbidden",
|
||||
"loc": ["header", "tool"],
|
||||
"msg": "Extra inputs are not permitted",
|
||||
"input": "plumbus",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## アンダースコア変換の無効化 { #disable-convert-underscores }
|
||||
|
||||
通常のヘッダーパラメータと同様に、パラメータ名にアンダースコアがある場合は**自動的にハイフンに変換**されます。
|
||||
|
||||
例えば、コード上でヘッダーパラメータ `save_data` を定義すると、想定される HTTP ヘッダーは `save-data` となり、ドキュメント上にもそのように表示されます。
|
||||
|
||||
何らかの理由でこの自動変換を無効化する必要がある場合、ヘッダーパラメータ用の Pydantic モデルでも無効化できます。
|
||||
|
||||
{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
`convert_underscores` を `False` に設定する前に、アンダースコアを含むヘッダーの使用を禁止している HTTP プロキシやサーバーがあることに留意してください。
|
||||
|
||||
///
|
||||
|
||||
## まとめ { #summary }
|
||||
|
||||
**Pydantic モデル**を使って **FastAPI** で **ヘッダー**を宣言できます。😎
|
||||
@@ -1,20 +1,20 @@
|
||||
# ヘッダーのパラメータ
|
||||
# ヘッダーのパラメータ { #header-parameters }
|
||||
|
||||
ヘッダーのパラメータは、`Query`や`Path`、`Cookie`のパラメータを定義するのと同じように定義できます。
|
||||
|
||||
## `Header`をインポート
|
||||
## `Header`をインポート { #import-header }
|
||||
|
||||
まず、`Header`をインポートします:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial001.py hl[3] *}
|
||||
{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}
|
||||
|
||||
## `Header`のパラメータの宣言
|
||||
## `Header`のパラメータの宣言 { #declare-header-parameters }
|
||||
|
||||
次に、`Path`や`Query`、`Cookie`と同じ構造を用いてヘッダーのパラメータを宣言します。
|
||||
|
||||
最初の値がデフォルト値で、追加の検証パラメータや注釈パラメータをすべて渡すことができます。
|
||||
デフォルト値に加えて、追加の検証パラメータや注釈パラメータをすべて定義できます:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial001.py hl[9] *}
|
||||
{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
@@ -30,23 +30,23 @@
|
||||
|
||||
///
|
||||
|
||||
## 自動変換
|
||||
## 自動変換 { #automatic-conversion }
|
||||
|
||||
`Header`は`Path`や`Query`、`Cookie`が提供する機能に加え、少しだけ追加の機能を持っています。
|
||||
|
||||
ほとんどの標準ヘッダーは、「マイナス記号」(`-`)としても知られる「ハイフン」で区切られています。
|
||||
ほとんどの標準ヘッダーは、「マイナス記号」(`-`)としても知られる「ハイフン」文字で区切られています。
|
||||
|
||||
しかし、`user-agent`のような変数はPythonでは無効です。
|
||||
|
||||
そのため、デフォルトでは、`Header`はパラメータの文字をアンダースコア(`_`)からハイフン(`-`)に変換して、ヘッダーを抽出して文書化します。
|
||||
そのため、デフォルトでは、`Header`はパラメータ名の文字をアンダースコア(`_`)からハイフン(`-`)に変換して、ヘッダーを抽出して文書化します。
|
||||
|
||||
また、HTTPヘッダは大文字小文字を区別しないので、Pythonの標準スタイル(別名「スネークケース」)で宣言することができます。
|
||||
|
||||
そのため、`User_Agent`などのように最初の文字を大文字にする必要はなく、通常のPythonコードと同じように`user_agent`を使用することができます。
|
||||
|
||||
もしなんらかの理由でアンダースコアからハイフンへの自動変換を無効にする必要がある場合は、`Header`の`convert_underscores`に`False`を設定してください:
|
||||
もしなんらかの理由でアンダースコアからハイフンへの自動変換を無効にする必要がある場合は、`Header`のパラメータ`convert_underscores`を`False`に設定してください:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial002.py hl[9] *}
|
||||
{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
@@ -54,26 +54,26 @@
|
||||
|
||||
///
|
||||
|
||||
## ヘッダーの重複
|
||||
## ヘッダーの重複 { #duplicate-headers }
|
||||
|
||||
受信したヘッダーが重複することがあります。つまり、同じヘッダーで複数の値を持つということです。
|
||||
|
||||
これらの場合、リストの型宣言を使用して定義することができます。
|
||||
これらの場合、型宣言でリストを使用して定義することができます。
|
||||
|
||||
重複したヘッダーのすべての値をPythonの`list`として受け取ることができます。
|
||||
|
||||
例えば、複数回出現する可能性のある`X-Token`のヘッダを定義するには、以下のように書くことができます:
|
||||
|
||||
{* ../../docs_src/header_params/tutorial003.py hl[9] *}
|
||||
{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}
|
||||
|
||||
もし、その*path operation*で通信する場合は、次のように2つのHTTPヘッダーを送信します:
|
||||
その*path operation*と通信する際に、次のように2つのHTTPヘッダーを送信する場合:
|
||||
|
||||
```
|
||||
X-Token: foo
|
||||
X-Token: bar
|
||||
```
|
||||
|
||||
このレスポンスは以下のようになります:
|
||||
レスポンスは以下のようになります:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -84,8 +84,8 @@ X-Token: bar
|
||||
}
|
||||
```
|
||||
|
||||
## まとめ
|
||||
## まとめ { #recap }
|
||||
|
||||
ヘッダーは`Header`で宣言し、`Query`や`Path`、`Cookie`と同じパターンを使用する。
|
||||
ヘッダーは`Header`で宣言し、`Query`や`Path`、`Cookie`と同じ共通パターンを使用します。
|
||||
|
||||
また、変数のアンダースコアを気にする必要はありません。**FastAPI** がそれらの変換をすべて取り持ってくれます。
|
||||
|
||||
@@ -1,83 +1,95 @@
|
||||
# チュートリアル - ユーザーガイド
|
||||
# チュートリアル - ユーザーガイド { #tutorial-user-guide }
|
||||
|
||||
このチュートリアルは**FastAPI**のほぼすべての機能の使い方を段階的に紹介します。
|
||||
このチュートリアルでは、**FastAPI**のほとんどの機能を使う方法を段階的に紹介します。
|
||||
|
||||
各セクションは前のセクションを踏まえた内容になっています。しかし、トピックごとに分割されているので、特定のAPIの要求を満たすようなトピックに直接たどり着けるようになっています。
|
||||
各セクションは前のセクションを踏まえた内容になっています。しかし、トピックごとに分割されているので、特定のAPIのニーズを満たすために、任意の特定のトピックに直接進めるようになっています。
|
||||
|
||||
また、将来的にリファレンスとして機能するように構築されています。
|
||||
また、将来的にリファレンスとして機能するように構築されているので、後で戻ってきて必要なものを正確に確認できます。
|
||||
|
||||
従って、後でこのチュートリアルに戻ってきて必要なものを確認できます。
|
||||
|
||||
## コードを実行する
|
||||
## コードを実行する { #run-the-code }
|
||||
|
||||
すべてのコードブロックをコピーして直接使用できます(実際にテストされたPythonファイルです)。
|
||||
|
||||
いずれかの例を実行するには、コードを `main.py`ファイルにコピーし、` uvicorn`を次のように起動します:
|
||||
いずれかの例を実行するには、コードを `main.py`ファイルにコピーし、次のように `fastapi dev` を起動します:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
<span style="color: green;">INFO</span>: Started reloader process [28720]
|
||||
<span style="color: green;">INFO</span>: Started server process [28722]
|
||||
<span style="color: green;">INFO</span>: Waiting for application startup.
|
||||
<span style="color: green;">INFO</span>: Application startup complete.
|
||||
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
|
||||
<b>fastapi run</b>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
|
||||
<b>[</b><font color="#4E9A06">'/home/user/code/awesomeapp'</font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
コードを記述またはコピーし、編集してローカルで実行することを**強くお勧めします**。
|
||||
コードを記述またはコピーし、編集してローカルで実行することを**強く推奨します**。
|
||||
|
||||
また、エディターで使用することで、書く必要のあるコードの少なさ、すべての型チェック、自動補完などのFastAPIの利点を実感できます。
|
||||
エディターで使用することで、書く必要のあるコードの少なさ、すべての型チェック、自動補完など、FastAPIの利点を本当に実感できます。
|
||||
|
||||
---
|
||||
|
||||
## FastAPIをインストールする
|
||||
## FastAPIをインストールする { #install-fastapi }
|
||||
|
||||
最初のステップは、FastAPIのインストールです。
|
||||
|
||||
チュートリアルのために、すべてのオプションの依存関係と機能をインストールしたいとき:
|
||||
[仮想環境](../virtual-environments.md){.internal-link target=_blank} を作成して有効化し、それから **FastAPIをインストール** してください:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[all]"
|
||||
$ pip install "fastapi[standard]"
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
...これには、コードを実行するサーバーとして使用できる `uvicorn`も含まれます。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
パーツ毎にインストールすることも可能です。
|
||||
`pip install "fastapi[standard]"` でインストールすると、`fastapi-cloud-cli` を含むいくつかのデフォルトのオプション標準依存関係が付属します。これにより、<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> にデプロイできます。
|
||||
|
||||
以下は、アプリケーションを本番環境にデプロイする際に行うであろうものです:
|
||||
これらのオプション依存関係が不要な場合は、代わりに `pip install fastapi` をインストールできます。
|
||||
|
||||
```
|
||||
pip install fastapi
|
||||
```
|
||||
|
||||
また、サーバーとして動作するように`uvicorn` をインストールします:
|
||||
|
||||
```
|
||||
pip install "uvicorn[standard]"
|
||||
```
|
||||
|
||||
そして、使用したい依存関係をそれぞれ同様にインストールします。
|
||||
標準依存関係はインストールしたいが `fastapi-cloud-cli` は不要な場合は、`pip install "fastapi[standard-no-fastapi-cloud-cli]"` でインストールできます。
|
||||
|
||||
///
|
||||
|
||||
## 高度なユーザーガイド
|
||||
## 高度なユーザーガイド { #advanced-user-guide }
|
||||
|
||||
**高度なユーザーガイド**もあり、**チュートリアル - ユーザーガイド**の後で読むことができます。
|
||||
この **チュートリアル - ユーザーガイド** の後で、後から読める **高度なユーザーガイド** もあります。
|
||||
|
||||
**高度なユーザーガイド**は**チュートリアル - ユーザーガイド**に基づいており、同じ概念を使用し、いくつかの追加機能を紹介しています。
|
||||
**高度なユーザーガイド** は本チュートリアルをベースにしており、同じ概念を使用し、いくつかの追加機能を教えます。
|
||||
|
||||
ただし、最初に**チュートリアル - ユーザーガイド**(現在読んでいる内容)をお読みください。
|
||||
ただし、最初に **チュートリアル - ユーザーガイド**(今読んでいる内容)をお読みください。
|
||||
|
||||
**チュートリアル-ユーザーガイド**だけで完全なアプリケーションを構築できるように設計されています。加えて、**高度なユーザーガイド**の中からニーズに応じたアイデアを使用して、様々な拡張が可能です。
|
||||
**チュートリアル - ユーザーガイド** だけで完全なアプリケーションを構築できるように設計されており、その後ニーズに応じて、**高度なユーザーガイド** の追加のアイデアのいくつかを使って、さまざまな方法で拡張できます。
|
||||
|
||||
@@ -1,47 +1,66 @@
|
||||
# メタデータとドキュメントのURL
|
||||
# メタデータとドキュメントのURL { #metadata-and-docs-urls }
|
||||
|
||||
**FastAPI** アプリケーションのいくつかのメタデータの設定をカスタマイズできます。
|
||||
**FastAPI** アプリケーションのいくつかのメタデータ設定をカスタマイズできます。
|
||||
|
||||
## タイトル、説明文、バージョン
|
||||
## APIのメタデータ { #metadata-for-api }
|
||||
|
||||
以下を設定できます:
|
||||
OpenAPI仕様および自動APIドキュメントUIで使用される次のフィールドを設定できます:
|
||||
|
||||
* **タイトル**: OpenAPIおよび自動APIドキュメントUIでAPIのタイトル/名前として使用される。
|
||||
* **説明文**: OpenAPIおよび自動APIドキュメントUIでのAPIの説明文。
|
||||
* **バージョン**: APIのバージョン。例: `v2` または `2.5.0`。
|
||||
*たとえば、以前のバージョンのアプリケーションがあり、OpenAPIも使用している場合に便利です。
|
||||
| パラメータ | 型 | 説明 |
|
||||
|------------|------|-------------|
|
||||
| `title` | `str` | APIのタイトルです。 |
|
||||
| `summary` | `str` | APIの短い要約です。 <small>OpenAPI 3.1.0、FastAPI 0.99.0 以降で利用できます。</small> |
|
||||
| `description` | `str` | APIの短い説明です。Markdownを使用できます。 |
|
||||
| `version` | `string` | APIのバージョンです。これはOpenAPIのバージョンではなく、あなた自身のアプリケーションのバージョンです。たとえば `2.5.0` です。 |
|
||||
| `terms_of_service` | `str` | APIの利用規約へのURLです。指定する場合、URLである必要があります。 |
|
||||
| `contact` | `dict` | 公開されるAPIの連絡先情報です。複数のフィールドを含められます。 <details><summary><code>contact</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>連絡先の個人/組織を識別する名前です。</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>連絡先情報を指すURLです。URL形式である必要があります。</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>連絡先の個人/組織のメールアドレスです。メールアドレス形式である必要があります。</td></tr></tbody></table></details> |
|
||||
| `license_info` | `dict` | 公開されるAPIのライセンス情報です。複数のフィールドを含められます。 <details><summary><code>license_info</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>必須</strong>(<code>license_info</code> が設定されている場合)。APIに使用されるライセンス名です。</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>APIの <a href="https://spdx.org/licenses/" class="external-link" target="_blank">SPDX</a> ライセンス式です。<code>identifier</code> フィールドは <code>url</code> フィールドと同時に指定できません。 <small>OpenAPI 3.1.0、FastAPI 0.99.0 以降で利用できます。</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>APIに使用されるライセンスへのURLです。URL形式である必要があります。</td></tr></tbody></table></details> |
|
||||
|
||||
これらを設定するには、パラメータ `title`、`description`、`version` を使用します:
|
||||
以下のように設定できます:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial001.py hl[4:6] *}
|
||||
{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}
|
||||
|
||||
この設定では、自動APIドキュメントは以下の様になります:
|
||||
/// tip | 豆知識
|
||||
|
||||
`description` フィールドにはMarkdownを書けて、出力ではレンダリングされます。
|
||||
|
||||
///
|
||||
|
||||
この設定では、自動APIドキュメントは以下のようになります:
|
||||
|
||||
<img src="/img/tutorial/metadata/image01.png">
|
||||
|
||||
## タグのためのメタデータ
|
||||
## ライセンス識別子 { #license-identifier }
|
||||
|
||||
さらに、パラメータ `openapi_tags` を使うと、path operations をグループ分けするための複数のタグに関するメタデータを追加できます。
|
||||
OpenAPI 3.1.0 および FastAPI 0.99.0 以降では、`license_info` を `url` の代わりに `identifier` で設定することもできます。
|
||||
|
||||
それぞれのタグ毎にひとつの辞書を含むリストをとります。
|
||||
例:
|
||||
|
||||
それぞれの辞書は以下をもつことができます:
|
||||
{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}
|
||||
|
||||
* `name` (**必須**): *path operations* および `APIRouter` の `tags` パラメーターで使用するのと同じタグ名である `str`。
|
||||
* `description`: タグの簡単な説明文である `str`。 Markdownで記述でき、ドキュメントUIに表示されます。
|
||||
* `externalDocs`: 外部ドキュメントを説明するための `dict`:
|
||||
* `description`: 外部ドキュメントの簡単な説明文である `str`。
|
||||
* `url` (**必須**): 外部ドキュメントのURLである `str`。
|
||||
## タグのメタデータ { #metadata-for-tags }
|
||||
|
||||
### タグのためのメタデータの作成
|
||||
パラメータ `openapi_tags` を使うと、path operation をグループ分けするために使用する各タグに追加のメタデータを追加できます。
|
||||
|
||||
`users` と `items` のタグを使った例でメタデータの追加を試してみましょう。
|
||||
それぞれのタグごとに1つの辞書を含むリストを取ります。
|
||||
|
||||
タグのためのメタデータを作成し、それを `openapi_tags` パラメータに渡します。
|
||||
それぞれの辞書は以下を含められます:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial004.py hl[3:16,18] *}
|
||||
* `name` (**必須**): *path operation* および `APIRouter` の `tags` パラメータで使用するのと同じタグ名の `str`。
|
||||
* `description`: タグの短い説明の `str`。Markdownを含められ、ドキュメントUIに表示されます。
|
||||
* `externalDocs`: 外部ドキュメントを説明する `dict`。以下を含みます:
|
||||
* `description`: 外部ドキュメントの短い説明の `str`。
|
||||
* `url` (**必須**): 外部ドキュメントのURLの `str`。
|
||||
|
||||
説明文 (description) の中で Markdown を使用できることに注意してください。たとえば、「login」は太字 (**login**) で表示され、「fancy」は斜体 (_fancy_) で表示されます。
|
||||
### タグのメタデータの作成 { #create-metadata-for-tags }
|
||||
|
||||
`users` と `items` のタグを使った例で試してみましょう。
|
||||
|
||||
タグのメタデータを作成し、それを `openapi_tags` パラメータに渡します:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}
|
||||
|
||||
説明の中でMarkdownを使用できることに注意してください。たとえば「login」は太字 (**login**) で表示され、「fancy」は斜体 (_fancy_) で表示されます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -49,31 +68,31 @@
|
||||
|
||||
///
|
||||
|
||||
### 自作タグの使用
|
||||
### タグの使用 { #use-your-tags }
|
||||
|
||||
`tags` パラメーターを使用して、それぞれの *path operations* (および `APIRouter`) を異なるタグに割り当てます:
|
||||
*path operation*(および `APIRouter`)の `tags` パラメータを使用して、それらを異なるタグに割り当てます:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial004.py hl[21,26] *}
|
||||
{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
タグのより詳しい説明を知りたい場合は [Path Operation Configuration](path-operation-configuration.md#tags){.internal-link target=_blank} を参照して下さい。
|
||||
タグの詳細は [Path Operation Configuration](path-operation-configuration.md#tags){.internal-link target=_blank} を参照してください。
|
||||
|
||||
///
|
||||
|
||||
### ドキュメントの確認
|
||||
### ドキュメントの確認 { #check-the-docs }
|
||||
|
||||
ここで、ドキュメントを確認すると、追加したメタデータがすべて表示されます:
|
||||
ここでドキュメントを確認すると、追加したメタデータがすべて表示されます:
|
||||
|
||||
<img src="/img/tutorial/metadata/image02.png">
|
||||
|
||||
### タグの順番
|
||||
### タグの順番 { #order-of-tags }
|
||||
|
||||
タグのメタデータ辞書の順序は、ドキュメントUIに表示される順序の定義にもなります。
|
||||
|
||||
たとえば、`users` はアルファベット順では `items` の後に続きます。しかし、リストの最初に `users` のメタデータ辞書を追加したため、ドキュメントUIでは `users` が先に表示されます。
|
||||
たとえば、`users` はアルファベット順では `items` の後に続きますが、リストの最初の辞書としてメタデータを追加したため、それより前に表示されます。
|
||||
|
||||
## OpenAPI URL
|
||||
## OpenAPI URL { #openapi-url }
|
||||
|
||||
デフォルトでは、OpenAPIスキーマは `/openapi.json` で提供されます。
|
||||
|
||||
@@ -81,21 +100,21 @@
|
||||
|
||||
たとえば、`/api/v1/openapi.json` で提供されるように設定するには:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial002.py hl[3] *}
|
||||
{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}
|
||||
|
||||
OpenAPIスキーマを完全に無効にする場合は、`openapi_url=None` を設定できます。これにより、それを使用するドキュメントUIも無効になります。
|
||||
|
||||
## ドキュメントのURL
|
||||
## ドキュメントのURL { #docs-urls }
|
||||
|
||||
以下の2つのドキュメントUIを構築できます:
|
||||
含まれている2つのドキュメントUIを設定できます:
|
||||
|
||||
* **Swagger UI**: `/docs` で提供されます。
|
||||
* URL はパラメータ `docs_url` で設定できます。
|
||||
* `docs_url=None` を設定することで無効にできます。
|
||||
* ReDoc: `/redoc` で提供されます。
|
||||
* URL はパラメータ `redoc_url` で設定できます。
|
||||
* `redoc_url=None` を設定することで無効にできます。
|
||||
* URL はパラメータ `docs_url` で設定できます。
|
||||
* `docs_url=None` を設定することで無効にできます。
|
||||
* **ReDoc**: `/redoc` で提供されます。
|
||||
* URL はパラメータ `redoc_url` で設定できます。
|
||||
* `redoc_url=None` を設定することで無効にできます。
|
||||
|
||||
たとえば、`/documentation` でSwagger UIが提供されるように設定し、ReDocを無効にするには:
|
||||
|
||||
{* ../../docs_src/metadata/tutorial003.py hl[3] *}
|
||||
{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# ミドルウェア
|
||||
# ミドルウェア { #middleware }
|
||||
|
||||
**FastAPI** アプリケーションにミドルウェアを追加できます。
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
|
||||
`yield` を使った依存関係をもつ場合は、終了コードはミドルウェアの *後に* 実行されます。
|
||||
|
||||
バックグラウンドタスク (後述) がある場合は、それらは全てのミドルウェアの *後に* 実行されます。
|
||||
バックグラウンドタスク ([バックグラウンドタスク](background-tasks.md){.internal-link target=_blank} セクションで説明します。後で確認できます) がある場合は、それらは全てのミドルウェアの *後に* 実行されます。
|
||||
|
||||
///
|
||||
|
||||
## ミドルウェアの作成
|
||||
## ミドルウェアの作成 { #create-a-middleware }
|
||||
|
||||
ミドルウェアを作成するには、関数の上部でデコレータ `@app.middleware("http")` を使用します。
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
* 次に、対応する*path operation*によって生成された `response` を返します。
|
||||
* その後、`response` を返す前にさらに `response` を変更することもできます。
|
||||
|
||||
{* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *}
|
||||
{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">'X-'プレフィックスを使用</a>してカスタムの独自ヘッダーを追加できます。
|
||||
カスタムの独自ヘッダーは <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">`X-` プレフィックスを使用</a>して追加できる点に注意してください。
|
||||
|
||||
ただし、ブラウザのクライアントに表示させたいカスタムヘッダーがある場合は、<a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">StarletteのCORSドキュメント</a>に記載されているパラメータ `expose_headers` を使用して、それらをCORS設定に追加する必要があります ([CORS (オリジン間リソース共有)](cors.md){.internal-link target=_blank})
|
||||
ただし、ブラウザのクライアントに表示させたいカスタムヘッダーがある場合は、<a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">StarletteのCORSドキュメント</a>に記載されているパラメータ `expose_headers` を使用して、それらをCORS設定に追加する必要があります ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank})。
|
||||
|
||||
///
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
///
|
||||
|
||||
### `response` の前後
|
||||
### `response` の前後 { #before-and-after-the-response }
|
||||
|
||||
*path operation* が `request` を受け取る前に、 `request` とともに実行されるコードを追加できます。
|
||||
|
||||
@@ -57,10 +57,39 @@
|
||||
|
||||
例えば、リクエストの処理とレスポンスの生成にかかった秒数を含むカスタムヘッダー `X-Process-Time` を追加できます:
|
||||
|
||||
{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *}
|
||||
{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}
|
||||
|
||||
## その他のミドルウェア
|
||||
/// tip | 豆知識
|
||||
|
||||
ここでは、これらのユースケースに対してより正確になり得るため、`time.time()` の代わりに <a href="https://docs.python.org/3/library/time.html#time.perf_counter" class="external-link" target="_blank">`time.perf_counter()`</a> を使用しています。 🤓
|
||||
|
||||
///
|
||||
|
||||
## 複数ミドルウェアの実行順序 { #multiple-middleware-execution-order }
|
||||
|
||||
`@app.middleware()` デコレータまたは `app.add_middleware()` メソッドのいずれかを使って複数のミドルウェアを追加すると、新しく追加された各ミドルウェアがアプリケーションをラップし、スタックを形成します。最後に追加されたミドルウェアが *最も外側*、最初に追加されたミドルウェアが *最も内側* になります。
|
||||
|
||||
リクエスト経路では、*最も外側* のミドルウェアが最初に実行されます。
|
||||
|
||||
レスポンス経路では、最後に実行されます。
|
||||
|
||||
例:
|
||||
|
||||
```Python
|
||||
app.add_middleware(MiddlewareA)
|
||||
app.add_middleware(MiddlewareB)
|
||||
```
|
||||
|
||||
これにより、実行順序は次のようになります:
|
||||
|
||||
* **リクエスト**: MiddlewareB → MiddlewareA → route
|
||||
|
||||
* **レスポンス**: route → MiddlewareA → MiddlewareB
|
||||
|
||||
このスタック動作により、ミドルウェアが予測可能で制御しやすい順序で実行されることが保証されます。
|
||||
|
||||
## その他のミドルウェア { #other-middlewares }
|
||||
|
||||
他のミドルウェアの詳細については、[高度なユーザーガイド: 高度なミドルウェア](../advanced/middleware.md){.internal-link target=_blank}を参照してください。
|
||||
|
||||
次のセクションでは、ミドルウェアを使用して <abbr title="Cross-Origin Resource Sharing">CORS</abbr> を処理する方法について説明します。
|
||||
次のセクションでは、ミドルウェアを使用して <abbr title="Cross-Origin Resource Sharing - クロスオリジンリソース共有">CORS</abbr> を処理する方法について説明します。
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# Path Operationの設定
|
||||
# Path Operationの設定 { #path-operation-configuration }
|
||||
|
||||
*path operationデコレータ*を設定するためのパラメータがいくつかあります。
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
これらのパラメータは*path operation関数*ではなく、*path operationデコレータ*に直接渡されることに注意してください。
|
||||
これらのパラメータは*path operationデコレータ*に直接渡され、*path operation関数*に渡されないことに注意してください。
|
||||
|
||||
///
|
||||
|
||||
## レスポンスステータスコード
|
||||
## レスポンスステータスコード { #response-status-code }
|
||||
|
||||
*path operation*のレスポンスで使用する(HTTP)`status_code`を定義することができます。
|
||||
|
||||
@@ -16,55 +16,65 @@
|
||||
|
||||
しかし、それぞれの番号コードが何のためのものか覚えていない場合は、`status`のショートカット定数を使用することができます:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial001.py hl[3,17] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}
|
||||
|
||||
そのステータスコードはレスポンスで使用され、OpenAPIスキーマに追加されます。
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
また、`from starlette import status`を使用することもできます。
|
||||
`from starlette import status`を使用することもできます。
|
||||
|
||||
**FastAPI** は開発者の利便性を考慮して、`fastapi.status`と同じ`starlette.status`を提供しています。しかし、これはStarletteから直接提供されています。
|
||||
|
||||
///
|
||||
|
||||
## タグ
|
||||
## タグ { #tags }
|
||||
|
||||
`tags`パラメータを`str`の`list`(通常は1つの`str`)と一緒に渡すと、*path operation*にタグを追加できます:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial002.py hl[17,22,27] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}
|
||||
|
||||
これらはOpenAPIスキーマに追加され、自動ドキュメントのインターフェースで使用されます:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/path-operation-configuration/image01.png">
|
||||
<img src="/img/tutorial/path-operation-configuration/image01.png">
|
||||
|
||||
## 概要と説明
|
||||
### Enumを使ったタグ { #tags-with-enums }
|
||||
|
||||
大きなアプリケーションの場合、**複数のタグ**が蓄積されていき、関連する*path operations*に対して常に**同じタグ**を使っていることを確認したくなるかもしれません。
|
||||
|
||||
このような場合、タグを`Enum`に格納すると理にかなっています。
|
||||
|
||||
**FastAPI** は、プレーンな文字列の場合と同じ方法でそれをサポートしています:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}
|
||||
|
||||
## 概要と説明 { #summary-and-description }
|
||||
|
||||
`summary`と`description`を追加できます:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003.py hl[20:21] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
|
||||
## docstringを用いた説明
|
||||
## docstringを用いた説明 { #description-from-docstring }
|
||||
|
||||
説明文は長くて複数行におよぶ傾向があるので、関数<abbr title="ドキュメントに使用される関数内の最初の式(変数に代入されていない)としての複数行の文字列">docstring</abbr>内に*path operation*の説明文を宣言できます。すると、**FastAPI** は説明文を読み込んでくれます。
|
||||
説明文は長くて複数行におよぶ傾向があるので、関数<dfn title="関数内の最初の式(どの変数にも代入されない)として記述される、ドキュメント用の複数行の文字列">docstring</dfn>内に*path operation*の説明文を宣言できます。すると、**FastAPI** は説明文を読み込んでくれます。
|
||||
|
||||
docstringに<a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a>を記述すれば、正しく解釈されて表示されます。(docstringのインデントを考慮して)
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial004.py hl[19:27] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}
|
||||
|
||||
これは対話的ドキュメントで使用されます:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/path-operation-configuration/image02.png">
|
||||
<img src="/img/tutorial/path-operation-configuration/image02.png">
|
||||
|
||||
## レスポンスの説明
|
||||
## レスポンスの説明 { #response-description }
|
||||
|
||||
`response_description`パラメータでレスポンスの説明をすることができます。
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005.py hl[21] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`respnse_description`は具体的にレスポンスを参照し、`description`は*path operation*全般を参照していることに注意してください。
|
||||
`response_description`は具体的にレスポンスを参照し、`description`は*path operation*全般を参照していることに注意してください。
|
||||
|
||||
///
|
||||
|
||||
@@ -76,22 +86,22 @@ OpenAPIは*path operation*ごとにレスポンスの説明を必要としてい
|
||||
|
||||
///
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/path-operation-configuration/image03.png">
|
||||
<img src="/img/tutorial/path-operation-configuration/image03.png">
|
||||
|
||||
## 非推奨の*path operation*
|
||||
## *path operation*を非推奨にする { #deprecate-a-path-operation }
|
||||
|
||||
*path operation*を<abbr title="非推奨、使わない方がよい">deprecated</abbr>としてマークする必要があるが、それを削除しない場合は、`deprecated`パラメータを渡します:
|
||||
*path operation*を<dfn title="非推奨、使用しないことを推奨">deprecated</dfn>としてマークする必要があるが、それを削除しない場合は、`deprecated`パラメータを渡します:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}
|
||||
|
||||
対話的ドキュメントでは非推奨と明記されます:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/path-operation-configuration/image04.png">
|
||||
<img src="/img/tutorial/path-operation-configuration/image04.png">
|
||||
|
||||
*path operations*が非推奨である場合とそうでない場合でどのように見えるかを確認してください:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/path-operation-configuration/image05.png">
|
||||
<img src="/img/tutorial/path-operation-configuration/image05.png">
|
||||
|
||||
## まとめ
|
||||
## まとめ { #recap }
|
||||
|
||||
*path operationデコレータ*にパラメータを渡すことで、*path operations*のメタデータを簡単に設定・追加することができます。
|
||||
|
||||
@@ -1,40 +1,52 @@
|
||||
# パスパラメータと数値の検証
|
||||
# パスパラメータと数値の検証 { #path-parameters-and-numeric-validations }
|
||||
|
||||
クエリパラメータに対して`Query`でより多くのバリデーションとメタデータを宣言できるのと同じように、パスパラメータに対しても`Path`で同じ種類のバリデーションとメタデータを宣言することができます。
|
||||
|
||||
## Pathのインポート
|
||||
## `Path`のインポート { #import-path }
|
||||
|
||||
まず初めに、`fastapi`から`Path`をインポートします:
|
||||
まず初めに、`fastapi`から`Path`をインポートし、`Annotated`もインポートします:
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial001.py hl[1] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}
|
||||
|
||||
## メタデータの宣言
|
||||
/// info | 情報
|
||||
|
||||
FastAPI はバージョン 0.95.0 で`Annotated`のサポートを追加し(そして推奨し始めました)。
|
||||
|
||||
古いバージョンの場合、`Annotated`を使おうとするとエラーになります。
|
||||
|
||||
`Annotated`を使用する前に、FastAPI のバージョンを少なくとも 0.95.1 まで[アップグレードしてください](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}。
|
||||
|
||||
///
|
||||
|
||||
## メタデータの宣言 { #declare-metadata }
|
||||
|
||||
パラメータは`Query`と同じものを宣言することができます。
|
||||
|
||||
例えば、パスパラメータ`item_id`に対して`title`のメタデータを宣言するには以下のようにします:
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial001.py hl[8] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
パスの一部でなければならないので、パスパラメータは常に必須です。
|
||||
|
||||
そのため、`...`を使用して必須と示す必要があります。
|
||||
|
||||
それでも、`None`で宣言しても、デフォルト値を設定しても、何の影響もなく、常に必要とされていることに変わりはありません。
|
||||
パスパラメータはパスの一部でなければならないので、常に必須です。`None`で宣言したりデフォルト値を設定したりしても何も影響せず、常に必須のままです。
|
||||
|
||||
///
|
||||
|
||||
## 必要に応じてパラメータを並び替える
|
||||
## 必要に応じてパラメータを並び替える { #order-the-parameters-as-you-need }
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`Annotated`を使う場合、これはおそらくそれほど重要でも必要でもありません。
|
||||
|
||||
///
|
||||
|
||||
クエリパラメータ`q`を必須の`str`として宣言したいとしましょう。
|
||||
|
||||
また、このパラメータには何も宣言する必要がないので、`Query`を使う必要はありません。
|
||||
|
||||
しかし、パスパラメータ`item_id`のために`Path`を使用する必要があります。
|
||||
しかし、パスパラメータ`item_id`のために`Path`を使用する必要があります。そして何らかの理由で`Annotated`を使いたくないとします。
|
||||
|
||||
Pythonは「デフォルト」を持たない値の前に「デフォルト」を持つ値を置くことができません。
|
||||
Pythonは「デフォルト」を持つ値を「デフォルト」を持たない値の前に置くとエラーになります。
|
||||
|
||||
しかし、それらを並び替えることができ、デフォルト値を持たない値(クエリパラメータ`q`)を最初に持つことができます。
|
||||
|
||||
@@ -42,63 +54,88 @@ Pythonは「デフォルト」を持たない値の前に「デフォルト」
|
||||
|
||||
そのため、以下のように関数を宣言することができます:
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[8] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}
|
||||
|
||||
## 必要に応じてパラメータを並び替えるトリック
|
||||
ただし、`Annotated`を使う場合はこの問題は起きないことを覚えておいてください。`Query()`や`Path()`に関数パラメータのデフォルト値を使わないためです。
|
||||
|
||||
クエリパラメータ`q`を`Query`やデフォルト値なしで宣言し、パスパラメータ`item_id`を`Path`を用いて宣言し、それらを別の順番に並びたい場合、Pythonには少し特殊な構文が用意されています。
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}
|
||||
|
||||
## 必要に応じてパラメータを並び替えるトリック { #order-the-parameters-as-you-need-tricks }
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`Annotated`を使う場合、これはおそらくそれほど重要でも必要でもありません。
|
||||
|
||||
///
|
||||
|
||||
これは**小さなトリック**で、便利な場合がありますが、頻繁に必要になることはありません。
|
||||
|
||||
次のことをしたい場合:
|
||||
|
||||
* `q`クエリパラメータを`Query`もデフォルト値もなしで宣言する
|
||||
* パスパラメータ`item_id`を`Path`を使って宣言する
|
||||
* それらを別の順番にする
|
||||
* `Annotated`を使わない
|
||||
|
||||
...Pythonにはそのための少し特殊な構文があります。
|
||||
|
||||
関数の最初のパラメータとして`*`を渡します。
|
||||
|
||||
Pythonはその`*`で何かをすることはありませんが、それ以降のすべてのパラメータがキーワード引数(キーと値のペア)として呼ばれるべきものであると知っているでしょう。それは<abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>としても知られています。たとえデフォルト値がなくても。
|
||||
Pythonはその`*`で何かをすることはありませんが、それ以降のすべてのパラメータがキーワード引数(キーと値のペア)として呼ばれるべきものであると知っているでしょう。それは<abbr title="From: K-ey W-ord Arg-uments - キーワード引数"><code>kwargs</code></abbr>としても知られています。たとえデフォルト値がなくても。
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[8] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}
|
||||
|
||||
## 数値の検証: 以上
|
||||
### `Annotated`のほうがよい { #better-with-annotated }
|
||||
|
||||
`Query`と`Path`(、そして後述する他のもの)を用いて、文字列の制約を宣言することができますが、数値の制約も同様に宣言できます。
|
||||
`Annotated`を使う場合は、関数パラメータのデフォルト値を使わないため、この問題は起きず、おそらく`*`を使う必要もありません。
|
||||
|
||||
ここで、`ge=1`の場合、`item_id`は`1`「より大きい`g`か、同じ`e`」整数でなれけばなりません。
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial004.py hl[8] *}
|
||||
## 数値の検証: 以上 { #number-validations-greater-than-or-equal }
|
||||
|
||||
## 数値の検証: より大きいと小なりイコール
|
||||
`Query`と`Path`(、そして後述する他のもの)を用いて、数値の制約を宣言できます。
|
||||
|
||||
ここで、`ge=1`の場合、`item_id`は`1`「より大きい`g`か、同じ`e`」整数でなければなりません。
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}
|
||||
|
||||
## 数値の検証: より大きいと小なりイコール { #number-validations-greater-than-and-less-than-or-equal }
|
||||
|
||||
以下も同様です:
|
||||
|
||||
* `gt`: より大きい(`g`reater `t`han)
|
||||
* `le`: 小なりイコール(`l`ess than or `e`qual)
|
||||
* `gt`: `g`reater `t`han
|
||||
* `le`: `l`ess than or `e`qual
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial005.py hl[9] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}
|
||||
|
||||
## 数値の検証: 浮動小数点、 大なり小なり
|
||||
## 数値の検証: 浮動小数点、 大なり小なり { #number-validations-floats-greater-than-and-less-than }
|
||||
|
||||
数値のバリデーションは`float`の値に対しても有効です。
|
||||
|
||||
ここで重要になってくるのは<abbr title="より大きい"><code>gt</code></abbr>だけでなく<abbr title="以下"><code>ge</code></abbr>も宣言できることです。これと同様に、例えば、値が`1`より小さくても`0`より大きくなければならないことを要求することができます。
|
||||
ここで重要になってくるのは<abbr title="greater than – より大きい"><code>gt</code></abbr>だけでなく<abbr title="greater than or equal – 以上"><code>ge</code></abbr>も宣言できることです。これと同様に、例えば、値が`1`より小さくても`0`より大きくなければならないことを要求することができます。
|
||||
|
||||
したがって、`0.5`は有効な値ですが、`0.0`や`0`はそうではありません。
|
||||
|
||||
これは<abbr title="未満"><code>lt</code></abbr>も同じです。
|
||||
これは<abbr title="less than – より小さい"><code>lt</code></abbr>も同じです。
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial006.py hl[11] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}
|
||||
|
||||
## まとめ
|
||||
## まとめ { #recap }
|
||||
|
||||
`Query`と`Path`(そしてまだ見たことない他のもの)では、[クエリパラメータと文字列の検証](query-params-str-validations.md){.internal-link target=_blank}と同じようにメタデータと文字列の検証を宣言することができます。
|
||||
|
||||
また、数値のバリデーションを宣言することもできます:
|
||||
|
||||
* `gt`: より大きい(`g`reater `t`han)
|
||||
* `ge`: 以上(`g`reater than or `e`qual)
|
||||
* `lt`: より小さい(`l`ess `t`han)
|
||||
* `le`: 以下(`l`ess than or `e`qual)
|
||||
* `gt`: `g`reater `t`han
|
||||
* `ge`: `g`reater than or `e`qual
|
||||
* `lt`: `l`ess `t`han
|
||||
* `le`: `l`ess than or `e`qual
|
||||
|
||||
/// info | 情報
|
||||
|
||||
`Query`、`Path`などは後に共通の`Param`クラスのサブクラスを見ることになります。(使う必要はありません)
|
||||
`Query`、`Path`、および後で見る他のクラスは、共通の`Param`クラスのサブクラスです。
|
||||
|
||||
そして、それらすべては、これまで見てきた追加のバリデーションとメタデータと同じパラメータを共有しています。
|
||||
それらはすべて、これまで見てきた追加のバリデーションとメタデータの同じパラメータを共有しています。
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# パスパラメータ
|
||||
# パスパラメータ { #path-parameters }
|
||||
|
||||
Pythonのformat文字列と同様のシンタックスで「パスパラメータ」や「パス変数」を宣言できます:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial001.py hl[6,7] *}
|
||||
{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}
|
||||
|
||||
パスパラメータ `item_id` の値は、引数 `item_id` として関数に渡されます。
|
||||
|
||||
しがたって、この例を実行して <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a> にアクセスすると、次のレスポンスが表示されます。
|
||||
したがって、この例を実行して <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a> にアクセスすると、次のレスポンスが表示されます。
|
||||
|
||||
```JSON
|
||||
{"item_id":"foo"}
|
||||
```
|
||||
|
||||
## パスパラメータと型
|
||||
## 型付きパスパラメータ { #path-parameters-with-types }
|
||||
|
||||
標準のPythonの型アノテーションを使用して、関数内のパスパラメータの型を宣言できます:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial002.py hl[7] *}
|
||||
{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}
|
||||
|
||||
ここでは、 `item_id` は `int` として宣言されています。
|
||||
|
||||
@@ -26,7 +26,7 @@ Pythonのformat文字列と同様のシンタックスで「パスパラメー
|
||||
|
||||
///
|
||||
|
||||
## データ<abbr title="別名: serialization, parsing, marshalling">変換</abbr>
|
||||
## データ<dfn title="別名: シリアライズ、パース、マーシャリング">変換</dfn> { #data-conversion }
|
||||
|
||||
この例を実行し、ブラウザで <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a> を開くと、次のレスポンスが表示されます:
|
||||
|
||||
@@ -38,68 +38,69 @@ Pythonのformat文字列と同様のシンタックスで「パスパラメー
|
||||
|
||||
関数が受け取った(および返した)値は、文字列の `"3"` ではなく、Pythonの `int` としての `3` であることに注意してください。
|
||||
|
||||
したがって、型宣言を使用すると、**FastAPI**は自動リクエスト <abbr title="HTTPリクエストで受け取った文字列をPythonデータへ変換する">"解析"</abbr> を行います。
|
||||
したがって、その型宣言を使うと、**FastAPI**は自動リクエスト <dfn title="HTTPリクエストから受け取った文字列をPythonのデータに変換する">"解析"</dfn> を行います。
|
||||
|
||||
///
|
||||
|
||||
## データバリデーション
|
||||
## データバリデーション { #data-validation }
|
||||
|
||||
しかしブラウザで <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a> を開くと、次のHTTPエラーが表示されます:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"loc": [
|
||||
"path",
|
||||
"item_id"
|
||||
],
|
||||
"msg": "value is not a valid integer",
|
||||
"type": "type_error.integer"
|
||||
}
|
||||
]
|
||||
"detail": [
|
||||
{
|
||||
"type": "int_parsing",
|
||||
"loc": [
|
||||
"path",
|
||||
"item_id"
|
||||
],
|
||||
"msg": "Input should be a valid integer, unable to parse string as an integer",
|
||||
"input": "foo"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
これは、パスパラメータ `item_id` が `int` ではない値 `"foo"` だからです。
|
||||
|
||||
<a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a> で見られるように、intのかわりに `float` が与えられた場合にも同様なエラーが表示されます。
|
||||
<a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a> で見られるように、`int` のかわりに `float` が与えられた場合にも同様なエラーが表示されます。
|
||||
|
||||
/// check | 確認
|
||||
|
||||
したがって、Pythonの型宣言を使用することで、**FastAPI**はデータのバリデーションを行います。
|
||||
したがって、同じPythonの型宣言を使用することで、**FastAPI**はデータのバリデーションを行います。
|
||||
|
||||
表示されたエラーには問題のある箇所が明確に指摘されていることに注意してください。
|
||||
表示されたエラーには、バリデーションが通らなかった箇所が明確に示されていることに注意してください。
|
||||
|
||||
これは、APIに関連するコードの開発およびデバッグに非常に役立ちます。
|
||||
これは、APIとやり取りするコードを開発・デバッグする際に非常に役立ちます。
|
||||
|
||||
///
|
||||
|
||||
## ドキュメント
|
||||
## ドキュメント { #documentation }
|
||||
|
||||
そしてブラウザで <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> を開くと、以下の様な自動的に生成された対話的なドキュメントが表示されます。
|
||||
そしてブラウザで <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> を開くと、以下の様な自動的に生成された対話的なAPIドキュメントが表示されます。
|
||||
|
||||
<img src="/img/tutorial/path-params/image01.png">
|
||||
|
||||
/// check | 確認
|
||||
|
||||
繰り返しになりますが、Python型宣言を使用するだけで、**FastAPI**は対話的なAPIドキュメントを自動的に生成します(Swagger UIを統合)。
|
||||
繰り返しになりますが、同じPython型宣言を使用するだけで、**FastAPI**は対話的なドキュメントを自動的に生成します(Swagger UIを統合)。
|
||||
|
||||
パスパラメータが整数として宣言されていることに注意してください。
|
||||
|
||||
///
|
||||
|
||||
## 標準であることのメリット、ドキュメンテーションの代替物
|
||||
## 標準ベースのメリット、ドキュメンテーションの代替物 { #standards-based-benefits-alternative-documentation }
|
||||
|
||||
また、生成されたスキーマが <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class="external-link" target="_blank">OpenAPI</a> 標準に従っているので、互換性のあるツールが多数あります。
|
||||
また、生成されたスキーマが <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a> 標準に従っているので、互換性のあるツールが多数あります。
|
||||
|
||||
このため、**FastAPI**自体が代替のAPIドキュメントを提供します(ReDocを使用)。これは、 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> にアクセスすると確認できます。
|
||||
|
||||
<img src="/img/tutorial/path-params/image02.png">
|
||||
|
||||
同様に、互換性のあるツールが多数あります(多くの言語用のコード生成ツールを含む)。
|
||||
同様に、互換性のあるツールが多数あります。多くの言語用のコード生成ツールを含みます。
|
||||
|
||||
## Pydantic
|
||||
## Pydantic { #pydantic }
|
||||
|
||||
すべてのデータバリデーションは <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> によって内部で実行されるため、Pydanticの全てのメリットが得られます。そして、安心して利用することができます。
|
||||
|
||||
@@ -107,7 +108,7 @@ Pythonのformat文字列と同様のシンタックスで「パスパラメー
|
||||
|
||||
これらのいくつかについては、チュートリアルの次の章で説明します。
|
||||
|
||||
## 順序の問題
|
||||
## 順序の問題 { #order-matters }
|
||||
|
||||
*path operations* を作成する際、固定パスをもつ状況があり得ます。
|
||||
|
||||
@@ -117,63 +118,63 @@ Pythonのformat文字列と同様のシンタックスで「パスパラメー
|
||||
|
||||
*path operations* は順に評価されるので、 `/users/me` が `/users/{user_id}` よりも先に宣言されているか確認する必要があります:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
|
||||
{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}
|
||||
|
||||
それ以外の場合、 `/users/{users_id}` は `/users/me` としてもマッチします。値が「"me"」であるパラメータ `user_id` を受け取ると「考え」ます。
|
||||
それ以外の場合、 `/users/{user_id}` は `/users/me` としてもマッチします。値が `"me"` であるパラメータ `user_id` を受け取ると「考え」ます。
|
||||
|
||||
## 定義済みの値
|
||||
同様に、path operation を再定義することはできません:
|
||||
|
||||
*パスパラメータ*を受け取る *path operation* をもち、有効な*パスパラメータ*の値を事前に定義したい場合は、標準のPython <abbr title="Enumeration">`Enum`</abbr> を利用できます。
|
||||
{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}
|
||||
|
||||
### `Enum` クラスの作成
|
||||
パスは最初にマッチしたものが常に使われるため、最初のものが常に使用されます。
|
||||
|
||||
## 定義済みの値 { #predefined-values }
|
||||
|
||||
*パスパラメータ*を受け取る *path operation* をもち、有効な*パスパラメータ*の値を事前に定義したい場合は、標準のPython <abbr title="Enumeration - 列挙型">`Enum`</abbr> を利用できます。
|
||||
|
||||
### `Enum` クラスの作成 { #create-an-enum-class }
|
||||
|
||||
`Enum` をインポートし、 `str` と `Enum` を継承したサブクラスを作成します。
|
||||
|
||||
`str` を継承することで、APIドキュメントは値が `文字列` でなければいけないことを知り、正確にレンダリングできるようになります。
|
||||
`str` を継承することで、APIドキュメントは値が `string` 型でなければいけないことを知り、正確にレンダリングできるようになります。
|
||||
|
||||
そして、固定値のクラス属性を作ります。すると、その値が使用可能な値となります:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[1,6,7,8,9] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
<a href="https://docs.python.org/3/library/enum.html" class="external-link" target="_blank">Enumerations (もしくは、enums)はPython 3.4以降で利用できます</a>。
|
||||
|
||||
///
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
"AlexNet"、"ResNet"そして"LeNet"は機械学習<abbr title="Technically, Deep Learning model architectures">モデル</abbr>の名前です。
|
||||
"AlexNet"、"ResNet"そして"LeNet"は機械学習<dfn title="厳密には、Deep Learning のモデルアーキテクチャ">モデル</dfn>の名前です。
|
||||
|
||||
///
|
||||
|
||||
### *パスパラメータ*の宣言
|
||||
### *パスパラメータ*の宣言 { #declare-a-path-parameter }
|
||||
|
||||
次に、作成したenumクラスである`ModelName`を使用した型アノテーションをもつ*パスパラメータ*を作成します:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[16] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}
|
||||
|
||||
### ドキュメントの確認
|
||||
### ドキュメントの確認 { #check-the-docs }
|
||||
|
||||
*パスパラメータ*の利用可能な値が事前に定義されているので、対話的なドキュメントで適切に表示できます:
|
||||
|
||||
<img src="/img/tutorial/path-params/image03.png">
|
||||
|
||||
### Python*列挙型*の利用
|
||||
### Python*列挙型*の利用 { #working-with-python-enumerations }
|
||||
|
||||
*パスパラメータ*の値は*列挙型メンバ*となります。
|
||||
|
||||
#### *列挙型メンバ*の比較
|
||||
#### *列挙型メンバ*の比較 { #compare-enumeration-members }
|
||||
|
||||
これは、作成した列挙型 `ModelName` の*列挙型メンバ*と比較できます:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[17] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}
|
||||
|
||||
#### *列挙値*の取得
|
||||
#### *列挙値*の取得 { #get-the-enumeration-value }
|
||||
|
||||
`model_name.value` 、もしくは一般に、 `your_enum_member.value` を使用して実際の値 (この場合は `str`) を取得できます。
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[20] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -181,13 +182,13 @@ Pythonのformat文字列と同様のシンタックスで「パスパラメー
|
||||
|
||||
///
|
||||
|
||||
#### *列挙型メンバ*の返却
|
||||
#### *列挙型メンバ*の返却 { #return-enumeration-members }
|
||||
|
||||
*path operation* から*列挙型メンバ*を返すことができます。JSONボディ(`dict` など)でネストすることもできます。
|
||||
*path operation* から*列挙型メンバ*を返すことができます。JSONボディ(例: `dict`)でネストすることもできます。
|
||||
|
||||
それらはクライアントに返される前に適切な値 (この場合は文字列) に変換されます。
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
|
||||
{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}
|
||||
|
||||
クライアントは以下の様なJSONレスポンスを得ます:
|
||||
|
||||
@@ -198,23 +199,23 @@ Pythonのformat文字列と同様のシンタックスで「パスパラメー
|
||||
}
|
||||
```
|
||||
|
||||
## パスを含んだパスパラメータ
|
||||
## パスを含んだパスパラメータ { #path-parameters-containing-paths }
|
||||
|
||||
パス `/files/{file_path}` となる *path operation* を持っているとしましょう。
|
||||
|
||||
ただし、 `home/johndoe/myfile.txt` のような*パス*を含んだ `file_path` が必要です。
|
||||
|
||||
したがって、URLは `/files/home/johndoe/myfile.txt` の様になります。
|
||||
したがって、そのファイルのURLは `/files/home/johndoe/myfile.txt` の様になります。
|
||||
|
||||
### OpenAPIサポート
|
||||
### OpenAPIサポート { #openapi-support }
|
||||
|
||||
OpenAPIはテストや定義が困難なシナリオにつながる可能性があるため、内部に*パス*を含む*パスパラメータ*の宣言をサポートしていません。
|
||||
|
||||
それにも関わらず、Starletteの内部ツールのひとつを使用することで、**FastAPI**はそれが実現できます。
|
||||
|
||||
そして、パラメータがパスを含むべきであることを明示的にドキュメントに追加することなく、機能します。
|
||||
そして、パラメータがパスを含むべきであることを示すドキュメントを追加しなくても、ドキュメントは動作します。
|
||||
|
||||
### パス変換
|
||||
### パスコンバーター { #path-convertor }
|
||||
|
||||
Starletteのオプションを直接使用することで、以下のURLの様な*パス*を含んだ、*パスパラメータ*の宣言ができます:
|
||||
|
||||
@@ -226,22 +227,22 @@ Starletteのオプションを直接使用することで、以下のURLの様
|
||||
|
||||
したがって、以下の様に使用できます:
|
||||
|
||||
{* ../../docs_src/path_params/tutorial004.py hl[6] *}
|
||||
{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
最初のスラッシュ (`/`)が付いている `/home/johndoe/myfile.txt` をパラメータが含んでいる必要があります。
|
||||
最初のスラッシュ (`/`)が付いている `/home/johndoe/myfile.txt` をパラメータが含んでいる必要があるかもしれません。
|
||||
|
||||
この場合、URLは `files` と `home` の間にダブルスラッシュ (`//`) のある、 `/files//home/johndoe/myfile.txt` になります。
|
||||
|
||||
///
|
||||
|
||||
## まとめ
|
||||
## まとめ { #recap }
|
||||
|
||||
簡潔で、本質的で、標準的なPythonの型宣言を使用することで、**FastAPI**は以下を行います:
|
||||
|
||||
* エディターサポート: エラーチェック、自動補完、など
|
||||
* データ「<abbr title="HTTPリクエストで受け取った文字列をPythonデータへ変換する">解析</abbr>」
|
||||
* データ「<dfn title="HTTPリクエストから受け取った文字列をPythonのデータに変換する">解析</dfn>」
|
||||
* データバリデーション
|
||||
* APIアノテーションと自動ドキュメント生成
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# クエリパラメータモデル
|
||||
# クエリパラメータモデル { #query-parameter-models }
|
||||
|
||||
もし関連する**複数のクエリパラメータ**から成るグループがあるなら、それらを宣言するために、**Pydanticモデル**を作成できます。
|
||||
|
||||
こうすることで、**複数の場所**で**そのPydanticモデルを再利用**でき、バリデーションやメタデータを、すべてのクエリパラメータに対して一度に宣言できます。😎
|
||||
こうすることで、**複数の場所**で**そのモデルを再利用**でき、バリデーションやメタデータを、すべてのパラメータに対して一度に宣言できます。😎
|
||||
|
||||
/// note | 備考
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
|
||||
///
|
||||
|
||||
## クエリパラメータにPydanticモデルを使用する
|
||||
## Pydanticモデルを使ったクエリパラメータ { #query-parameters-with-a-pydantic-model }
|
||||
|
||||
必要な**複数のクエリパラメータ**を**Pydanticモデル**で宣言し、さらに、それを `Query` として宣言しましょう:
|
||||
必要な**クエリパラメータ**を**Pydanticモデル**で宣言し、さらに、そのパラメータを `Query` として宣言しましょう:
|
||||
|
||||
{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}
|
||||
|
||||
**FastAPI**は、リクエストの**クエリパラメータ**からそれぞれの**フィールド**のデータを**抽出**し、定義された**Pydanticモデル**を提供します。
|
||||
**FastAPI**は、リクエストの**クエリパラメータ**からそれぞれの**フィールド**のデータを**抽出**し、定義したPydanticモデルを提供します。
|
||||
|
||||
## ドキュメントの確認
|
||||
## ドキュメントの確認 { #check-the-docs }
|
||||
|
||||
対話的APIドキュメント `/docs` でクエリパラメータを確認できます:
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
<img src="/img/tutorial/query-param-models/image01.png">
|
||||
</div>
|
||||
|
||||
## 余分なクエリパラメータを禁止する
|
||||
## 余分なクエリパラメータを禁止する { #forbid-extra-query-parameters }
|
||||
|
||||
特定の(あまり一般的ではないかもしれない)ケースで、受け付けるクエリパラメータを**制限**する必要があるかもしれません。
|
||||
特定の(あまり一般的ではないかもしれない)ユースケースで、受け取りたいクエリパラメータを**制限**したい場合があります。
|
||||
|
||||
Pydanticのモデルの Configuration を利用して、 `extra` フィールドを `forbid` とすることができます。
|
||||
Pydanticのモデル設定を使って、あらゆる `extra` フィールドを `forbid` にできます。
|
||||
|
||||
{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
|
||||
|
||||
@@ -42,7 +42,7 @@ Pydanticのモデルの Configuration を利用して、 `extra` フィールド
|
||||
https://example.com/items/?limit=10&tool=plumbus
|
||||
```
|
||||
|
||||
クエリパラメータ `tool` が許可されていないことを通知する**エラー**レスポンスが返されます。
|
||||
クエリパラメータ `tool` が許可されていないことを伝える**エラー**レスポンスが返されます。
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -57,7 +57,7 @@ https://example.com/items/?limit=10&tool=plumbus
|
||||
}
|
||||
```
|
||||
|
||||
## まとめ
|
||||
## まとめ { #summary }
|
||||
|
||||
**FastAPI**では、**クエリパラメータ**を宣言するために、**Pydanticモデル**を使用できます。😎
|
||||
|
||||
|
||||
@@ -1,120 +1,204 @@
|
||||
# クエリパラメータと文字列の検証
|
||||
# クエリパラメータと文字列の検証 { #query-parameters-and-string-validations }
|
||||
|
||||
**FastAPI** ではパラメータの追加情報とバリデーションを宣言することができます。
|
||||
|
||||
以下のアプリケーションを例にしてみましょう:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial001.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
|
||||
|
||||
クエリパラメータ `q` は `Optional[str]` 型で、`None` を許容する `str` 型を意味しており、デフォルトは `None` です。そのため、FastAPIはそれが必須ではないと理解します。
|
||||
クエリパラメータ `q` は `str | None` 型で、`str` 型ですが `None` にもなり得ることを意味し、実際にデフォルト値は `None` なので、FastAPIはそれが必須ではないと理解します。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
FastAPIは、 `q` はデフォルト値が `=None` であるため、必須ではないと理解します。
|
||||
FastAPIは、 `q` はデフォルト値が `= None` であるため、必須ではないと理解します。
|
||||
|
||||
`Optional[str]` における `Optional` はFastAPIには利用されませんが、エディターによるより良いサポートとエラー検出を可能にします。
|
||||
`str | None` を使うことで、エディターによるより良いサポートとエラー検出を可能にします。
|
||||
|
||||
///
|
||||
|
||||
## バリデーションの追加
|
||||
## バリデーションの追加 { #additional-validation }
|
||||
|
||||
`q`はオプショナルですが、もし値が渡されてきた場合には、**50文字を超えないこと**を強制してみましょう。
|
||||
`q`はオプショナルですが、もし値が渡されてきた場合には、**長さが50文字を超えないこと**を強制してみましょう。
|
||||
|
||||
### `Query`のインポート
|
||||
### `Query` と `Annotated` のインポート { #import-query-and-annotated }
|
||||
|
||||
そのために、まずは`fastapi`から`Query`をインポートします:
|
||||
そのために、まずは以下をインポートします:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002.py hl[3] *}
|
||||
* `fastapi` から `Query`
|
||||
* `typing` から `Annotated`
|
||||
|
||||
## デフォルト値として`Query`を使用
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
|
||||
|
||||
パラメータのデフォルト値として使用し、パラメータ`max_length`を50に設定します:
|
||||
/// info | 情報
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002.py hl[9] *}
|
||||
FastAPI はバージョン 0.95.0 で `Annotated` のサポートを追加し(推奨し始め)ました。
|
||||
|
||||
デフォルト値`None`を`Query(default=None)`に置き換える必要があるので、`Query`の最初の引数はデフォルト値を定義するのと同じです。
|
||||
古いバージョンの場合、`Annotated` を使おうとするとエラーになります。
|
||||
|
||||
`Annotated` を使う前に、FastAPI のバージョンを少なくとも 0.95.1 にするために、[FastAPI のバージョンをアップグレード](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}してください。
|
||||
|
||||
///
|
||||
|
||||
## `q` パラメータの型で `Annotated` を使う { #use-annotated-in-the-type-for-the-q-parameter }
|
||||
|
||||
以前、[Python Types Intro](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank} で `Annotated` を使ってパラメータにメタデータを追加できると説明したことを覚えていますか?
|
||||
|
||||
いよいよ FastAPI で使うときです。 🚀
|
||||
|
||||
次の型アノテーションがありました:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
これを `Annotated` で包んで、次のようにします:
|
||||
|
||||
```Python
|
||||
q: Annotated[str | None] = None
|
||||
```
|
||||
|
||||
どちらも同じ意味で、`q` は `str` または `None` になり得るパラメータで、デフォルトでは `None` です。
|
||||
|
||||
では、面白いところに進みましょう。 🎉
|
||||
|
||||
## `q` パラメータの `Annotated` に `Query` を追加する { #add-query-to-annotated-in-the-q-parameter }
|
||||
|
||||
追加情報(この場合は追加のバリデーション)を入れられる `Annotated` ができたので、`Annotated` の中に `Query` を追加し、パラメータ `max_length` を `50` に設定します:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
|
||||
|
||||
デフォルト値は引き続き `None` なので、このパラメータは依然としてオプショナルです。
|
||||
|
||||
しかし、`Annotated` の中に `Query(max_length=50)` を入れることで、この値に **追加のバリデーション** をしたい、最大 50 文字にしたい、と FastAPI に伝えています。 😎
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ここでは **クエリパラメータ** なので `Query()` を使っています。後で `Path()`、`Body()`、`Header()`、`Cookie()` など、`Query()` と同じ引数を受け取れるものも見ていきます。
|
||||
|
||||
///
|
||||
|
||||
FastAPI は次を行います:
|
||||
|
||||
* 最大長が 50 文字であることを確かめるようデータを **検証** する
|
||||
* データが有効でないときに、クライアントに **明確なエラー** を表示する
|
||||
* OpenAPI スキーマの *path operation* にパラメータを **ドキュメント化** する(その結果、**自動ドキュメント UI** に表示されます)
|
||||
|
||||
## 代替(古い方法): デフォルト値としての `Query` { #alternative-old-query-as-the-default-value }
|
||||
|
||||
FastAPI の以前のバージョン(<dfn title="2023-03 より前">0.95.0</dfn> より前)では、パラメータのデフォルト値として `Query` を使う必要があり、`Annotated` の中に入れるのではありませんでした。これを使ったコードを見かける可能性が高いので、説明します。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
新しいコードでは、可能な限り上で説明したとおり `Annotated` を使ってください。複数の利点(後述)があり、欠点はありません。 🍰
|
||||
|
||||
///
|
||||
|
||||
関数パラメータのデフォルト値として `Query()` を使い、パラメータ `max_length` を 50 に設定する方法は次のとおりです:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
|
||||
|
||||
この場合(`Annotated` を使わない場合)、関数内のデフォルト値 `None` を `Query()` に置き換える必要があるため、`Query(default=None)` のパラメータでデフォルト値を設定する必要があります。これは(少なくとも FastAPI にとっては)そのデフォルト値を定義するのと同じ目的を果たします。
|
||||
|
||||
なので:
|
||||
|
||||
```Python
|
||||
q: Optional[str] = Query(default=None)
|
||||
q: str | None = Query(default=None)
|
||||
```
|
||||
|
||||
...を以下と同じようにパラメータをオプションにします:
|
||||
...はデフォルト値 `None` を持つオプショナルなパラメータになり、以下と同じです:
|
||||
|
||||
|
||||
```Python
|
||||
q: Optional[str] = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
しかし、これはクエリパラメータとして明示的に宣言しています。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
FastAPIは以下の部分を気にすることを覚えておいてください:
|
||||
|
||||
```Python
|
||||
= None
|
||||
```
|
||||
|
||||
もしくは:
|
||||
|
||||
```Python
|
||||
= Query(default=None)
|
||||
```
|
||||
|
||||
そして、 `None` を利用することでクエリパラメータが必須ではないと検知します。
|
||||
|
||||
`Optional` の部分は、エディターによるより良いサポートを可能にします。
|
||||
|
||||
///
|
||||
ただし `Query` のバージョンでは、クエリパラメータであることを明示的に宣言しています。
|
||||
|
||||
そして、さらに多くのパラメータを`Query`に渡すことができます。この場合、文字列に適用される、`max_length`パラメータを指定します。
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = Query(default=None, max_length=50)
|
||||
q: str | None = Query(default=None, max_length=50)
|
||||
```
|
||||
|
||||
これにより、データを検証し、データが有効でない場合は明確なエラーを表示し、OpenAPIスキーマの *path operation* にパラメータを記載します。
|
||||
|
||||
## バリデーションをさらに追加する
|
||||
### デフォルト値としての `Query` または `Annotated` 内の `Query` { #query-as-the-default-value-or-in-annotated }
|
||||
|
||||
`Annotated` の中で `Query` を使う場合、`Query` の `default` パラメータは使えないことに注意してください。
|
||||
|
||||
その代わりに、関数パラメータの実際のデフォルト値を使います。そうしないと整合性が取れなくなります。
|
||||
|
||||
例えば、これは許可されません:
|
||||
|
||||
```Python
|
||||
q: Annotated[str, Query(default="rick")] = "morty"
|
||||
```
|
||||
|
||||
...なぜなら、デフォルト値が `"rick"` なのか `"morty"` なのかが不明確だからです。
|
||||
|
||||
そのため、(できれば)次のようにします:
|
||||
|
||||
```Python
|
||||
q: Annotated[str, Query()] = "rick"
|
||||
```
|
||||
|
||||
...または、古いコードベースでは次のようなものが見つかるでしょう:
|
||||
|
||||
```Python
|
||||
q: str = Query(default="rick")
|
||||
```
|
||||
|
||||
### `Annotated` の利点 { #advantages-of-annotated }
|
||||
|
||||
関数パラメータのデフォルト値スタイルではなく、**`Annotated` を使うことが推奨** されます。複数の理由で **より良い** からです。 🤓
|
||||
|
||||
**関数パラメータ** の **デフォルト値** は **実際のデフォルト値** であり、Python 全般としてより直感的です。 😌
|
||||
|
||||
FastAPI なしで同じ関数を **別の場所** から **呼び出しても**、**期待どおりに動作** します。**必須** パラメータ(デフォルト値がない)があれば、**エディター** がエラーで知らせてくれますし、**Python** も必須パラメータを渡さずに実行すると文句を言います。
|
||||
|
||||
`Annotated` を使わずに **(古い)デフォルト値スタイル** を使う場合、FastAPI なしでその関数を **別の場所** で呼び出すとき、正しく動かすために関数へ引数を渡すことを **覚えておく** 必要があります。そうしないと値が期待と異なります(例えば `str` の代わりに `QueryInfo` か、それに類するものになります)。また、エディターも警告せず、Python もその関数の実行で文句を言いません。内部の処理がエラーになるときに初めて問題が出ます。
|
||||
|
||||
`Annotated` は複数のメタデータアノテーションを持てるので、<a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a> のような別ツールと同じ関数を使うこともできます。 🚀
|
||||
|
||||
## バリデーションをさらに追加する { #add-more-validations }
|
||||
|
||||
パラメータ`min_length`も追加することができます:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial003.py hl[10] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
|
||||
|
||||
## 正規表現の追加
|
||||
## 正規表現の追加 { #add-regular-expressions }
|
||||
|
||||
パラメータが一致するべき<abbr title="正規表現とは、文字列の検索パターンを定義する文字列です。">正規表現</abbr>を定義することができます:
|
||||
パラメータが一致するべき <dfn title="正規表現、regex、regexp は、文字列に対する検索パターンを定義する文字の並びです。">正規表現</dfn> `pattern` を定義することができます:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004.py hl[11] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
この特定の正規表現は受け取ったパラメータの値をチェックします:
|
||||
この特定の正規表現パターンは受け取ったパラメータの値をチェックします:
|
||||
|
||||
* `^`: は、これ以降の文字で始まり、これより以前には文字はありません。
|
||||
* `fixedquery`: は、正確な`fixedquery`を持っています.
|
||||
* `$`: で終わる場合、`fixedquery`以降には文字はありません.
|
||||
|
||||
もしこれらすべての **正規表現**のアイデアについて迷っていても、心配しないでください。多くの人にとって難しい話題です。正規表現を必要としなくても、まだ、多くのことができます。
|
||||
もしこれらすべての **「正規表現」** のアイデアについて迷っていても、心配しないでください。多くの人にとって難しい話題です。正規表現を必要としなくても、まだ、多くのことができます。
|
||||
|
||||
しかし、あなたがそれらを必要とし、学ぶときにはすでに、 **FastAPI**で直接それらを使用することができます。
|
||||
これで、必要になったときにはいつでも **FastAPI** で使えることが分かりました。
|
||||
|
||||
## デフォルト値
|
||||
## デフォルト値 { #default-values }
|
||||
|
||||
第一引数に`None`を渡して、デフォルト値として使用するのと同じように、他の値を渡すこともできます。
|
||||
もちろん、`None` 以外のデフォルト値も使えます。
|
||||
|
||||
クエリパラメータ`q`の`min_length`を`3`とし、デフォルト値を`fixedquery`としてみましょう:
|
||||
クエリパラメータ `q` の `min_length` を `3` とし、デフォルト値を `"fixedquery"` として宣言したいとします:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial005.py hl[7] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
デフォルト値を指定すると、パラメータは任意になります。
|
||||
`None` を含む任意の型のデフォルト値があると、パラメータはオプショナル(必須ではない)になります。
|
||||
|
||||
///
|
||||
|
||||
## 必須にする
|
||||
## 必須パラメータ { #required-parameters }
|
||||
|
||||
これ以上、バリデーションやメタデータを宣言する必要のない場合は、デフォルト値を指定しないだけでクエリパラメータ`q`を必須にすることができます。以下のように:
|
||||
これ以上、バリデーションやメタデータを宣言する必要がない場合は、デフォルト値を宣言しないだけでクエリパラメータ `q` を必須にできます。以下のように:
|
||||
|
||||
```Python
|
||||
q: str
|
||||
@@ -123,42 +207,42 @@ q: str
|
||||
以下の代わりに:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
現在は以下の例のように`Query`で宣言しています:
|
||||
しかし今は、例えば次のように `Query` で宣言しています:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = Query(default=None, min_length=3)
|
||||
q: Annotated[str | None, Query(min_length=3)] = None
|
||||
```
|
||||
|
||||
そのため、`Query`を使用して必須の値を宣言する必要がある場合は、第一引数に`...`を使用することができます:
|
||||
そのため、`Query` を使いながら値を必須として宣言したい場合は、単にデフォルト値を宣言しません:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006.py hl[7] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}
|
||||
|
||||
/// info | 情報
|
||||
### 必須、`None` にできる { #required-can-be-none }
|
||||
|
||||
これまで`...`を見たことがない方へ: これは特殊な単一値です。<a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">Pythonの一部であり、"Ellipsis"と呼ばれています</a>。
|
||||
パラメータが `None` を受け付けるが、それでも必須である、と宣言できます。これにより、値が `None` であってもクライアントは値を送らなければならなくなります。
|
||||
|
||||
///
|
||||
そのために、`None` が有効な型であることを宣言しつつ、単にデフォルト値を宣言しません:
|
||||
|
||||
これは **FastAPI** にこのパラメータが必須であることを知らせます。
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
|
||||
|
||||
## クエリパラメータのリスト / 複数の値
|
||||
## クエリパラメータのリスト / 複数の値 { #query-parameter-list-multiple-values }
|
||||
|
||||
クエリパラメータを明示的に`Query`で宣言した場合、値のリストを受け取るように宣言したり、複数の値を受け取るように宣言したりすることもできます。
|
||||
クエリパラメータを明示的に `Query` で定義すると、値のリストを受け取るように宣言したり、言い換えると複数の値を受け取るように宣言したりすることもできます。
|
||||
|
||||
例えば、URL内に複数回出現するクエリパラメータ`q`を宣言するには以下のように書きます:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial011.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
|
||||
|
||||
そしてURLは以下です:
|
||||
そして、次のような URL なら:
|
||||
|
||||
```
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
複数の*クエリパラメータ*の値`q`(`foo`と`bar`)を*path operation関数*内で*関数パラメータ*`q`としてPythonの`list`を受け取ることになります。
|
||||
*path operation function* 内の *function parameter* `q` で、複数の `q` *query parameters'* 値(`foo` と `bar`)を Python の `list` として受け取ります。
|
||||
|
||||
そのため、このURLのレスポンスは以下のようになります:
|
||||
|
||||
@@ -179,15 +263,15 @@ http://localhost:8000/items/?q=foo&q=bar
|
||||
|
||||
対話的APIドキュメントは複数の値を許可するために自動的に更新されます。
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/query-params-str-validations/image02.png">
|
||||
<img src="/img/tutorial/query-params-str-validations/image02.png">
|
||||
|
||||
### デフォルト値を持つ、クエリパラメータのリスト / 複数の値
|
||||
### デフォルト値を持つ、クエリパラメータのリスト / 複数の値 { #query-parameter-list-multiple-values-with-defaults }
|
||||
|
||||
また、値が指定されていない場合はデフォルトの`list`を定義することもできます。
|
||||
また、値が指定されていない場合はデフォルトの `list` を定義することもできます。
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial012.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}
|
||||
|
||||
以下のURLを開くと:
|
||||
以下にアクセスすると:
|
||||
|
||||
```
|
||||
http://localhost:8000/items/
|
||||
@@ -204,21 +288,21 @@ http://localhost:8000/items/
|
||||
}
|
||||
```
|
||||
|
||||
#### `list`を使う
|
||||
#### `list` だけを使う { #using-just-list }
|
||||
|
||||
`List[str]`の代わりに直接`list`を使うこともできます:
|
||||
`list[str]` の代わりに直接 `list` を使うこともできます:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013.py hl[7] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}
|
||||
|
||||
/// note | 備考
|
||||
|
||||
この場合、FastAPIはリストの内容をチェックしないことを覚えておいてください。
|
||||
|
||||
例えば`List[int]`はリストの内容が整数であるかどうかをチェックします(そして、文書化します)。しかし`list`だけではそうしません。
|
||||
例えば`list[int]`はリストの内容が整数であるかどうかをチェックします(そして、文書化します)。しかし`list`だけではそうしません。
|
||||
|
||||
///
|
||||
|
||||
## より多くのメタデータを宣言する
|
||||
## より多くのメタデータを宣言する { #declare-more-metadata }
|
||||
|
||||
パラメータに関する情報をさらに追加することができます。
|
||||
|
||||
@@ -234,13 +318,13 @@ http://localhost:8000/items/
|
||||
|
||||
`title`を追加できます:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial007.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
|
||||
|
||||
`description`を追加できます:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial008.py hl[13] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
|
||||
|
||||
## エイリアスパラメータ
|
||||
## エイリアスパラメータ { #alias-parameters }
|
||||
|
||||
パラメータに`item-query`を指定するとします.
|
||||
|
||||
@@ -258,23 +342,91 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
|
||||
それならば、`alias`を宣言することができます。エイリアスはパラメータの値を見つけるのに使用されます:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial009.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
|
||||
|
||||
## 非推奨パラメータ
|
||||
## パラメータを非推奨にする { #deprecating-parameters }
|
||||
|
||||
さて、このパラメータが気に入らなくなったとしましょう
|
||||
さて、このパラメータが気に入らなくなったとしましょう。
|
||||
|
||||
それを使っているクライアントがいるので、しばらくは残しておく必要がありますが、ドキュメントには<abbr title="使わない方がよい">非推奨</abbr>と明記しておきたいです。
|
||||
それを使っているクライアントがいるので、しばらくは残しておく必要がありますが、ドキュメントには<abbr title="obsolete, recommended not to use it - 廃止予定、使用は推奨されません">deprecated</abbr>と明記しておきたいです。
|
||||
|
||||
その場合、`Query`にパラメータ`deprecated=True`を渡します:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial010.py hl[18] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
|
||||
|
||||
ドキュメントは以下のようになります:
|
||||
|
||||
<img src="https://fastapi.tiangolo.com/img/tutorial/query-params-str-validations/image01.png">
|
||||
<img src="/img/tutorial/query-params-str-validations/image01.png">
|
||||
|
||||
## まとめ
|
||||
## OpenAPI からパラメータを除外する { #exclude-parameters-from-openapi }
|
||||
|
||||
生成される OpenAPI スキーマ(つまり自動ドキュメントシステム)からクエリパラメータを除外するには、`Query` のパラメータ `include_in_schema` を `False` に設定します:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
|
||||
|
||||
## カスタムバリデーション { #custom-validation }
|
||||
|
||||
上で示したパラメータではできない **カスタムバリデーション** が必要になる場合があります。
|
||||
|
||||
その場合、通常のバリデーション(例: 値が `str` であることの検証)の後に適用される **カスタムバリデータ関数** を使えます。
|
||||
|
||||
これを行うには、`Annotated` の中で <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">Pydantic の `AfterValidator`</a> を使います。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
Pydantic には <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> などもあります。 🤓
|
||||
|
||||
///
|
||||
|
||||
例えば、このカスタムバリデータは、<abbr title="International Standard Book Number - 国際標準図書番号">ISBN</abbr> の書籍番号なら item ID が `isbn-` で始まること、<abbr title="Internet Movie Database - インターネット・ムービー・データベース: 映画に関する情報を掲載する Web サイト">IMDB</abbr> の movie URL ID なら `imdb-` で始まることをチェックします:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
これは Pydantic バージョン 2 以上で利用できます。 😎
|
||||
|
||||
///
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
データベースや別の API など、何らかの **外部コンポーネント** との通信が必要なタイプのバリデーションを行う必要がある場合は、代わりに **FastAPI Dependencies** を使うべきです。これについては後で学びます。
|
||||
|
||||
これらのカスタムバリデータは、リクエストで提供された **同じデータのみ** でチェックできるもの向けです。
|
||||
|
||||
///
|
||||
|
||||
### そのコードを理解する { #understand-that-code }
|
||||
|
||||
重要なのは、**`Annotated` の中で関数と一緒に `AfterValidator` を使うこと** だけです。この部分は飛ばしても構いません。 🤸
|
||||
|
||||
---
|
||||
|
||||
ただし、この具体的なコード例が気になっていて、まだ興味が続くなら、追加の詳細を示します。
|
||||
|
||||
#### `value.startswith()` を使う文字列 { #string-with-value-startswith }
|
||||
|
||||
気づきましたか?`value.startswith()` を使う文字列はタプルを受け取れ、そのタプル内の各値をチェックします:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
|
||||
|
||||
#### ランダムなアイテム { #a-random-item }
|
||||
|
||||
`data.items()` で、辞書の各アイテムのキーと値を含むタプルを持つ <dfn title="for ループで繰り返し処理できるもの(list、set など)">反復可能オブジェクト</dfn> を取得します。
|
||||
|
||||
この反復可能オブジェクトを `list(data.items())` で適切な `list` に変換します。
|
||||
|
||||
そして `random.choice()` でその `list` から **ランダムな値** を取得するので、`(id, name)` のタプルを得ます。これは `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")` のようになります。
|
||||
|
||||
次に、そのタプルの **2つの値を代入** して、変数 `id` と `name` に入れます。
|
||||
|
||||
つまり、ユーザーが item ID を提供しなかった場合でも、ランダムな提案を受け取ります。
|
||||
|
||||
...これを **単一のシンプルな1行** で行っています。 🤯 Python が好きになりませんか? 🐍
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
|
||||
|
||||
## まとめ { #recap }
|
||||
|
||||
パラメータに追加のバリデーションとメタデータを宣言することができます。
|
||||
|
||||
@@ -285,12 +437,14 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
* `description`
|
||||
* `deprecated`
|
||||
|
||||
文字列のためのバリデーション:
|
||||
文字列に固有のバリデーション:
|
||||
|
||||
* `min_length`
|
||||
* `max_length`
|
||||
* `regex`
|
||||
* `pattern`
|
||||
|
||||
この例では、`str`の値のバリデーションを宣言する方法を見てきました。
|
||||
`AfterValidator` を使ったカスタムバリデーション。
|
||||
|
||||
この例では、`str` の値のバリデーションを宣言する方法を見てきました。
|
||||
|
||||
数値のような他の型のバリデーションを宣言する方法は次の章を参照してください。
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user