Compare commits

..

9 Commits

Author SHA1 Message Date
Yurii Motov
4eb0b839b9 Fix errors found by translation fixer tool 2026-01-20 11:13:27 +01:00
Motov Yurii
99e1367663 Merge branch 'master' into translate-ja-update-outdated-60349fbc 2026-01-20 12:19:56 +03:00
Yurii Motov
e731f1063e Add language codes to links in index.md and project-generation.md by translation fixer tool 2026-01-07 15:33:32 +01:00
Yurii Motov
98512651f8 Enable ja language in docs 2026-01-07 15:30:03 +01:00
Yurii Motov
6f11a9d390 Merge remote-tracking branch 'upstream/master' into translate-ja-update-outdated-60349fbc 2026-01-07 15:24:50 +01:00
Yurii Motov
61b4ade71e Update index.md to reflect latest changes 2025-12-26 11:22:32 +01:00
Yurii Motov
f5e53c0a49 Merge remote-tracking branch 'upstream/master' into translate-ja-update-outdated-60349fbc 2025-12-26 11:18:06 +01:00
github-actions[bot]
d6b46c0a38 🎨 Auto format 2025-12-21 18:13:50 +00:00
github-actions[bot]
a14afc3241 🌐 Update translations for ja (update-outdated) 2025-12-21 18:13:20 +00:00
95 changed files with 4460 additions and 2988 deletions

View File

@@ -189,7 +189,7 @@ Siehe Abschnitt `### Links` im allgemeinen Prompt in `scripts/translate.py`.
////
## HTML-„abbr“-Elemente { #html-abbr-elements }
## HTML „abbr“-Elemente { #html-abbr-elements }
//// tab | Test

View File

@@ -56,19 +56,19 @@ from app.routers import items
Die gleiche Dateistruktur mit Kommentaren:
```bash
```
.
├── app # "app" ist ein Python-Package
│   ├── __init__.py # diese Datei macht "app" zu einem "Python-Package"
│   ├── main.py # "main"-Modul, z. B. import app.main
│   ├── dependencies.py # "dependencies"-Modul, z. B. import app.dependencies
│   └── routers # "routers" ist ein "Python-Subpackage"
│   │ ├── __init__.py # macht "routers" zu einem "Python-Subpackage"
│   │ ├── items.py # "items"-Submodul, z. B. import app.routers.items
│   │ └── users.py # "users"-Submodul, z. B. import app.routers.users
│   └── internal # "internal" ist ein "Python-Subpackage"
│   ├── __init__.py # macht "internal" zu einem "Python-Subpackage"
│   └── admin.py # "admin"-Submodul, z. B. import app.internal.admin
├── app # app ist ein Python-Package
│   ├── __init__.py # diese Datei macht app zu einem Python-Package
│   ├── main.py # main-Modul, z. B. import app.main
│   ├── dependencies.py # dependencies-Modul, z. B. import app.dependencies
│   └── routers # routers ist ein Python-Subpackage
│   │ ├── __init__.py # macht routers zu einem Python-Subpackage
│   │ ├── items.py # items-Submodul, z. B. import app.routers.items
│   │ └── users.py # users-Submodul, z. B. import app.routers.users
│   └── internal # internal ist ein Python-Subpackage
│   ├── __init__.py # macht internal zu einem Python-Subpackage
│   └── admin.py # admin-Submodul, z. B. import app.internal.admin
```
## `APIRouter` { #apirouter }
@@ -479,7 +479,7 @@ $ fastapi dev app/main.py
</div>
Und öffnen Sie die Dokumentation unter <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
und öffnen Sie die Dokumentation unter <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Sie sehen die automatische API-Dokumentation, einschließlich der Pfade aller Submodule, mit den richtigen Pfaden (und Präfixen) und den richtigen Tags:

View File

@@ -13,7 +13,7 @@ Create a virtual environment and install the required packages with <a href="htt
<div class="termy">
```console
$ uv sync --extra all
$ uv sync
---> 100%
```
@@ -32,9 +32,9 @@ That way, you don't have to "install" your local version to be able to test ever
/// note | Technical Details
This only happens when you install using `uv sync --extra all` instead of running `pip install fastapi` directly.
This only happens when you install using `uv sync` instead of running `pip install fastapi` directly.
That is because `uv sync --extra all` will install the local version of FastAPI in "editable" mode by default.
That is because `uv sync` will install the local version of FastAPI in "editable" mode by default.
///

View File

@@ -18,12 +18,6 @@ hide:
### Translations
* 🌐 Update translations for de (update-outdated). PR [#14690](https://github.com/fastapi/fastapi/pull/14690) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update LLM prompt for Russian translations. PR [#14733](https://github.com/fastapi/fastapi/pull/14733) by [@YuriiMotov](https://github.com/YuriiMotov).
* 🌐 Update translations for ru (update-outdated). PR [#14693](https://github.com/fastapi/fastapi/pull/14693) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update translations for pt (update-outdated). PR [#14724](https://github.com/fastapi/fastapi/pull/14724) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update Korean LLM prompt. PR [#14740](https://github.com/fastapi/fastapi/pull/14740) by [@hard-coders](https://github.com/hard-coders).
* 🌐 Improve LLM prompt for Turkish translations. PR [#14728](https://github.com/fastapi/fastapi/pull/14728) by [@Kadermiyanyedi](https://github.com/Kadermiyanyedi).
* 🌐 Update portuguese llm-prompt.md. PR [#14702](https://github.com/fastapi/fastapi/pull/14702) by [@ceb10n](https://github.com/ceb10n).
* 🌐 Update LLM prompt instructions file for French. PR [#14618](https://github.com/fastapi/fastapi/pull/14618) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update translations for ko (add-missing). PR [#14699](https://github.com/fastapi/fastapi/pull/14699) by [@tiangolo](https://github.com/tiangolo).

View File

@@ -317,6 +317,8 @@ extra:
name: de - Deutsch
- link: /es/
name: es - español
- link: /ja/
name: ja - 日本語
- link: /ko/
name: ko - 한국어
- link: /pt/

View File

@@ -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 ステータスコード 201Createdを返します。
これを達成するには、 `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 | 注意
の例のように `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` も同です。
///
## OpenAPIAPIドキュメント
## OpenAPIAPI ドキュメント { #openapi-and-api-docs }
ステータスコードとレスポンスを直接返す場合、それらはOpenAPIスキーマ (APIドキュメント) には含まれません。なぜなら、FastAPIは何が返されるのか事前に知ることができないからです。
追加のステータスコードとレスポンスを直接返す場合、それらは OpenAPI スキーマAPI ドキュメントには含まれません。FastAPI には、事前に何が返されるかを知る方法がないからです。
しかし、 [Additional Responses](additional-responses.md){.internal-link target=_blank} を使ってコードの中にドキュメントを書くことができます。
しかし、[Additional Responses](additional-responses.md){.internal-link target=_blank} を使ってコードにドキュメントできます。

View File

@@ -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` パラメータを使用して、*パスオペレーションデコレータ* で使用したい `Response`(例: 任意の `Response` サブクラス)を宣言することもできます。
*path operation関数* から返されるコンテンツは、その `Response` に含まれます。
*パスオペレーション関数* から返されるコンテンツは、その `Response` に含まれます。
そしてもし、`Response` が、`JSONResponse``UJSONResponse` の場合のようにJSONメディアタイプ (`application/json`) ならば、データは *path operationデコレータ* に宣言したPydantic `response_model` により自動的に変換 (もしくはフィルタ) されます。
そしてその `Response` が、`JSONResponse``UJSONResponse` の場合のようにJSONメディアタイプ`application/json`)なら、返すデータは *パスオペレーションデコレータ* に宣言した任意の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` クラスサブクラスをインポートし、*パスオペレーションデコレータ* に宣言します。
{* ../../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_py39.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` を渡す。
* *パスオペレーションデコレータ* のパラメータ `response_class``HTMLResponse` を渡す。
{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *}
{* ../../docs_src/custom_response/tutorial002_py39.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}で見たように、レスポンスを返すことで、*パスオペレーション* の中でレスポンスを直接オーバーライドすることもできます。
上記と同じ例において、 `HTMLResponse` を返すと、このようになります:
{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *}
{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
/// warning | 注意
*path operation関数* から直接返される `Response` は、OpenAPIにドキュメントされず (例えば、 `Content-Type` がドキュメントされない) 、自動的な対話的ドキュメントからも閲覧できません。
*パスオペレーション関数* から直接返される `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の*パスオペレーション*のドキュメント化のためにのみ使用され`Response` はそのまま使用されます。
#### `HTMLResponse` を直接返す
#### `HTMLResponse` を直接返す { #return-an-htmlresponse-directly }
例えば、このようになります:
{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *}
{* ../../docs_src/custom_response/tutorial004_py39.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_py39.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_py39.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_py39.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_py39.py hl[2,9] *}
非同期なジェネレータか通常のジェネレータ・イテレータを受け取り、レスポンスボディをストリームします。
---
{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *}
または、`response_class` パラメータで使用できます:
#### `StreamingResponse` をファイルライクなオブジェクトとともに使う
{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
ファイルライクなオブジェクト (例えば、 `open()` で返されたオブジェクト) がある場合、 `StreamingResponse` に含めて返すことができます。
その場合、*パスオペレーション*関数から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_py39.py hl[2,7,9] *}
### `StreamingResponse` { #streamingresponse }
非同期ジェネレータ、または通常のジェネレータ/イテレータを受け取り、レスポンスボディをストリームします。
{* ../../docs_src/custom_response/tutorial007_py39.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_py39.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`パスオペレーションを宣言しているに注意してください。
///
### `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_py39.py hl[2,10] *}
## デフォルトレスポンスクラス
`response_class` パラメータを使うこともできます:
**FastAPI** クラスのインスタンスか `APIRouter` を生成するときに、デフォルトのレスポンスクラスを指定できます。
{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
定義するためのパラメータは、 `default_response_class`す。
この場合、*パスオペレーション*関数からファイルパスを直接返せます。
以下の例では、 **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_py39.py hl[9:14,17] *}
これまでは次のように返していたものが:
```json
{"message": "Hello World"}
```
...このレスポンスでは次のように返されます:
```json
{
"message": "Hello World"
}
```
もちろん、JSONの整形よりも、これを活用するもっと良い方法が見つかるはずです。 😉
## デフォルトレスポンスクラス { #default-response-class }
**FastAPI** クラスのインスタンス、または `APIRouter` を作成する際に、デフォルトで使用するレスポンスクラスを指定できます。
これを定義するパラメータは `default_response_class` です。
以下の例では、**FastAPI** はすべての*パスオペレーション*で、`JSONResponse` の代わりに `ORJSONResponse` をデフォルトとして使います。
{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
/// tip | 豆知識
前に見たように、 *path operation* の中`response_class` をオーバーライドできます。
これまでと同様に、*パスオペレーション*`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}

View File

@@ -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**の開発のために寄付されています。🎉 😄
また、以降のセクションは、すでにそれを読んでいて、主要な考え方を理解ていることを前提としています。

View File

@@ -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_py39.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_py39.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_py39.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_py39.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_py39.py hl[19:36, 39:40] *}
この例では、Pydanticモデルを一切宣言していません。実際、リクエストボディはJSONとして <abbr title="converted from some plain format, like bytes, into Python objects bytesなどのプレーンな形式からPythonオブジェクトに変換すること">parsed</abbr> されず、直接 `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_py39.py hl[15:20, 22] *}
それでも、デフォルトの統合機能を使っていないにもかかわらず、YAMLで受け取りたいデータのために、Pydanticモデルを使って手動でJSON Schemaを生成しています。
そしてリクエストを直接使い、ボディを `bytes` として抽出します。これは、FastAPIがリクエストペイロードをJSONとしてパースしようとすらしないことを意味します。
その後、コード内でそのYAMLコンテンツを直接パースし、さらに同じPydanticモデルを使ってYAMLコンテンツを検証しています。
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
/// tip | 豆知識
ここでは同じPydanticモデルを再利用しています。
ただし同様に、別の方法で検証することもできます。
///

View File

@@ -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_py39.py hl[1,18] *}
## 備考
## 備考 { #notes }
`Response` を直接返す場合、バリデーションや、変換 (シリアライズ) や、自動ドキュメントは行われません。

View File

@@ -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_py39.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_py39.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_py39.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_py39.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>.

View File

@@ -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を直接(またはSanicFlaskResponderなど別のツールを)使用した場合、データバリデーションとシリアライゼーションをすべて自分で実装する必要があります。そのため、最終的なアプリケーションはFastAPIを使用して構築した場合と同じオーバーヘッドが発生します。そして多くの場合、このデータバリデーションとシリアライゼーションは、アプリケーションで書かれるコードの大部分になります。
* そのため、FastAPIを使用することで、開発時間、バグ、コード行数を節約でき、使用しない場合あなたがそれをすべて自分のコードで実装する必要があるため)と比べて、同じパフォーマンス(またはそれ以上)を得られる可能性があります。
* FastAPIを比較する場合は、Flask-apispec、NestJS、Moltenなどデータバリデーション、シリアライゼーション、ドキュメント化を提供するwebアプリケーションフレームワークまたはツール群と比較してください。自動データバリデーション、シリアライゼーション、ドキュメント化が統合されたフレームワークです。

View File

@@ -1,4 +1,4 @@
# デプロイメントのコンセプト
# デプロイメントのコンセプト { #deployments-concepts }
**FastAPI**を用いたアプリケーションをデプロイするとき、もしくはどのようなタイプのWeb APIであっても、おそらく気になるコンセプトがいくつかあります。
@@ -10,12 +10,12 @@
* 起動時の実行
* 再起動
* レプリケーション(実行中のプロセス数)
* メモリ
* メモリ
* 開始前の事前のステップ
これらが**デプロイメント**にどのような影響を与えるかを見ていきましょう。
最終的な目的は、**安全な方法で**APIクライアントに**サービスを提供**し、**中断を回避**するだけでなく、**計算リソース**(例えばリモートサーバー/仮想マシン)を可能な限り効率的に使用することです。🚀
最終的な目的は、**安全な方法で**APIクライアントに**サービスを提供**し、**中断を回避**するだけでなく、**計算リソース**(例えばリモートサーバー/仮想マシン)を可能な限り効率的に使用することです。 🚀
この章では前述した**コンセプト**についてそれぞれ説明します。
@@ -27,16 +27,16 @@
しかし、今はこれらの重要な**コンセプトに基づくアイデア**を確認しましょう。これらのコンセプトは、他のどのタイプの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 +59,11 @@ TLS Termination Proxyとして使用できるツールには以下のような
次に考慮すべきコンセプトは、実際のAPIを実行するプログラムUvicornに関連するものすべてです。
## プログラム と プロセス
## プログラム と プロセス { #program-and-process }
私たちは「**プロセス**」という言葉についてたくさん話すので、その意味や「**プログラム**」という言葉との違いを明確にしておくと便利です。
### プログラムとは何か
### プログラムとは何か { #what-is-a-program }
**プログラム**という言葉は、一般的にいろいろなものを表現するのに使われます:
@@ -71,7 +71,7 @@ TLS Termination Proxyとして使用できるツールには以下のような
* OSによって実行することができるファイル例: `python`, `python.exe` or `uvicorn`
* OS上で**実行**している間、CPUを使用し、メモリ上に何かを保存する特定のプログラム**プロセス**とも呼ばれる)
### プロセスとは何か
### プロセスとは何か { #what-is-a-process }
**プロセス**という言葉は通常、より具体的な意味で使われ、OSで実行されているものだけを指します先ほどの最後の説明のように
@@ -92,27 +92,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 +129,33 @@ OSの「タスク・マネージャー」や「システム・モニター」
次の章で、より具体的な例を挙げていきます。
## 再起動
## 再起動 { #restarts }
起動時にアプリケーションが実行されることを確認するのと同様に、失敗後にアプリケーションが**再起動**されることも確認したいと思われます。
### 我々は間違いを犯す
### 我々は間違いを犯す { #we-make-mistakes }
私たち人間は常に**間違い**を犯します。ソフトウェアには、ほとんど常に**バグ**があらゆる箇所に隠されています。🐛
### 小さなエラーは自動的に処理される
そして私たち開発者は、それらのバグを見つけたり新しい機能を実装したりしながらコードを改善し続けます(新しいバグも追加してしまうかもしれません😅)。
### 小さなエラーは自動的に処理される { #small-errors-automatically-handled }
FastAPIでWeb APIを構築する際に、コードにエラーがある場合、FastAPIは通常、エラーを引き起こした単一のリクエストにエラーを含めます。🛡
クライアントはそのリクエストに対して**500 Internal Server Error**を受け取りますが、アプリケーションは完全にクラッシュするのではなく、次のリクエストのために動作を続けます。
### 重大なエラー - クラッシュ
### 重大なエラー - クラッシュ { #bigger-errors-crashes }
しかしながら、**アプリケーション全体をクラッシュさせるようなコードを書いて**UvicornとPythonをクラッシュさせるようなケースもあるかもしれません。💥
それでも、ある箇所でエラーが発生したからといって、アプリケーションを停止させたままにしたくないでしょう。 少なくとも壊れていない*パスオペレーション*については、**実行し続けたい**はずです。
### クラッシュ後の再起動
### クラッシュ後の再起動 { #restart-after-crash }
しかし、実行中の**プロセス**をクラッシュさせるような本当にひどいエラーの場合、少なくとも2〜3回ほどプロセスを**再起動**させる外部コンポーネントが必要でしょう。
/// tip
/// tip | 豆知識
...とはいえ、アプリケーション全体が**すぐにクラッシュする**のであれば、いつまでも再起動し続けるのは意味がないでしょう。しかし、その場合はおそらく開発中か少なくともデプロイ直後に気づくと思われます。
@@ -161,7 +165,7 @@ FastAPIでWeb APIを構築する際に、コードにエラーがある場合、
あなたはおそらく**外部コンポーネント**がアプリケーションの再起動を担当することを望むと考えます。 なぜなら、その時点でUvicornとPythonを使った同じアプリケーションはすでにクラッシュしており、同じアプリケーションの同じコードに対して何もできないためです。
### 自動的に再起動するツールの例
### 自動的に再起動するツールの例 { #example-tools-to-restart-automatically }
ほとんどの場合、前述した**起動時にプログラムを実行する**ために使用されるツールは、自動で**再起動**することにも利用されます。
@@ -176,19 +180,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ワーカー**と呼ばれます。
### ワーカー・プロセス と ポート
### ワーカー・プロセス と ポート { #worker-processes-and-ports }
<!-- NOTE: https.md written in Japanese does not exist, so it redirects to English one -->
[HTTPSについて](https.md){.internal-link target=_blank}のドキュメントで、1つのサーバーで1つのポートとIPアドレスの組み合わせでリッスンできるのは1つのプロセスだけであることを覚えていますでしょうか
@@ -197,13 +201,13 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
そのため、**複数のプロセス**を同時に持つには**ポートでリッスンしている単一のプロセス**が必要であり、それが何らかの方法で各ワーカー・プロセスに通信を送信することが求められます。
### プロセスあたりのメモリ
### プロセスあたりのメモリ { #memory-per-process }
さて、プログラムがメモリにロードする際には、例えば機械学習モデルや大きなファイルの内容を変数に入れたりする場合では、**サーバーのメモリRAM**を少し消費します。
そして複数のプロセスは通常、**メモリを共有しません**。これは、実行中の各プロセスがそれぞれ独自の変数やメモリ等を持っていることを意味します。つまり、コード内で大量のメモリを消費している場合、**各プロセス**は同等の量のメモリを消費することになります。
### サーバーメモリ
### サーバーメモリ { #server-memory }
例えば、あなたのコードが **1GBのサイズの機械学習モデル**をロードする場合、APIで1つのプロセスを実行すると、少なくとも1GBのRAMを消費します。
@@ -211,7 +215,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
リモートサーバーや仮想マシンのRAMが3GBしかない場合、4GB以上のRAMをロードしようとすると問題が発生します。🚨
### 複数プロセス - 例
### 複数プロセス - 例 { #multiple-processes-an-example }
この例では、2つの**ワーカー・プロセス**を起動し制御する**マネージャー・ プロセス**があります。
@@ -227,7 +231,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
毎回同程度の計算を行うAPIがあり、多くのクライアントがいるのであれば、**CPU使用率**もおそらく**安定**するでしょう(常に急激に上下するのではなく)。
### レプリケーション・ツールと戦略の例
### レプリケーション・ツールと戦略の例 { #examples-of-replication-tools-and-strategies }
これを実現するにはいくつかのアプローチがありますが、具体的な戦略については次の章(Dockerやコンテナの章など)で詳しく説明します。
@@ -237,25 +241,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 +272,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
もちろん、事前のステップを何度も実行しても問題がない場合もあり、その際は対処がかなり楽になります。
/// tip
/// tip | 豆知識
また、セットアップによっては、アプリケーションを開始する前の**事前のステップ**が必要ない場合もあることを覚えておいてください。
@@ -279,7 +280,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
///
### 事前ステップの戦略例
### 事前ステップの戦略例 { #examples-of-previous-steps-strategies }
これは**システムを**デプロイする方法に**大きく依存**するだろうし、おそらくプログラムの起動方法や再起動の処理などにも関係してくるでしょう。
@@ -289,14 +290,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 +319,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
`htop`のような単純なツールを使って、サーバーで使用されているCPUやRAM、あるいは各プロセスで使用されている量を見ることができます。あるいは、より複雑な監視ツールを使って、サーバに分散して使用することもできます。
## まとめ
## まとめ { #recap }
アプリケーションのデプロイ方法を決定する際に、考慮すべきであろう主要なコンセプトのいくつかを紹介していきました:
@@ -327,7 +327,7 @@ FastAPI アプリケーションでは、Uvicorn のようなサーバープロ
* 起動時の実行
* 再起動
* レプリケーション(実行中のプロセス数)
* メモリ
* メモリ
* 開始前の事前ステップ
これらの考え方とその適用方法を理解することで、デプロイメントを設定したり調整したりする際に必要な直感的な判断ができるようになるはずです。🤓

View File

@@ -1,20 +1,17 @@
# コンテナ内の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
@@ -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,20 +127,18 @@ 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` を作成します
@@ -174,28 +162,28 @@ def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
### Dockerfile
### Dockerfile { #dockerfile }
同じプロジェクト・ディレクトリに`Dockerfile`というファイルを作成します:
```{ .dockerfile .annotate }
# (1)
# (1)!
FROM python:3.9
# (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 +199,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 +214,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 +275,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,7 +317,7 @@ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
```
### Dockerイメージをビルドする
### Dockerイメージをビルドする { #build-the-docker-image }
すべてのファイルが揃ったので、コンテナ・イメージをビルドしましょう。
@@ -317,7 +334,7 @@ $ docker build -t myimage .
</div>
/// tip
/// tip | 豆知識
末尾の `.` に注目してほしいです。これは `./` と同じ意味です。 これはDockerにコンテナイメージのビルドに使用するディレクトリを指示します。
@@ -325,7 +342,7 @@ $ docker build -t myimage .
///
### Dockerコンテナの起動する
### Dockerコンテナの起動する { #start-the-docker-container }
* イメージに基づいてコンテナを実行します:
@@ -337,7 +354,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 +364,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 +372,7 @@ Dockerコンテナの<a href="http://192.168.99.100/items/5?q=somequery" class="
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
## 代替の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 +380,10 @@ Dockerコンテナの<a href="http://192.168.99.100/items/5?q=somequery" class="
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## 単一ファイルのFastAPIでDockerイメージをビルドする
## 単一ファイルのFastAPIでDockerイメージをビルドする { #build-a-docker-image-with-a-single-file-fastapi }
FastAPI が単一のファイル、例えば `./app` ディレクトリのない `main.py` の場合、ファイル構造は次のようになります:
```
.
├── Dockerfile
@@ -384,43 +402,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 +446,7 @@ TraefikはDockerやKubernetesなどと統合されているので、コンテナ
あるいは、コンテナ内でアプリケーションを実行しながらクラウド・プロバイダーがサービスの1つとしてHTTPSを処理することもできます。
## 起動時および再起動時の実行
## 起動時および再起動時の実行 { #running-on-startup-and-restarts }
通常、コンテナの**起動と実行**を担当する別のツールがあります。
@@ -438,21 +456,21 @@ TraefikはDockerやKubernetesなどと統合されているので、コンテナ
コンテナを使わなければ、アプリケーションを起動時や再起動時に実行させるのは面倒で難しいかもしれません。しかし、**コンテナ**で作業する場合、ほとんどのケースでその機能はデフォルトで含まれています。✨
## レプリケーション - プロセス数
## レプリケーション - プロセス数 { #replication-number-of-processes }
**Kubernetes** や Docker Swarm モード、Nomad、あるいは複数のマシン上で分散コンテナを管理するための同様の複雑なシステムを使ってマシンの<abbr title="何らかの方法で接続され、一緒に動作するように構成されたマシンのグループ">クラスター</abbr>を構成している場合、 各コンテナでWorkerを持つGunicornのような**プロセスマネージャ**を使用する代わりに、**クラスター・レベル**で**レプリケーション**を処理したいと思うでしょう。
**Kubernetes** や Docker Swarm モード、Nomad、あるいは複数のマシン上で分散コンテナを管理するための同様の複雑なシステムを使ってマシンの<abbr title="A group of machines that are configured to be connected and work together in some way.">cluster</abbr>を構成している場合、 各コンテナで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 +478,7 @@ HTTPSに使われるものと同じ**TLS Termination Proxy**コンポーネン
そしてコンテナで作業する場合、コンテナの起動と管理に使用する同じシステムには、**ロードバランサー****TLS Termination Proxy**の可能性もある)から**ネットワーク通信**HTTPリクエストなどをアプリのあるコンテナ複数可に送信するための内部ツールが既にあるはずです。
### 1つのロードバランサー - 複数のワーカーコンテナー
### 1つのロードバランサー - 複数のワーカーコンテナー { #one-load-balancer-multiple-worker-containers }
**Kubernetes**や同様の分散コンテナ管理システムで作業する場合、その内部のネットワーキングのメカニズムを使用することで、メインの**ポート**でリッスンしている単一の**ロードバランサー**が、アプリを実行している可能性のある**複数のコンテナ**に通信(リクエスト)を送信できるようになります。
@@ -470,56 +488,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.9
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 +554,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 +606,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キャッシュ**内の命令の**順番**に注意することで、**ビルド時間を最小化**、生産性を最大化できます(そして退屈を避けることができます)。😎

View File

@@ -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アドレス**を持つことになるでしょう。
おそらくクラウドサーバー(仮想マシン)かそれに類するものを手に入れ、<abbr title="That doesn't change 変わらない">fixed</abbr> **パブリック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接続を確立するためのクライアントとサーバー間のこの
TLSHTTPSはデフォルトで`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** をセットアップする方法について、いくつかの具体例を紹介します。🔒

View File

@@ -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 アプリケーションにも当てはまります)。
次のセクションでは、留意すべき点の詳細や、それを実現するためのいくつかの手法を確認します。 ✨

View File

@@ -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** について学びましょう。これらのツールにも、他の**デプロイメントのコンセプト**を解決する簡単な方法があることがわかります。

View File

@@ -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
```

View File

@@ -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> を参照してください。
///
## 型とバリデーション
## 型とバリデーション { #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`**という**特別な**環境変数があります。この環境変数は、OSLinux、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 for Environment Variable</a> 参照してください。
環境変数の用途や適用方法が最初は直感的ではないかもしれませんが、開発中のさまざまなシナリオで繰り返し登場します。そのため、基本を知っておくことが重要です
多くの場合、環境変数がどのように役立ち、すぐに適用できるのかはあまり明確ではありません。しかし、開発中のさまざまなシナリオで何度も登場するため、知っておくとよいでしょう
たとえば、この情報は次のセクションで扱う[Virtual Environments](virtual-environments.md)にも関連します。
えば、次のセクション[Virtual Environments](virtual-environments.md)でこの情報が必要になります。

View File

@@ -1,8 +1,8 @@
# 条件付き OpenAPI
# 条件付き OpenAPI { #conditional-openapi }
必要であれば、設定と環境変数を利用して、環境に応じて条件付きでOpenAPIを構成することが可能です。また、完全にOpenAPIを無効にすることもできます。
## セキュリティとAPI、およびドキュメントについて
## セキュリティとAPI、およびドキュメントについて { #about-security-apis-and-docs }
本番環境においてドキュメントのUIを非表示にすることによって、APIを保護しようと *すべきではありません*
@@ -17,19 +17,19 @@
* リクエストボディとレスポンスのための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_py39.py hl[6,11] *}
ここでは `openapi_url` の設定を、デフォルトの `"/openapi.json"` のまま宣言しています。

View File

@@ -1,11 +1,11 @@
# 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>
@@ -27,131 +27,142 @@
---
**ドキュメント**: <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% 削減します。*
* **直感的**: 素晴らしいエディタサポート。あらゆる場所で <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 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 typing import Union
from fastapi import FastAPI
app = FastAPI()
@@ -163,16 +174,18 @@ def read_root():
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
def read_item(item_id: int, q: Union[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="9 14"
from typing import Union
```Python hl_lines="7 12"
from fastapi import FastAPI
app = FastAPI()
@@ -184,28 +197,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: Union[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 +239,58 @@ 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> が提供しています
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### 代替 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> が提供しています
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## アップグレード例
## アップグレード例 { #example-upgrade }
`PUT`リクエストからボディを受け取るために`main.py`を修正しましょう。
次に、`PUT` リクエストからボディを受け取るために `main.py` ファイルを修正しましょう。
Pydantic によって、Python の標準的な型を使ってボディを宣言します。
Pydantic によって、標準的な Python の型を使ってボディを宣言します。
```Python hl_lines="4 9-12 25-27"
from typing import Union
```Python hl_lines="2 7 8 9 10 23 24 25"
from fastapi import FastAPI
from pydantic import BaseModel
@@ -272,7 +300,7 @@ app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: bool = None
is_offer: Union[bool, None] = None
@app.get("/")
@@ -281,7 +309,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: Union[str, None] = None):
return {"item_id": item_id, "q": q}
@@ -290,173 +318,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 ドキュメント新しいボディも含めて自動でアップデートされます
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
- "Try it out"ボタンをクリックしてください。パラメータを入力して API と直接やりとりすることができます:
* 「Try it outボタンをクリックします。パラメータを入力して API と直接やりとりできます
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)
- それから、"Execute" ボタンをクリックしてください。 ユーザーインターフェースは API と通信し、パラメータを送信し、結果を取得して画面に表示します:
* 次に、「Executeボタンをクリックします。ユーザーインターフェースは API と通信し、パラメータを送信し、結果を取得して画面に表示します
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### 代替 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 ドキュメントにも新しいクエリパラメータやボディが反映されます。
* 代替のドキュメントにも新しいクエリパラメータやボディが反映されます。
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### まとめ
### まとめ { #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 オブジェクトでも検証が可能です。
* 入力データの <abbr title="also known as: serialization, parsing, marshalling">変換</abbr>: ネットワークから Python のデータや型へ。以下から読み取ります:
* JSON
* パスパラメータ
* クエリパラメータ
* Cookie。
* ヘッダー
* フォーム
* ファイル
* 出力データの <abbr title="also known as: serialization, parsing, marshalling">変換</abbr>: 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 ...
```
...そして、エディタが属性を自動補完し、そのタイプを知る方法を確認してください。:
...に変更し、エディタが属性を自動補完し、そのを知ることを確認してください。
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
より多くの機能を含む、より完全な例については、<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` のような **検証制約** を設定する方法。
* 非常に強力で使いやすい **<abbr title="also known as components, resources, providers, services, injectables">依存性注入</abbr>** システム。
* **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 と UvicornFastAPI で内部的に使用されています)にのみ下回っていると示されています。
必要に応じて 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 と UvicornFastAPI で内部的に使用されています)にのみ下回っていると示されています。(*
詳細は <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()` とともに、フォームの <abbr title="converting the string that comes from an HTTP request into Python data">parsing</abbr> をサポートしたい場合必要です。
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 ライセンスの条項の下でライセンスされています。

View File

@@ -1,5 +1,5 @@
# 学習
# 学習 { #learn }
ここでは、**FastAPI** を学習するための入門セクションとチュートリアルを紹介します。
これは、FastAPIを学習するにあたっての**書籍**や**コース**であり、**公式**かつ推奨される方法とみなすことができます 😎
これは、**書籍**や**コース**、FastAPIを学習するための**公式**かつ推奨される方法とみなすことができます😎

View File

@@ -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)
- 🔒 デフォルトでの安全なパスワードハッシュ化
- 🔑 JWTJSON Web Token認証
- 📫 メールベースのパスワードリカバリ
- ✅ [Pytest](https://pytest.org) によるテスト
- 📞 リバースプロキシ / ロードバランサとしての [Traefik](https://traefik.io)
- 🚢 Docker Composeを使用したデプロイ手順自動HTTPS証明書を処理するフロントエンドTraefikプロキシのセットアップ方法を含む
- 🏭 GitHub Actionsに基づくCIcontinuous integrationとCDcontinuous deployment

View File

@@ -1,16 +1,16 @@
# Pythonの型の紹介
# Pythonの型の紹介 { #python-types-intro }
**Python 3.6以降** では「型ヒント」オプションがサポートされています。
Pythonではオプションの「型ヒント」(「型アノテーション」とも呼ばれます)がサポートされています。
これらの **"型ヒント"** 変数の<abbr title=": str, int, float, bool">型</abbr>を宣言することができる新しい構文です。Python 3.6以降)
これらの **型ヒント** またはアノテーションは、変数の<abbr title="for example: str, int, float, bool">型</abbr>を宣言できる特別な構文です。
変数に型を宣言することでエディターやツールがより良いサポートを提供することができます。
変数に型を宣言することでエディターやツールがより良いサポートを提供できます。
こではPythonの型ヒントについての **クイックチュートリアル/リフレッシュ** で、**FastAPI**でそれらを使用するために必要な最低限のことだけをカバーしています。...実際には本当に少ないです。
はPythonの型ヒントについての **クイックチュートリアル/リフレッシュ** にすぎません。**FastAPI** で使用するために必要な最低限のことだけをカバーしています。...実際には本当に少ないです。
**FastAPI** はすべてこれらの型ヒントに基づいており、多くの強みと利点を与えてくれます。
しかしたとえまったく **FastAPI** を使用しない場合でも、それらについて少し学ぶことで利点を得ることができるでしょう
しかしたとえ **FastAPI**まったく使用しない場合でも、それらについて少し学ぶことで利点を得られます
/// note | 備考
@@ -18,14 +18,13 @@
///
## 動機
## 動機 { #motivation }
簡単な例から始めてみましょう:
{* ../../docs_src/python_types/tutorial001.py *}
{* ../../docs_src/python_types/tutorial001_py39.py *}
このプログラムを実行すると以下が出力されます:
このプログラムを呼び出すと、以下が出力されます:
```
John Doe
@@ -35,12 +34,11 @@ John Doe
* `first_name``last_name`を取得します。
* `title()`を用いて、それぞれの最初の文字を大文字に変換します。
* 真ん中にスペースを入れて<abbr title="次から次へと中身を入れて一つにまとめる">連結</abbr>します。
* 真ん中にスペースを入れて<abbr title="Puts them together, as one. With the contents of one after the other.">連結</abbr>します。
{* ../../docs_src/python_types/tutorial001.py hl[2] *}
{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
### 編集
### 編集 { #edit-it }
これはとても簡単なプログラムです。
@@ -50,7 +48,7 @@ John Doe
しかし、そうすると「最初の文字を大文字に変換するあのメソッド」を呼び出す必要があります。
それは`upper`でしたか?`uppercase`でしたか?それとも`first_uppercase`または`capitalize`
それは`upper`でしたか?`uppercase`でしたか?`first_uppercase``capitalize`
そして、古くからプログラマーの友人であるエディタで自動補完を試してみます。
@@ -58,13 +56,13 @@ John Doe
しかし、悲しいことに、これはなんの役にも立ちません:
<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_py39.py hl[1] *}
これは、以下のようにデフォルト値を宣言するのと同じではありません:
@@ -95,41 +92,39 @@ John Doe
そして、通常、型ヒントを追加しても、それらがない状態と起こることは何も変わりません。
しかし今、あなたが再びその関数を作成している最中に、型ヒントを使っていると想像してみてさい。
しかし今、あなたが再びその関数を作成している最中に、型ヒントを使っていると想像してみてください。
同じタイミングで`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_py39.py hl[1] *}
エディタは変数の型を知っているので、補完だけでなく、エラーチェックをすることもできます:
エディタは変数の型を知っているので、補完だけでなく、エラーチェックをすることもできます。
<img src="https://fastapi.tiangolo.com/img/python-types/image04.png">
<img src="/img/python-types/image04.png">
これで`age``str(age)`で文字列に変換して修正する必要があることがわかります:
{* ../../docs_src/python_types/tutorial004.py hl[2] *}
{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
## 型の宣言 { #declaring-types }
## 型の宣言
関数のパラメータとして、型ヒントを宣言している主な場所を確認しました。
型ヒントを宣言する主な場所を見てきました。関数のパラメータです。
これは **FastAPI** で使用する主な場所でもあります。
### 単純な型
### 単純な型 { #simple-types }
`str`だけでなく、Pythonの標準的な型すべてを宣言することができます。
`str`だけでなく、Pythonの標準的な型すべてを宣言できます。
例えば、以下を使用可能です:
@@ -138,40 +133,47 @@ John Doe
* `bool`
* `bytes`
{* ../../docs_src/python_types/tutorial005.py hl[1] *}
{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
### 型パラメータを持つジェネリック型 { #generic-types-with-type-parameters }
### 型パラメータを持つジェネリック型
データ構造の中には、`dict``list``set``tuple`のように他の値を含むことができるものがあります。また内部の値も独自の型を持つことができます。
データ構造の中には、`dict``list``set`、そして`tuple`のように他の値を含むことができるものがあります。また内部の値も独自の型を持つことができます。
内部の型を持つこれらの型は「**generic**」型と呼ばれます。そして、内部の型も含めて宣言することが可能です。
これらの型や内部の型を宣言するには、Pythonの標準モジュール`typing`を使用ます。
これらの型や内部の型を宣言するには、Pythonの標準モジュール`typing`を使用できます。これらの型ヒントをサポートするために特別に存在しています。
これらの型ヒントをサポートするために特別に存在しています。
#### 新しいPythonバージョン { #newer-versions-of-python }
#### `List`
`typing`を使う構文は、Python 3.6から最新バージョンまでPython 3.9、Python 3.10などを含む)すべてのバージョンと **互換性** があります。
Pythonが進化するにつれ、**新しいバージョン** ではこれらの型アノテーションへのサポートが改善され、多くの場合、型アノテーションを宣言するために`typing`モジュールをインポートして使う必要すらなくなります。
プロジェクトでより新しいPythonバージョンを選べるなら、その追加のシンプルさを活用できます。
ドキュメント全体で、Pythonの各バージョンと互換性のある例差分がある場合を示しています。
例えば「**Python 3.6+**」はPython 3.6以上3.7、3.8、3.9、3.10などを含む)と互換性があることを意味します。また「**Python 3.9+**」はPython 3.9以上3.10などを含む)と互換性があることを意味します。
**最新のPythonバージョン** を使えるなら、最新バージョン向けの例を使ってください。例えば「**Python 3.10+**」のように、それらは **最良かつ最もシンプルな構文** になります。
#### List { #list }
例えば、`str``list`の変数を定義してみましょう。
`typing`から`List`をインポートします(大文字の`L`を含む):
同じコロン(`:`)の構文で変数を宣言します。
{* ../../docs_src/python_types/tutorial006.py hl[1] *}
型として、`list`を指定します。
リストはいくつかの内部の型を含む型なので、それらを角括弧で囲みます:
同じようにコロン(`:`)の構文で変数を宣言します。
{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
型として、`List`を入力します。
リストはいくつかの内部の型を含む型なので、それらを角括弧で囲んでいます。
{* ../../docs_src/python_types/tutorial006.py hl[4] *}
/// tip | 豆知識
/// info | 情報
角括弧内の内部の型は「型パラメータ」と呼ばれています。
この場合、`str``List`に渡される型パラメータです。
この場合、`str``list`に渡される型パラメータです。
///
@@ -179,86 +181,203 @@ John Doe
そうすることで、エディタはリストの項目を処理している間にもサポートを提供できます。
<img src="https://fastapi.tiangolo.com/img/python-types/image05.png">
<img src="/img/python-types/image05.png">
タイプがなければ、それはほぼ不可能です。
がなければ、それはほぼ不可能です。
変数`item`はリスト`items`の要素の一つであることに注意してください。
それでも、エディタはそれが`str`であることを知っていて、そのためのサポートを提供しています。
#### `Tuple``Set`
#### Tuple と Set { #tuple-and-set }
`tuple``set`の宣言も同様です:
{* ../../docs_src/python_types/tutorial007.py hl[1,4] *}
{* ../../docs_src/python_types/tutorial007_py39.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`の値です
{* ../../docs_src/python_types/tutorial008.py hl[1,4] *}
2番目の型パラメータは`dict`の値です:
{* ../../docs_src/python_types/tutorial008_py39.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!}
Python 3.6以上Python 3.10を含む)では、`typing``Union`型を使い、角括弧の中に受け付ける可能性のある型を入れられます。
Python 3.10では、受け付ける可能性のある型を<abbr title='also called "bitwise or operator", but that meaning is not relevant here'>縦棒(`|`</abbr>で区切って書ける **新しい構文** もあります。
//// tab | Python 3.10+
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
ただの`str`の代わりに`Optional[str]`を使用することで、エディタは値が常に`str`であると仮定している場合に実際には`None`である可能性があるエラーを検出するのに役立ちます。
////
#### ジェネリック型
//// tab | Python 3.9+
以下のように角括弧で型パラメータを取る型を:
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial008b_py39.py!}
```
* `List`
* `Tuple`
* `Set`
* `Dict`
////
どちらの場合も、`item`は`int`または`str`になり得ることを意味します。
#### `None`の可能性 { #possibly-none }
値が`str`のような型を持つ可能性がある一方で、`None`にもなり得ることを宣言できます。
Python 3.6以上Python 3.10を含む)では、`typing`モジュールから`Optional`をインポートして使うことで宣言できます。
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009_py39.py!}
```
ただの`str`の代わりに`Optional[str]`を使用することで、値が常に`str`であると仮定しているときに、実際には`None`である可能性もあるというエラーをエディタが検出するのに役立ちます。
`Optional[Something]`は実際には`Union[Something, None]`のショートカットで、両者は等価です。
これは、Python 3.10では`Something | None`も使えることを意味します:
//// tab | Python 3.10+
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial009_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009_py39.py!}
```
////
//// tab | Python 3.9+ alternative
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009b_py39.py!}
```
////
#### `Union`または`Optional`の使用 { #using-union-or-optional }
Python 3.10未満のバージョンを使っている場合、これは私のとても **主観的** な観点からのヒントです:
* 🚨 `Optional[SomeType]`は避けてください
* 代わりに ✨ **`Union[SomeType, None]`を使ってください** ✨
どちらも等価で、内部的には同じですが、`Optional`より`Union`をおすすめします。というのも「**optional**」という単語は値がオプションであることを示唆するように見えますが、実際には「`None`になり得る」という意味であり、オプションではなく必須である場合でもそうだからです。
`Union[SomeType, None]`のほうが意味がより明示的だと思います。
これは言葉や名前の話にすぎません。しかし、その言葉はあなたやチームメイトがコードをどう考えるかに影響し得ます。
例として、この関数を見てみましょう:
{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
パラメータ`name`は`Optional[str]`として定義されていますが、**オプションではありません**。そのパラメータなしで関数を呼び出せません:
```Python
say_hi() # Oh, no, this throws an error! 😱
```
`name`パラメータはデフォルト値がないため、**依然として必須***optional*ではない)です。それでも、`name`は値として`None`を受け付けます:
```Python
say_hi(name=None) # This works, None is valid 🎉
```
良い知らせとして、Python 3.10になればその心配は不要です。型のユニオンを定義するために`|`を単純に使えるからです:
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
そして、`Optional`や`Union`のような名前について心配する必要もなくなります。😎
#### ジェネリック型 { #generic-types }
角括弧で型パラメータを取るこれらの型は、例えば次のように **Generic types** または **Generics** と呼ばれます:
//// tab | Python 3.10+
同じ組み込み型をジェネリクスとして(角括弧と内部の型で)使えます:
* `list`
* `tuple`
* `set`
* `dict`
また、これまでのPythonバージョンと同様に、`typing`モジュールから:
* `Union`
* `Optional`
* ...など
* ...and others.
**ジェネリック型** または **ジェネリクス** と呼びます。
Python 3.10では、ジェネリクスの`Union`や`Optional`を使う代替として、型のユニオンを宣言するために<abbr title='also called "bitwise or operator", but that meaning is not relevant here'>縦棒(`|`</abbr>を使えます。これはずっと良く、よりシンプルです。
### 型としてのクラス
////
//// tab | Python 3.9+
同じ組み込み型をジェネリクスとして(角括弧と内部の型で)使えます:
* `list`
* `tuple`
* `set`
* `dict`
そして`typing`モジュールのジェネリクス:
* `Union`
* `Optional`
* ...and others.
////
### 型としてのクラス { #classes-as-types }
変数の型としてクラスを宣言することもできます。
例えば、`Person`クラスという名前のクラスがあるとしましょう:
名前を持つ`Person`クラスがあるとしましょう:
{* ../../docs_src/python_types/tutorial010.py hl[1,2,3] *}
{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
変数を`Person`型として宣言できます:
変数の型を`Person`として宣言することができます:
{* ../../docs_src/python_types/tutorial010.py hl[6] *}
{* ../../docs_src/python_types/tutorial010_py39.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`の**インスタンス**である」ことを意味します。
「`one_person`は`Person`という名前の**クラス**である」という意味ではありません。
## Pydanticのモデル { #pydantic-models }
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> はデータ検証を行うためのPythonライブラリです。
@@ -266,18 +385,17 @@ John Doe
そして、それぞれの属性は型を持ちます。
さらに、いくつかの値を持つクラスのインスタンスを作成すると、その値を検証し、適切な型に変換して(もしそうであれば)てのデータを持つオブジェクトを提供してくれます。
さらに、いくつかの値を持つクラスのインスタンスを作成すると、その値を検証し、適切な型に変換して(もしそうであれば)すべてのデータを持つオブジェクトを提供してくれます。
また、その結果のオブジェクトですべてのエディタのサポートを受けることができます。
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>
///
@@ -285,30 +403,62 @@ Pydanticについてより学びたい方は<a href="https://docs.pydantic.dev/"
すべてのことは[チュートリアル - ユーザーガイド](tutorial/index.md){.internal-link target=_blank}で実際に見ることができます。
## **FastAPI**での型ヒント
/// tip | 豆知識
Pydanticには、デフォルト値なしで`Optional`または`Union[Something, None]`を使った場合の特別な挙動があります。詳細はPydanticドキュメントの<a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">Required Optional fields</a>を参照してください。
///
## メタデータアノテーション付き型ヒント { #type-hints-with-metadata-annotations }
Pythonには、`Annotated`を使って型ヒントに**追加の<abbr title="Data about the data, in this case, information about the type, e.g. a description.">メタデータ</abbr>**を付与できる機能もあります。
Python 3.9以降、`Annotated`は標準ライブラリの一部なので、`typing`からインポートできます。
{* ../../docs_src/python_types/tutorial013_py39.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}で見ることができます。
重要なのは、Pythonの標準的な型を使うことで、クラスやデコレータなどを追加するのではなくつの場所で **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>があります。
///

View File

@@ -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_py39.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_py39.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_py39.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`インポートして使用し、バックグラウンドタスクを追加して下さい。

View File

@@ -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`を使用して、モデルの属性に追加のバリデーションやメタデータを宣言することができます。

View File

@@ -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モデルであるつのパラメータがあることに気付きます。
そのため、パラメータ名をボディのキー(フィールド名)として使用し、以下のようなボディを期待しています:
この場合、**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,48 @@
繰り返しになりますが、データ型の変換、検証、文書化などを行います。
## 複数のボディパラメータとクエリ
## 複数のボディパラメータとクエリ { #multiple-body-params-and-query }
もちろん、ボディパラメータに加えて、必要に応じて追加のクエリパラメータを宣言することもできます。
デフォルトでは、単数値はクエリパラメータとして解釈されるので、明示的に `Query` を追加する必要はありません。
デフォルトでは、単数値はクエリパラメータとして解釈されるので、明示的に `Query` を追加する必要はなく、次のようにできます:
```Python
q: str = None
q: Union[str, None] = None
```
以下において:
またはPython 3.10以上では:
{* ../../docs_src/body_multiple_params/tutorial004.py hl[27] *}
```Python
q: str | None = None
```
例えば:
{* ../../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 +163,9 @@ item: Item = Body(..., embed=True)
}
```
## まとめ
## まとめ { #recap }
リクエストが単一のボディしか持てない場合でも、*path operation関数*に複数のボディパラメータを追加することができます。
リクエストが単一のボディしか持てない場合でも、*path operation function*に複数のボディパラメータを追加することができます。
しかし、**FastAPI** はそれを処理し、関数内の正しいデータを与え、*path operation*内の正しいスキーマを検証し、文書化します。

View File

@@ -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_py39.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_py39.py hl[7] *}
/// tip | 豆知識
@@ -218,14 +208,14 @@ JSONはキーとして`str`しかサポートしていないことに注意し
///
## まとめ
## まとめ { #recap }
**FastAPI** を使用すると、Pydanticモデルが提供する最大限の柔軟性を持ちながら、コードをシンプルに短く、エレガントに保つことができます。
以下のような利点があります:
しかし、以下のような利点があります:
* エディタのサポート(どこでも補完!)
* データ変換(別名:構文解析シリアライズ)
* データ変換(別名:構文解析 / シリアライズ)
* データの検証
* スキーマ文書
* 自動文書化
* 自動ドキュメント

View File

@@ -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,27 +44,27 @@
///
### 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 }
まとめると、部分的な更新を適用するには、次のようにします:
@@ -75,11 +75,11 @@
* この方法では、モデル内のデフォルト値ですでに保存されている値を上書きするのではなく、ユーザーが実際に設定した値のみを更新することができます。
* 保存されているモデルのコピーを作成し、受け取った部分的な更新で属性を更新します(`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 | 豆知識

View File

@@ -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 }
*パスオペレーション*加えるために、パスパラメータやクエリパラメータと同じ様に宣言します:
*パスオペレーション*追加するには、パスパラメータやクエリパラメータを宣言したのと同じ方法で宣言します:
{* ../../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ドキュメントにも表示されます:
また、それらが必要な各 *パスオペレーション* の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`Python 3.10+)や `Union[str, None]`Python 3.9+)の `Union`、値が必須ではないことを判断するために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} のドキュメントを参照してください。

View File

@@ -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,18 +32,17 @@
<img src="/img/tutorial/cookie-param-models/image01.png">
</div>
/// info | 備考
/// info | 情報
**ブラウザがクッキーを処理し**ていますが、特別な方法で内部的に処理を行っているために、**JavaScript**からは簡単に操作**できない**ことに留意してください。
**対話的APIドキュメントUI** `/docs` にアクセスすれば、*パスオペレーション*に関するクッキーの**ドキュメンテーション**を確認できます。
**APIドキュメントUI** `/docs` にアクセスすれば、*パスオペレーション*に関するクッキーの**ドキュメンテーション**を確認できます。
しかし、たとえ**クッキーデータを入力して**「Execute」をクリックしても、対話的APIドキュメントUIは**JavaScript**で動作しているためクッキーは送信されず、まるで値を入力しなかったかのような**エラー**メッセージが表示されます。
しかし、たとえ**データを入力して**「Execute」をクリックしても、ドキュメントUIは**JavaScript**で動作しているためクッキーは送信されず、まるで値を入力しなかったかのような**エラー**メッセージが表示されます。
///
## 余分なクッキーを禁止する
## 余分なクッキーを禁止する { #forbid-extra-cookies }
特定の(あまり一般的ではないかもしれない)ケースで、受け付けるクッキーを**制限**する必要があるかもしれません。
@@ -51,7 +50,7 @@
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] *}
もしクライアントが**余分なクッキー**を送ろうとすると、**エラー**レスポンスが返されます。
@@ -72,6 +71,6 @@ Pydanticのモデルの Configuration を利用して、 `extra` フィールド
}
```
## まとめ
## まとめ { #summary }
**FastAPI**では、<abbr title="帰ってしまう前に最後のクッキーをどうぞ。🍪 (原文: Have a last cookie before you go. 🍪)">**クッキー**</abbr>を宣言するために、**Pydanticモデル**を使用できます。😎

View File

@@ -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** に移動すると、*パスオペレーション* のクッキーに関する **documentation** を確認できます。
しかし、データを **入力** して「Execute」をクリックしても、docs UI は **JavaScript** で動作するためクッキーは送信されず、値を何も書かなかったかのような **error** メッセージが表示されます。
///
## まとめ { #recap }
クッキーは`Cookie`を使って宣言し、`Query``Path`と同じ共通のパターンを使用する。

View File

@@ -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_py39.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 | 技術詳細

View File

@@ -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_py39.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アプリケーション) を呼び出せます。

View File

@@ -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.9+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
////
//// tab | Python 3.9+ 注釈なし
/// 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.9+
```Python
commons: Annotated[CommonQueryParams, ...
```
////
//// tab | Python 3.9+ 注釈なし
/// tip | 豆知識
可能であれば`Annotated`バージョンを使用することを推奨します。
///
```Python
commons: CommonQueryParams ...
```
...は **FastAPI** に対して特別な意味をもちません。FastAPIはデータ変換や検証などには使用しませんそれらのためには`= Depends(CommonQueryParams)`を使用しています)。
////
...は **FastAPI** に対して特別な意味をもちません。FastAPIはデータ変換や検証などには使用しませんそれらのためには`Depends(CommonQueryParams)`を使用しています)。
実際には以下のように書けばいいだけです:
//// tab | Python 3.9+
```Python
commons: Annotated[Any, Depends(CommonQueryParams)]
```
////
//// tab | Python 3.9+ 注釈なし
/// 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.9+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
////
//// tab | Python 3.9+ 注釈なし
/// tip | 豆知識
可能であれば`Annotated`バージョンを使用することを推奨します。
///
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
////
依存関係が、クラス自体のインスタンスを作成するために**FastAPI**が「呼び出す」*特定の*クラスである場合、**FastAPI** はこれらのケースのショートカットを提供しています。
それらの具体的なケースについては以下のようにします:
以下のように書く代わりに:
//// tab | Python 3.9+
```Python
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
```
////
//// tab | Python 3.9+ 注釈なし
/// tip | 豆知識
可能であれば`Annotated`バージョンを使用することを推奨します。
///
```Python
commons: CommonQueryParams = Depends(CommonQueryParams)
```
////
...以下のように書きます:
//// tab | Python 3.9+
```Python
commons: Annotated[CommonQueryParams, Depends()]
```
////
//// tab | Python 3.9+ 注釈なし
/// 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** は何をすべきか知っています。

View File

@@ -1,57 +1,69 @@
# path operationデコレータの依存関係
# パスオペレーションデコレータの依存関係 { #dependencies-in-path-operation-decorators }
場合によっては*path operation関数*の中で依存関係の戻り値を本当に必要としないことあります。
場合によっては、*パスオペレーション関数*の中で依存関係の戻り値を実際には必要としないことあります。
もしくは、依存関係が値を返さない場合もあります。
または、依存関係が値を返さない場合もあります。
しかし、それでも実行・解決る必要があります。
しかし、それでも実行・解決される必要があります。
のような場合、*path operation関数*のパラメータを`Depends`で宣言する代わりに、*path operation decorator*に`dependencies``list`を追加することができます。
のような場合、`Depends`*パスオペレーション関数* のパラメータを宣言する代わりに、*パスオペレーションデコレータ*に `dependencies``list` を追加できます。
## *path operationデコレータ*への`dependencies`追加
## *パスオペレーションデコレータ*`dependencies`追加 { #add-dependencies-to-the-path-operation-decorator }
*path operationデコレータ*はオプショナルの引数`dependencies`を受け取ります。
*パスオペレーションデコレータ*はオプショ引数`dependencies`を受け取ります。
それは`Depends()``list`であるべきです:
{* ../../docs_src/dependencies/tutorial006.py hl[17] *}
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
これらの依存関係は、通常の依存関係と同様に実行・解決されます。しかし、それらの値(何かを返す場合)は*path operation関数*には渡されません。
これらの依存関係は、通常の依存関係と同様に実行・解決されます。しかし、それらの値(何かを返す場合)は*パスオペレーション関数*には渡されません。
/// tip | 豆知識
エディタによっては、未使用の関数パラメータをチェックしてエラーとして表示するものもあります。
一部のエディタは、未使用の関数パラメータをチェックしてエラーとして表示ます。
`dependencies``path operationデコレータ`で使用することで、エディタツールのエラーを回避しながら確実に実行することができます。
これらの`dependencies`*パスオペレーションデコレータ*で使用することで、エディタ/ツールのエラーを回避しつつ、確実に実行されるようにできます。
また、コードの未使用のパラメータがあるのを見て、それ不要だと思ってしまうような新しい開発者の混乱を避けるのにも役立つかもしれません。
また、コードの未使用のパラメータを見た新しい開発者が、それ不要だと思って混乱するのを避ける助けにもなるかもしれません。
///
## 依存関係のエラーと戻り値
/// 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_py39.py hl[8,13] *}
### 例外の発生 { #raise-exceptions }
これらの依存関係は、通常の依存関係と同じように例外を`raise`できます:
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
### 戻り値 { #return-values }
そして、値を返すことも返さないこともできますが、値は使われません。
つまり、すでにどこかで使っている通常の依存関係(値を返すもの)を再利用することができ、値は使われなくても依存関係は実行されます:
つまり、すでにどこかで使っている通常の依存関係(値を返すもの)を再利用でき、値は使われなくても依存関係は実行されます:
{* ../../docs_src/dependencies/tutorial006.py hl[9,14] *}
{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
## *path operations*のグループに対する依存関係
## *パスオペレーション*のグループに対する依存関係 { #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}について読むときに、*パスオペレーション*のグループに対して単一の`dependencies`パラメータを宣言する方法を学びます
## グローバル依存関係 { #global-dependencies }
次に、`FastAPI`アプリケーション全体に依存関係を追加して、各*パスオペレーション*に適用する方法を見ていきます。

View File

@@ -1,24 +1,12 @@
# yieldを持つ依存関係
# `yield`を持つ依存関係 { #dependencies-with-yield }
FastAPIは、いくつかの<abbr title='時々"exit"、"cleanup"、"teardown"、"close"、"context managers"、 ...のように呼ばれる'>終了後の追加のステップ</abbr>を行う依存関係をサポートしています。
FastAPIは、いくつかの<abbr title='sometimes also called "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code", etc. 「exit code」「cleanup code」「teardown code」「closing code」「context manager exit code」などと呼ばれることもあります。'>終了後の追加のステップ</abbr>を行う依存関係をサポートしています。
これを行うには、`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_py39.py hl[2:4] *}
生成された値は、*path operations*や他の依存関係に注入されるものです:
{* ../../docs_src/dependencies/tutorial007.py hl[4] *}
{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *}
`yield`文に続くコードは、レスポンスが送信された後に実行されます:
`yield`文に続くコードは、レスポンス後に実行されます:
{* ../../docs_src/dependencies/tutorial007.py hl[5,6] *}
{* ../../docs_src/dependencies/tutorial007_py39.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_py39.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_py39.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_py39.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`の*前*でも発生させることができます。ただし、後ではできません
これはやや高度なテクニックで、ほとんどの場合は本当に必要にはなりません。例えば、*パスオペレーション関数*など、アプリケーションコードの他の場所から(`HTTPException`を含む例外を発生させられるためです
ただし必要であれば使えます。 🤓
///
{* ../../docs_src/dependencies/tutorial008b_an_py39.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_py39.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_py39.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}を作成することで、他の例外を発生させることもできます。そして、その例外は依存関係の終了コードではなく、そのカスタム例外ハンドラによって処理されます
しかし例外ハンドラで処理されない例外を発生させた場合は、依存関係の終了コードで処理されます。
*パスオペレーション関数*のコードで例外をraiseした場合、`HTTPException`を含め、それはyieldを持つ依存関係に渡されます。ほとんどの場合、その例外が正しく処理されるように、`yield`を持つ依存関係から同じ例外、または新しい例外を再raiseしたくなるでしょう
///
## コンテキストマネージャ
## 早期終了と`scope` { #early-exit-and-scope }
### 「コンテキストマネージャ」とは
通常、`yield`を持つ依存関係の終了コードは、クライアントに**レスポンスが送信された後**に実行されます。
しかし、*パスオペレーション関数*からreturnした後に依存関係を使う必要がないと分かっている場合は、`Depends(scope="function")`を使って、**レスポンスが送信される前**に、*パスオペレーション関数*のreturn後に依存関係を閉じるべきだとFastAPIに伝えられます。
{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *}
`Depends()`は、以下のいずれかを取る`scope`パラメータを受け取ります:
* `"function"`: リクエストを処理する*パスオペレーション関数*の前に依存関係を開始し、*パスオペレーション関数*の終了後に依存関係を終了しますが、クライアントにレスポンスが返される**前**に終了します。つまり、依存関係関数は*パスオペレーション関数*の**周囲**で実行されます。
* `"request"`: リクエストを処理する*パスオペレーション関数*の前に依存関係を開始し(`"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_py39.py hl[1:9,13] *}
/// tip | 豆知識

View File

@@ -1,12 +1,12 @@
# 依存関係 - 最初のステップ
# 依存関係 { #dependencies }
** FastAPI** は非常に強力でありながら直感的な **<abbr title="コンポーネント、リソース、プロバイダ、サービス、インジェクタブルとしても知られている">依存性注入</abbr>** システムを持っています。
**FastAPI** は非常に強力でありながら直感的な **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** システムを持っています。
それは非常にシンプルに使用できるように設計されており、開発者が他のコンポーネント **FastAPI** と統合するのが非常に簡単になるように設計されています。
## 「依存性注入」とは
## 「Dependency Injection」とは { #what-is-dependency-injection }
**依存性注入」** とは、プログラミングにおいて、コード(この場合は、*path operation関数*)が動作したり使用したりするために必要なもの(「依存関係」)を宣言する方法があることを意味します:
**Dependency Injection」** とは、プログラミングにおいて、コード(この場合は、*パスオペレーション関数*)が動作したり使用したりするために必要なもの(「依存関係」)を宣言する方法があることを意味します:
そして、そのシステム(この場合は、**FastAPI**)は、必要な依存関係をコードに提供するために必要なことは何でも行います(依存関係を「注入」します)。
@@ -19,27 +19,27 @@
これらすべてを、コードの繰り返しを最小限に抑えながら行います。
## 最初のステップ
## 最初のステップ { #first-steps }
非常にシンプルな例を見てみましょう。あまりにもシンプルなので、今のところはあまり参考にならないでしょう。
しかし、この方法では **依存性注入** システムがどのように機能するかに焦点を当てることができます。
しかし、この方法では **Dependency Injection** システムがどのように機能するかに焦点を当てることができます。
### 依存関係の作成
### 依存関係「dependable」の作成 { #create-a-dependency-or-dependable }
まずは依存関係に注目してみましょう。
以下のように、*path operation関数*と同じパラメータを全て取ることができる関数にすぎません:
以下のように、*パスオペレーション関数*と同じパラメータを全て取ることができる関数にすぎません:
{* ../../docs_src/dependencies/tutorial001.py hl[8,9] *}
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
これだけです。
**2行**
そして、それはすべての*path operation関数*が持っているのと同じ形と構造を持っています。
そして、それはすべての*パスオペレーション関数*が持っているのと同じ形と構造を持っています。
「デコレータ」を含まない(`@app.get("/some-path")`を含まない)*path operation関数*と考えることもできます。
「デコレータ」を含まない(`@app.get("/some-path")`を含まない)*パスオペレーション関数*と考えることもできます。
そして何でも返すことができます。
@@ -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 }
*パスオペレーション関数*のパラメータに`Body``Query`などを使用するのと同じように、新しいパラメータに`Depends`を使用することができます:
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
関数のパラメータに`Depends`を使用するのは`Body``Query`などと同じですが、`Depends`の動作は少し異なります。
@@ -67,7 +77,9 @@
このパラメータは関数のようなものである必要があります。
そして、その関数は、*path operation関数*が行うのと同じ方法でパラメータを取ります。
直接**呼び出しません**(末尾に括弧を付けません)。`Depends()` のパラメータとして渡すだけです。
そして、その関数は、*パスオペレーション関数*が行うのと同じ方法でパラメータを取ります。
/// tip | 豆知識
@@ -79,7 +91,7 @@
* 依存関係("dependable")関数を正しいパラメータで呼び出します。
* 関数の結果を取得します。
* *path operation関数*のパラメータにその結果を代入してください。
* *パスオペレーション関数*のパラメータにその結果を代入してください。
```mermaid
graph TB
@@ -92,7 +104,7 @@ common_parameters --> read_items
common_parameters --> read_users
```
この方法では、共有されるコードを一度書き、**FastAPI** が*path operations*のための呼び出しを行います。
この方法では、共有されるコードを一度書き、**FastAPI** が*パスオペレーション*のための呼び出しを行います。
/// 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` のような他のツールでも同様です。
これは **大規模なコードベース** で、**同じ依存関係** を **多くの *パスオペレーション*** で何度も使う場合に特に役立ちます。
## `async`にするかどうか { #to-async-or-not-to-async }
依存関係は **FastAPI***パスオペレーション関数*と同じ)からも呼び出されるため、関数を定義する際にも同じルールが適用されます。
`async def`や通常の`def`を使用することができます。
また、通常の`def`*path operation関数*の中に`async def`を入れて依存関係を宣言したり、`async def`*path operation関数*の中に`def`を入れて依存関係を宣言したりすることなどができます。
また、通常の`def`*パスオペレーション関数*の中に`async def`を入れて依存関係を宣言したり、`async def`*パスオペレーション関数*の中に`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*が一致した時に*パスオペレーション関数*が宣言されていて、**FastAPI** が正しいパラメータで関数を呼び出してリクエストからデータを抽出する処理をしています。
実は、すべてのあるいはほとんどのWebフレームワークは、このように動作します。
これらの関数を直接呼び出すことはありません。これらの関数はフレームワーク(この場合は、**FastAPI**)によって呼び出されます。
依存性注入システムでは、**FastAPI** に*path operation*もまた、*path operation関数*の前に実行されるべき他の何かに「依存」していることを伝えることができ、**FastAPI** がそれを実行し、結果を「注入」することを引き受けます。
Dependency Injection システムでは、**FastAPI** に*パスオペレーション関数*もまた、*パスオペレーション関数*の前に実行されるべき他の何かに「依存」していることを伝えることができ、**FastAPI** がそれを実行し、結果を「注入」することを引き受けます。
他にも、「依存性注入」と同じような考えの一般的な用語があります:
他にも、「dependency injection」と同じような考えの一般的な用語があります:
* リソース
* プロバイダ
* サービス
* インジェクタブル
* コンポーネント
* resources
* providers
* services
* injectables
* components
## **FastAPI** プラグイン
## **FastAPI** プラグイン { #fastapi-plug-ins }
統合や「プラグイン」は **依存性注入** システムを使って構築することができます。しかし、実際には、**「プラグイン」を作成する必要はありません**。依存関係を使用することで、無限の数の統合やインタラクションを宣言することができ、それが**path operation関数*で利用可能になるからです。
統合や「プラグイン」は **Dependency Injection** システムを使って構築することができます。しかし、実際には、**「プラグイン」を作成する必要はありません**。依存関係を使用することで、無限の数の統合やインタラクションを宣言することができ、それが*パスオペレーション関数*で利用可能になるからです。
依存関係は非常にシンプルで直感的な方法で作成することができ、必要な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**システムが、これらの依存関係(およびそのサブ依存関係)をすべて解決し、各ステップで結果を提供(注入)します。
例えば、つのAPIエンドポイント*path operations*)があるとします:
例えば、つのAPIエンドポイント*パスオペレーション*)があるとします:
* `/items/public/`
* `/items/private/`
@@ -205,8 +243,8 @@ admin_user --> activate_user
paying_user --> pro_items
```
## **OpenAPI** との統合
## **OpenAPI** との統合 { #integrated-with-openapi_1 }
これら全ての依存関係は、要件を宣言すると同時に、*path operations*にパラメータやバリデーションを追加します。
これら全ての依存関係は、要件を宣言すると同時に、*パスオペレーション*にパラメータやバリデーションを追加します。
**FastAPI** はそれをすべてOpenAPIスキーマに追加して、対話型のドキュメントシステムに表示されるようにします。

View File

@@ -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`つだけであることに注意してください。
*パスオペレーション関数*の中で宣言している依存関係は`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 }
依存関係のつが同じ*path operation*に対して複数回宣言されている場合、例えば、複数の依存関係が共通のサブ依存関係を持っている場合、**FastAPI** はリクエストごとに回だけそのサブ依存関係を呼び出します。
依存関係の1つが同じ*パスオペレーション*に対して複数回宣言されている場合、例えば、複数の依存関係が共通のサブ依存関係を持っている場合、**FastAPI** はリクエストごとに1回だけそのサブ依存関係を呼び出します。
そして、返された値を<abbr title="計算された値・生成された値を保存するユーティリティまたはシステム、再計算する代わりに再利用するためのもの">「キャッシュ」</abbr>に保存し、同じリクエストに対して依存関係を何度も呼び出す代わりに、特定のリクエストでそれを必要とする全ての「依存関係」に渡すことになります。
そして、返された値を<abbr title="A utility/system to store computed/generated values, to reuse them instead of computing them again. 計算/生成された値を保存し、再計算する代わりに再利用するためのユーティリティ/システム。">「キャッシュ」</abbr>に保存し、同じリクエストに対して依存関係を何度も呼び出す代わりに、その特定のリクエストでそれを必要とする全ての「依存」に渡すことになります。
高度なシナリオでは、「キャッシュされた」値を使うのではなく、同じリクエストの各ステップ(おそらく複数回)で依存関係を呼び出す必要があることがわかっている場合、`Depens`を使用する際に、`use_cache=False`というパラメータを設定することができます
高度なシナリオでは、「キャッシュされた」値を使うのではなく、同じリクエストの各ステップ(おそらく複数回)で依存関係を呼び出す必要があることがわかっている場合、`Depends`を使用する際に、`use_cache=False`というパラメータを設定することができます:
//// tab | Python 3.9+
```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.9+ 非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** システムは非常にシンプルです。
*パスオペレーション関数*と同じように見えるただの関数です。
しかし、それでも非常に強力で、任意の深くネストされた依存関係「グラフ」(ツリー)を宣言することができます。

View File

@@ -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`に変換します。

View File

@@ -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] *}

View File

@@ -1,6 +1,6 @@
# モデル - より詳しく
# Extra Models { #extra-models }
先ほどの例に続き、複数の関連モデルを持つこと一般的です。
先ほどの例に続き、複数の関連モデルを持つこと一般的です。
これはユーザーモデルの場合は特にそうです。なぜなら:
@@ -8,27 +8,27 @@
* **出力モデル**はパスワードをもつべきではありません。
* **データベースモデル**はおそらくハッシュ化されたパスワードが必要になるでしょう。
/// danger | 危険
/// danger
ユーザーの平文のパスワードは絶対に保存しないでください。常に認証に利用可能な「安全なハッシュ」を保存してください。
ユーザーの平文のパスワードは絶対に保存しないでください。常に検証できる「安全なハッシュ」を保存してください。
知らない方は、[セキュリティの章](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}で「パスワードハッシュ」とは何かを学ぶことができます。
///
## 複数のモデル
## Multiple models { #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()`について
### About `**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)
```
...以下のようになります:
@@ -132,13 +132,13 @@ UserInDB(
)
```
/// warning | 注意
/// warning
サポートしている追加機能は、データの可能な流れをデモするだけであり、もちろん本当のセキュリティを提供しているわけではありません。
追加のサポート関数`fake_password_hasher``fake_save_user`は、データの可能な流れをデモするだけであり、もちろん本当のセキュリティを提供しているわけではありません。
///
## 重複の削減
## Reduce duplication { #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` or `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 { #list-of-models }
同じように、オブジェクトのリストのレスポンスを宣言できます。
そのためには、標準のPythonの`typing.List`またはPython 3.9以降では単に`list`)を使用します:
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
## Response with arbitrary `dict` { #response-with-arbitrary-dict }
また、Pydanticモデルを使用せずに、キーと値の型だけを定義した任意の`dict`を使ってレスポンスを宣言することもできます。
これは、有効なフィールド・属性名Pydanticモデルに必要なものを事前に知らない場合に便利です。
この場合、`typing.Dict`を使用することができます:
この場合、`typing.Dict`またはPython 3.9以降では単に`dict`を使用できます:
{* ../../docs_src/extra_models/tutorial005.py hl[1,8] *}
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
## まとめ
## Recap { #recap }
複数のPydanticモデルを使用し、ケースごとに自由に継承します。
エンティティが異なる「状態」を持たなければならない場合は、エンティティごとに単一のデータモデルを持つ必要はありません。`password``password_hash`パスワードなしなどのいくつかの「状態」をもつユーザー「エンティティ」の場合の様にすれば良いです。
エンティティが異なる「状態」を持たなければならない場合は、エンティティごとに単一のデータモデルを持つ必要はありません。`password``password_hash`パスワードなしを含む状態を持つユーザー「エンティティ」の場合と同様です。

View File

@@ -1,8 +1,8 @@
# 最初のステップ
# 最初のステップ { #first-steps }
最もシンプルなFastAPIファイルは以下のようになります:
{* ../../docs_src/first_steps/tutorial001.py *}
{* ../../docs_src/first_steps/tutorial001_py39.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">&apos;/home/user/code/awesomeapp&apos;</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)
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### 他の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)
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
### 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.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_py39.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_py39.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メソッドを
「**オペレーションズ**」とも呼ぶことにします。
#### *パスオペレーションデコレータ*を定義
#### *パスオペレーションデコレータ*を定義 { #define-a-path-operation-decorator }
{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
`@app.get("/")`は直下の関数が下記のリクエストの処理を担当することを**FastAPI**に伝えます:
* パス `/`
* <abbr title="an HTTP GET method"><code>get</code> オペレーション</abbr>
/// info | `@decorator` について
/// info | `@decorator` Info
Pythonにおける`@something`シンタックスはデコレータと呼ばれます。
@@ -255,7 +280,7 @@ Pythonにおける`@something`シンタックスはデコレータと呼ばれ
「デコレータ」は直下の関数を受け取り、それを使って何かを行います。
私たちの場合、このデコレーターは直下の関数が**オペレーション** `get`を使用した**パス**` / `に対応することを**FastAPI** に通知します。
私たちの場合、このデコレーターは直下の関数が**オペレーション** `get`を使用した**パス** `/`に対応することを**FastAPI** に通知します。
これが「*パスオペレーションデコレータ*」です。
@@ -286,7 +311,7 @@ Pythonにおける`@something`シンタックスはデコレータと呼ばれ
///
### Step 4: **パスオペレーション**を定義
### Step 4: **パスオペレーション関数**を定義 { #step-4-define-the-path-operation-function }
以下は「**パスオペレーション関数**」です:
@@ -294,7 +319,7 @@ Pythonにおける`@something`シンタックスはデコレータと呼ばれ
* **オペレーション**: は`get`です。
* **関数**: 「デコレータ」の直下にある関数 (`@app.get("/")`の直下) です。
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
{* ../../docs_src/first_steps/tutorial001_py39.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_py39.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_py39.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("/")`のようなデコレータを使用して、**パスオペレーションデコレータ**を記述します。
* **パスオペレーション関数**を定義します。例: `def root(): ...`。
* `fastapi dev`コマンドで開発サーバーを起動します。
* 任意で`fastapi deploy`を使ってアプリをデプロイします。

View File

@@ -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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.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_py39.py hl[2:5,15,21] *}
{* ../../docs_src/handling_errors/tutorial006.py hl[2,3,4,5,15,21] *}
この例では、非常に表現力のあるメッセージでエラーを`print`しています。
しかし、例外を使用して、デフォルトの例外ハンドラを再利用することができるということが理解できます。
この例では、非常に表現力のあるメッセージでエラーを`print`しているだけですが、要点は理解できるはずです。例外を使用し、その後デフォルトの例外ハンドラを再利用できます。

View File

@@ -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*通信する場合は、次のようにつの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** がそれらの変換をすべて取り持ってくれます。

View File

@@ -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">&apos;/home/user/code/awesomeapp&apos;</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 }
**高度なユーザーガイド**もあり、**チュートリアル - ユーザーガイド**の後で読むことができます。
この **チュートリアル - ユーザーガイド** の後で、後から読める **高度なユーザーガイド** もあります。
**高度なユーザーガイド**は**チュートリアル - ユーザーガイド**に基づいており、同じ概念を使用し、いくつかの追加機能を紹介しています。
**高度なユーザーガイド** は本チュートリアルをベースにしており、同じ概念を使用し、いくつかの追加機能を教えます。
ただし、最初に**チュートリアル - ユーザーガイド**(現在読んでいる内容)をお読みください。
ただし、最初に **チュートリアル - ユーザーガイド**(今読んでいる内容)をお読みください。
**チュートリアル-ユーザーガイド**だけで完全なアプリケーションを構築できるように設計されています。加えて、**高度なユーザーガイド**の中からニーズに応じたアイデアを使用して、様々な拡張が可能です。
**チュートリアル - ユーザーガイド** だけで完全なアプリケーションを構築できるように設計されており、その後ニーズに応じて、**高度なユーザーガイド** の追加のアイデアのいくつかを使って、さまざまな方法で拡張できます。

View File

@@ -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_py39.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_py39.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` を使うと、パスオペレーションをグループ分けするために使用する各タグに追加のメタデータを追加できます。
`users``items` のタグを使った例でメタデータの追加を試してみましょう
それぞれのタグごとに1つの辞書を含むリストを取ります
タグのためのメタデータを作成し、それを `openapi_tags` パラメータに渡します
それぞれの辞書は以下を含められます:
{* ../../docs_src/metadata/tutorial004.py hl[3:16,18] *}
* `name` (**必須**): *パスオペレーション* および `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_py39.py hl[3:16,18] *}
説明の中でMarkdownを使用できることに注意してください。たとえば「login」は太字 (**login**) で表示され、「fancy」は斜体 (_fancy_) で表示されます。
/// tip | 豆知識
@@ -49,31 +68,31 @@
///
### 自作タグの使用
### タグの使用 { #use-your-tags }
`tags` パラメーターを使用して、それぞれの *path operations* (および `APIRouter`) を異なるタグに割り当てます:
*パスオペレーション*および `APIRouter`)の `tags` パラメータを使用して、それらを異なるタグに割り当てます:
{* ../../docs_src/metadata/tutorial004.py hl[21,26] *}
{* ../../docs_src/metadata/tutorial004_py39.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_py39.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_py39.py hl[3] *}

View File

@@ -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_py39.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,9 +57,38 @@
例えば、リクエストの処理とレスポンスの生成にかかった秒数を含むカスタムヘッダー `X-Process-Time` を追加できます:
{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *}
{* ../../docs_src/middleware/tutorial001_py39.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}を参照してください。

View File

@@ -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_py39.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[18:19] *}
## docstringを用いた説明
## docstringを用いた説明 { #description-from-docstring }
説明文は長くて複数行におよぶ傾向があるので、関数<abbr title="ドキュメントに使用される関数内の最初の式(変数に代入されていない)としての複数行の文字列">docstring</abbr>内に*path operation*の説明文を宣言できます。すると、**FastAPI** は説明文を読み込んでくれます。
説明文は長くて複数行におよぶ傾向があるので、関数<abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation ドキュメントに使用される関数内の最初の式(変数に代入されていない)としての複数行の文字列">docstring</abbr>内に*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[19] *}
/// 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*を<abbr title="obsolete, recommended not to use it 非推奨、使わない方がよい">deprecated</abbr>としてマークする必要があるが、それを削除しない場合は、`deprecated`パラメータを渡します:
{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *}
{* ../../docs_src/path_operation_configuration/tutorial006_py39.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*のメタデータを簡単に設定・追加することができます。

View File

@@ -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_py39.py hl[7] *}
## 必要に応じてパラメータを並び替えるトリック
ただし、`Annotated`を使う場合はこの問題は起きないことを覚えておいてください。`Query()``Path()`に関数パラメータのデフォルト値を使わないためです。
クエリパラメータ`q``Query`やデフォルト値なしで宣言し、パスパラメータ`item_id``Path`を用いて宣言し、それらを別の順番に並びたい場合、Pythonには少し特殊な構文が用意されています。
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.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>としても知られています。たとえデフォルト値がなくても。
{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[8] *}
{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.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_py39.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_py39.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_py39.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_py39.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`クラスのサブクラスです。
そして、それらすべて、これまで見てきた追加のバリデーションとメタデータ同じパラメータを共有しています。
それらすべて、これまで見てきた追加のバリデーションとメタデータ同じパラメータを共有しています。
///

View File

@@ -1,22 +1,22 @@
# パスパラメータ
# パスパラメータ { #path-parameters }
Pythonのformat文字列と同様のシンタックスで「パスパラメータ」や「パス変数」を宣言できます:
{* ../../docs_src/path_params/tutorial001.py hl[6,7] *}
{* ../../docs_src/path_params/tutorial001_py39.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_py39.py hl[7] *}
ここでは、 `item_id``int` として宣言されています。
@@ -26,7 +26,7 @@ Pythonのformat文字列と同様のシンタックスで「パスパラメー
///
## データ<abbr title="別名: serialization, parsing, marshalling">変換</abbr>
## データ<abbr title="別名: serialization, parsing, marshalling">変換</abbr> { #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**は自動リクエスト <abbr title="HTTPリクエストで受け取った文字列をPythonデータへ変換する">"解析"</abbr> を行います。
///
## データバリデーション
## データバリデーション { #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,29 +118,29 @@ Pythonのformat文字列と同様のシンタックスで「パスパラメー
*path operations* は順に評価されるので、 `/users/me``/users/{user_id}` よりも先に宣言されているか確認する必要があります:
{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
それ以外の場合、 `/users/{users_id}``/users/me` としてもマッチします。値が"me"であるパラメータ `user_id` を受け取ると「考え」ます。
それ以外の場合、 `/users/{user_id}``/users/me` としてもマッチします。値が `"me"` であるパラメータ `user_id` を受け取ると「考え」ます。
## 定義済みの値
同様に、パスオペレーションを再定義することはできません:
{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
パスは最初にマッチしたものが常に使われるため、最初のものが常に使用されます。
## 定義済みの値 { #predefined-values }
*パスパラメータ*を受け取る *path operation* をもち、有効な*パスパラメータ*の値を事前に定義したい場合は、標準のPython <abbr title="Enumeration">`Enum`</abbr> を利用できます。
### `Enum` クラスの作成
### `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_py39.py hl[1,6:9] *}
/// tip | 豆知識
@@ -147,33 +148,33 @@ Pythonのformat文字列と同様のシンタックスで「パスパラメー
///
### *パスパラメータ*の宣言
### *パスパラメータ*の宣言 { #declare-a-path-parameter }
次に、作成したenumクラスである`ModelName`を使用した型アノテーションをもつ*パスパラメータ*を作成します:
{* ../../docs_src/path_params/tutorial005.py hl[16] *}
{* ../../docs_src/path_params/tutorial005_py39.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_py39.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_py39.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_py39.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,17 +227,17 @@ Starletteのオプションを直接使用することで、以下のURLの様
したがって、以下の様に使用できます:
{* ../../docs_src/path_params/tutorial004.py hl[6] *}
{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
/// tip | 豆知識
最初のスラッシュ (`/`)が付いている `/home/johndoe/myfile.txt` をパラメータが含んでいる必要があります
最初のスラッシュ (`/`)が付いている `/home/johndoe/myfile.txt` をパラメータが含んでいる必要があるかもしれません
この場合、URLは `files``home` の間にダブルスラッシュ (`//`) のある、 `/files//home/johndoe/myfile.txt` になります。
///
## まとめ
## まとめ { #recap }
簡潔で、本質的で、標準的なPythonの型宣言を使用することで、**FastAPI**は以下を行います:

View File

@@ -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モデル**を使用できます。😎

View File

@@ -1,120 +1,228 @@
# クエリパラメータと文字列の検証
# クエリパラメータと文字列の検証 { #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 で使うときです。 🚀
次の型アノテーションがありました:
//// tab | Python 3.10+
```Python
q: str | None = None
```
////
//// tab | Python 3.9+
```Python
q: Union[str, None] = None
```
////
これを `Annotated` で包んで、次のようにします:
//// tab | Python 3.10+
```Python
q: Annotated[str | None] = None
```
////
//// tab | Python 3.9+
```Python
q: Annotated[Union[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 の以前のバージョン(<abbr title="before 2023-03">0.95.0</abbr> より前)では、パラメータのデフォルト値として `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>を定義することができます:
パラメータが一致するべき <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">正規表現</abbr> `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_py39.py hl[9] *}
/// note | 備考
デフォルト値を指定すると、パラメータは任意になります。
`None` を含む任意の型のデフォルト値があると、パラメータはオプショナル(必須ではない)になります。
///
## 必須にする
## 必須パラメータ { #required-parameters }
これ以上、バリデーションやメタデータを宣言する必要ない場合は、デフォルト値を指定しないだけでクエリパラメータ`q`を必須にすることができます。以下のように:
これ以上、バリデーションやメタデータを宣言する必要ない場合は、デフォルト値を宣言しないだけでクエリパラメータ `q` を必須にできます。以下のように:
```Python
q: str
@@ -123,42 +231,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_py39.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 +287,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_py39.py hl[9] *}
以下のURLを開くと:
以下にアクセスすると:
```
http://localhost:8000/items/
@@ -204,21 +312,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_py39.py hl[9] *}
/// note | 備考
この場合、FastAPIはリストの内容をチェックしないことを覚えておいてください。
例えば`List[int]`はリストの内容が整数であるかどうかをチェックします(そして、文書化します)。しかし`list`だけではそうしません。
例えば`list[int]`はリストの内容が整数であるかどうかをチェックします(そして、文書化します)。しかし`list`だけではそうしません。
///
## より多くのメタデータを宣言する
## より多くのメタデータを宣言する { #declare-more-metadata }
パラメータに関する情報をさらに追加することができます。
@@ -234,13 +342,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 +366,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="ISBN means International Standard Book Number 国際標準図書番号">ISBN</abbr> の書籍番号なら item ID が `isbn-` で始まること、<abbr title="IMDB (Internet Movie Database) is a website with information about movies IMDBInternet 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()` で、辞書の各アイテムのキーと値を含むタプルを持つ <abbr title="Something we can iterate on with a for loop, like a list, set, etc.">反復可能オブジェクト</abbr> を取得します。
この反復可能オブジェクトを `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 +461,14 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
* `description`
* `deprecated`
文字列のためのバリデーション:
文字列に固有のバリデーション:
* `min_length`
* `max_length`
* `regex`
* `pattern`
この例では、`str`の値のバリデーションを宣言する方法を見てきました
`AfterValidator` を使ったカスタムバリデーション
この例では、`str` の値のバリデーションを宣言する方法を見てきました。
数値のような他の型のバリデーションを宣言する方法は次の章を参照してください。

View File

@@ -1,8 +1,8 @@
# クエリパラメータ
# クエリパラメータ { #query-parameters }
パスパラメータではない関数パラメータを宣言すると、それらは自動的に "クエリ" パラメータとして解釈されます。
パスパラメータではない関数パラメータを宣言すると、それらは自動的にクエリパラメータとして解釈されます。
{* ../../docs_src/query_params/tutorial001.py hl[9] *}
{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
クエリはURL内で `?` の後に続くキーとバリューの組で、 `&` で区切られています。
@@ -24,11 +24,11 @@ http://127.0.0.1:8000/items/?skip=0&limit=10
パスパラメータに適用される処理と完全に同様な処理がクエリパラメータにも施されます:
* エディターサポート (明らかに)
* データ<abbr title="HTTPリクエストで受け取った文字列をPythonデータへ変換する">解析</abbr>
* データ <abbr title="converting the string that comes from an HTTP request into Python data">解析</abbr>
* データバリデーション
* 自動ドキュメント生成
## デフォルト
## デフォルト { #defaults }
クエリパラメータはパスの固定部分ではないので、オプショナルとしたり、デフォルト値をもつことができます。
@@ -55,13 +55,13 @@ http://127.0.0.1:8000/items/?skip=20
関数内のパラメータの値は以下の様になります:
* `skip=20`: URL内にセットしたため
* `limit=10`: デフォルト値
* `limit=10`: デフォルト値だったため
## オプショナルなパラメータ
## オプショナルなパラメータ { #optional-parameters }
同様に、デフォルト値を `None` とすることで、オプショナルなクエリパラメータを宣言できます:
{* ../../docs_src/query_params/tutorial002.py hl[9] *}
{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
この場合、関数パラメータ `q` はオプショナルとなり、デフォルトでは `None` になります。
@@ -71,11 +71,11 @@ http://127.0.0.1:8000/items/?skip=20
///
## クエリパラメータの型変換
## クエリパラメータの型変換 { #query-parameter-type-conversion }
`bool` 型も宣言できます。これは以下の様に変換されます:
`bool` 型も宣言でき変換されます:
{* ../../docs_src/query_params/tutorial003.py hl[9] *}
{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
この場合、以下にアクセスすると:
@@ -109,27 +109,28 @@ http://127.0.0.1:8000/items/foo?short=yes
もしくは、他の大文字小文字のバリエーション (アッパーケース、最初の文字だけアッパーケース、など)で、関数は `short` パラメータを `True``bool` 値として扱います。それ以外は `False` になります。
## 複数のパスパラメータとクエリパラメータ
複数のパスパラメータとクエリパラメータを同時に宣言できます。**FastAPI**は互いを区別できます。
## 複数のパスパラメータとクエリパラメータ { #multiple-path-and-query-parameters }
複数のパスパラメータとクエリパラメータを同時に宣言できます。**FastAPI**はどれがどれかを把握しています。
そして特定の順序で宣言しなくてもよいです。
名前で判別されます:
{* ../../docs_src/query_params/tutorial004.py hl[8,10] *}
{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
## 必須のクエリパラメータ
## 必須のクエリパラメータ { #required-query-parameters }
パスパラメータ以外のパラメータ (今のところ、クエリパラメータのみ説明しました) のデフォルト値を宣言した場合、そのパラメータは必須ではなくなります。
パスパラメータ以外のパラメータ (今のところ、クエリパラメータのみ見てきました) のデフォルト値を宣言した場合、そのパラメータは必須ではなくなります。
特定の値を与えずにただオプショナルにしたい場合はデフォルト値を `None` にして下さい。
しかしクエリパラメータを必須にしたい場合は、ただデフォルト値を宣言しなければよいです:
{* ../../docs_src/query_params/tutorial005.py hl[6:7] *}
{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
ここで、クエリパラメータ `needy``str` 型の必須のクエリパラメータです
ここで、クエリパラメータ `needy``str` 型の必須のクエリパラメータです
以下のURLをブラウザで開くと:
@@ -141,16 +142,17 @@ http://127.0.0.1:8000/items/foo-item
```JSON
{
"detail": [
{
"loc": [
"query",
"needy"
],
"msg": "field required",
"type": "value_error.missing"
}
]
"detail": [
{
"type": "missing",
"loc": [
"query",
"needy"
],
"msg": "Field required",
"input": null
}
]
}
```
@@ -169,9 +171,9 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
}
```
そして当然、あるパラメータを必須に、別のパラメータにデフォルト値を設定し、また別のパラメータをオプショナルにできます:
そして当然、あるパラメータを必須に、あるパラメータにデフォルト値を設定し、またあるパラメータを完全にオプショナルにできます:
{* ../../docs_src/query_params/tutorial006.py hl[10] *}
{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
この場合、3つのクエリパラメータがあります。:
@@ -181,6 +183,6 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
/// tip | 豆知識
[パスパラメータ](path-params.md#_8){.internal-link target=_blank}と同様に `Enum` を使用できます。
[パスパラメータ](path-params.md#predefined-values){.internal-link target=_blank}と同様に `Enum` を使用できます。
///

View File

@@ -1,24 +1,28 @@
# リクエストフォームとファイル
# リクエストフォームとファイル { #request-forms-and-files }
`File``Form`を同時に使うことでファイルとフォームフィールドを定義することができます。
/// info | 情報
アップロードされたファイルやフォームデータを受信するには、まず<a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>をインストールします。
アップロードされたファイルやフォームデータを受信するには、まず<a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>をインストールします。
例えば、`pip install python-multipart`のように。
[仮想環境](../virtual-environments.md){.internal-link target=_blank}を作成し、それを有効化してから、例えば次のようにインストールしてください:
```console
$ pip install python-multipart
```
///
## `File`と`Form`のインポート
## `File`と`Form`のインポート { #import-file-and-form }
{* ../../docs_src/request_forms_and_files/tutorial001.py hl[1] *}
{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
## `File`と`Form`のパラメータの定義
## `File`と`Form`のパラメータの定義 { #define-file-and-form-parameters }
ファイルやフォームのパラメータは`Body``Query`の場合と同じように作成します:
{* ../../docs_src/request_forms_and_files/tutorial001.py hl[8] *}
{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
ファイルとフォームフィールドがフォームデータとしてアップロードされ、ファイルとフォームフィールドを受け取ります。
@@ -32,6 +36,6 @@
///
## まとめ
## まとめ { #recap }
同じリクエストでデータやファイルを受け取る必要がある場合は、`File``Form`を一緒に使用します。

View File

@@ -1,4 +1,4 @@
# フォームデータ
# フォームデータ { #form-data }
JSONの代わりにフィールドを受け取る場合は、`Form`を使用します。
@@ -6,27 +6,31 @@ JSONの代わりにフィールドを受け取る場合は、`Form`を使用し
フォームを使うためには、まず<a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>をインストールします。
たとえば、`pip install python-multipart`のように。
必ず[仮想環境](../virtual-environments.md){.internal-link target=_blank}を作成して有効化してから、例えば次のようにインストールしてください:
```console
$ pip install python-multipart
```
///
## `Form`のインポート
## `Form`のインポート { #import-form }
`fastapi`から`Form`をインポートします:
{* ../../docs_src/request_forms/tutorial001.py hl[1] *}
{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
## `Form`のパラメータの定義
## `Form`のパラメータの定義 { #define-form-parameters }
`Body``Query`の場合と同じようにフォームパラメータを作成します:
{* ../../docs_src/request_forms/tutorial001.py hl[7] *}
{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
例えば、OAuth2仕様が使用できる方法の「パスワードフロー」と呼ばれるでは、フォームフィールドとして`username``password`を送信する必要があります。
<abbr title="仕様">仕様</abbr>では、フィールドの名前が`username``password`であることと、JSONではなくフォームフィールドとして送信されることを要求しています。
<abbr title="specification 仕様">spec</abbr>では、フィールドの名前が`username``password`であることと、JSONではなくフォームフィールドとして送信されることを要求しています。
`Form`では`Body`(および`Query``Path``Cookie`)と同じメタデータとバリデーションを宣言することができます。
`Form`では`Body`(および`Query``Path``Cookie`)と同じ設定を宣言することができます。これには、バリデーション、例、エイリアス(例えば`username`の代わりに`user-name`)などが含まれます。
/// info | 情報
@@ -40,7 +44,7 @@ JSONの代わりにフィールドを受け取る場合は、`Form`を使用し
///
## 「フォームフィールド」について
## 「フォームフィールド」について { #about-form-fields }
HTMLフォーム`<form></form>`がサーバにデータを送信する方法は、通常、そのデータに「特別な」エンコーディングを使用していますが、これはJSONとは異なります。
@@ -64,6 +68,6 @@ HTMLフォーム`<form></form>`)がサーバにデータを送信する方
///
## まとめ
## まとめ { #recap }
フォームデータの入力パラメータを宣言するには、`Form`を使用する。

View File

@@ -1,6 +1,35 @@
# レスポンスモデル
# レスポンスモデル - 戻り値の型 { #response-model-return-type }
*path operations* のいずれにおいても、`response_model`パラメータを使用して、レスポンスのモデルを宣言することができます:
*パスオペレーション関数*の**戻り値の型**にアノテーションを付けることで、レスポンスに使用される型を宣言できます
関数**パラメータ**の入力データと同じように **型アノテーション** を使用できます。Pydanticモデル、リスト、辞書、整数や真偽値などのスカラー値を使用できます。
{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
FastAPIはこの戻り値の型を使って以下を行います:
* 返却データを**検証**します。
* データが不正(例: フィールドが欠けている)であれば、それは*あなた*のアプリコードが壊れていて、返すべきものを返していないことを意味し、不正なデータを返す代わりにサーバーエラーを返します。これにより、あなたとクライアントは、期待されるデータとデータ形状を受け取れることを確実にできます。
* OpenAPIの *パスオペレーション* に、レスポンス用の **JSON Schema** を追加します。
* これは**自動ドキュメント**で使用されます。
* 自動クライアントコード生成ツールでも使用されます。
しかし、最も重要なのは:
* 戻り値の型で定義された内容に合わせて、出力データを**制限しフィルタリング**します。
* これは**セキュリティ**の観点で特に重要です。以下で詳しく見ていきます。
## `response_model`パラメータ { #response-model-parameter }
型が宣言している内容とまったく同じではないデータを返す必要がある、またはそうしたいケースがあります。
例えば、**辞書を返す**、またはデータベースオブジェクトを返したいが、**Pydanticモデルとして宣言**したい場合があります。こうすることで、Pydanticモデルが返したオブジェクト例: 辞書やデータベースオブジェクト)のドキュメント化、バリデーションなどをすべて行ってくれます。
戻り値の型アノテーションを追加すると、ツールやエディタが(正しく)エラーとして、関数が宣言した型(例: Pydanticモデルとは異なる型例: dictを返していると警告します。
そのような場合、戻り値の型の代わりに、*パスオペレーションデコレータ*のパラメータ `response_model` を使用できます。
`response_model`パラメータは、いずれの *パスオペレーション* でも使用できます:
* `@app.get()`
* `@app.post()`
@@ -8,104 +37,211 @@
* `@app.delete()`
* など。
{* ../../docs_src/response_model/tutorial001.py hl[17] *}
{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}
/// note | 備考
`response_model`は「デコレータ」メソッド(`get``post`など)のパラメータであることに注意してください。すべてのパラメータやボディのように、*path operation関数* のパラメータではありません。
`response_model`は「デコレータ」メソッド(`get``post`など)のパラメータであることに注意してください。すべてのパラメータやボディのように、*パスオペレーション関数* のパラメータではありません。
///
Pydanticモデルの属性に対して宣言するのと同じ型を受け取るので、Pydanticモデルになることもできます、例えば`List[Item]`のようPydanticモデルの`list`なることもできます。
`response_model`は、Pydanticモデルのフィールドで宣言するのと同じ型を受け取ります。そのため、Pydanticモデルにもできます、例えば `List[Item]` のように、Pydanticモデルの `list` にもできます。
FastAPIは`response_model`を使って以下のことをします:
FastAPIはこの `response_model` を使って、データのドキュメント化や検証などを行い、さらに出力データを型宣言に合わせて**変換・フィルタリング**します
* 出力データを型宣言に変換します。
* データを検証します。
* OpenAPIの *path operation* で、レスポンス用のJSON Schemaを追加します。
* 自動ドキュメントシステムで使用されます。
/// tip | 豆知識
しかし、最も重要なのは:
エディタやmypyなどで厳密な型チェックをしている場合、関数の戻り値の型を `Any` として宣言できます。
* 出力データをモデルのデータに限定します。これがどのように重要なのか以下で見ていきましょう
/// note | 技術詳細
レスポンスモデルは、関数の戻り値のアノテーションではなく、このパラメータで宣言されています。なぜなら、パス関数は実際にはそのレスポンスモデルを返すのではなく、`dict`やデータベースオブジェクト、あるいは他のモデルを返し、`response_model`を使用してフィールドの制限やシリアライズを行うからです。
そうすると、意図的に何でも返していることをエディタに伝えられます。それでもFastAPIは `response_model` を使って、データのドキュメント化、検証、フィルタリングなどを行います
///
## 同じ入力データの返却
### `response_model`の優先順位 { #response-model-priority }
ここでは`UserIn`モデルを宣言しています。それには平文のパスワードが含まれています:
戻り値の型と `response_model` の両方を宣言した場合、`response_model` が優先され、FastAPIで使用されます
{* ../../docs_src/response_model/tutorial002.py hl[9,11] *}
これにより、レスポンスモデルとは異なる型を返している場合でも、エディタやmypyなどのツールで使用するために関数へ正しい型アテーションを追加できます。それでもFastAPIは `response_model` を使用してデータの検証やドキュメント化などを実行できます。
また `response_model=None` を使用して、その*パスオペレーション*のレスポンスモデル生成を無効化することもできます。これは、Pydanticのフィールドとして有効ではないものに対して型アテーションを追加する場合に必要になることがあります。以下のセクションのいずれかで例を示します。
## 同じ入力データの返却 { #return-the-same-input-data }
ここでは `UserIn` モデルを宣言しています。これには平文のパスワードが含まれます:
{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}
/// info | 情報
`EmailStr` を使用するには、最初に <a href="https://github.com/JoshData/python-email-validator" class="external-link" target="_blank">`email-validator`</a> をインストールしてください。
[仮想環境](../virtual-environments.md){.internal-link target=_blank}を作成して有効化してから、例えば次のようにインストールしてください:
```console
$ pip install email-validator
```
または次のようにします:
```console
$ pip install "pydantic[email]"
```
///
そして、このモデルを使用して入力を宣言し、同じモデルを使って出力を宣言しています:
{* ../../docs_src/response_model/tutorial002.py hl[17,18] *}
{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}
これで、ブラウザがパスワードを使ってユーザーを作成する際に、APIがレスポンスで同じパスワードを返すようになりました。
この場合、ユーザー自身がパスワードを送信しているので問題ないかもしれません。
この場合、同じユーザーがパスワードを送信しているので問題ないかもしれません。
しかし、同じモデルを別の*path operation*に使用すると、すべてのクライアントにユーザーのパスワードを送信してしまうことになります。
しかし、同じモデルを別の*パスオペレーション*に使用すると、すべてのクライアントにユーザーのパスワードを送信してしまう可能性があります。
/// danger | 危険
/// danger | 警告
ユーザーの平文のパスワードを保存したり、レスポンスで送信したりすることは絶対にしないでください。
すべての注意点を理解していて、自分が何をしているか分かっている場合を除き、ユーザーの平文のパスワードを保存したり、このようにレスポンスで送信したりしないでください。
///
## 出力モデルの追加
## 出力モデルの追加 { #add-an-output-model }
代わりに、平文のパスワードを持つ入力モデルと、パスワードを持たない出力モデルを作成することができます:
代わりに、平文のパスワードを持つ入力モデルと、パスワードを持たない出力モデルを作成できます:
{* ../../docs_src/response_model/tutorial003.py hl[9,11,16] *}
{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}
ここでは、*path operation関数*がパスワードを含む同じ入力ユーザーを返しているにもかかわらず:
ここでは、*パスオペレーション関数*がパスワードを含む同じ入力ユーザーを返しているにもかかわらず:
{* ../../docs_src/response_model/tutorial003.py hl[24] *}
{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}
...`response_model``UserOut`と宣言したことで、パスワードが含まれていません:
...`response_model`、パスワードを含まない `UserOut` モデルとして宣言しました:
{* ../../docs_src/response_model/tutorial003.py hl[22] *}
{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}
そのため、**FastAPI** は出力モデルで宣言されていないてのデータをフィルタリングしてくれますPydanticを使用
そのため、**FastAPI** は出力モデルで宣言されていないすべてのデータをフィルタリングしてくれますPydanticを使用
## ドキュメントを見る
### `response_model`または戻り値の型 { #response-model-or-return-type }
自動ドキュメントを見ると、入力モデルと出力モデルがそれぞれ独自のJSON Schemaを持っていることが確認できます。
このケースでは2つのモデルが異なるため、関数の戻り値の型を `UserOut` としてアノテーションすると、エディタやツールは、異なるクラスなので不正な型を返していると警告します。
<img src="https://fastapi.tiangolo.com/img/tutorial/response-model/image01.png">
そのため、この例では `response_model` パラメータで宣言する必要があります。
そして、両方のモデルは、対話型のAPIドキュメントに使用されます:
...しかし、これを解決する方法を以下で確認しましょう。
<img src="https://fastapi.tiangolo.com/img/tutorial/response-model/image02.png">
## 戻り値の型とデータフィルタリング { #return-type-and-data-filtering }
## レスポンスモデルのエンコーディングパラメータ
前の例から続けます。**関数に1つの型をアテーション**したい一方で、関数からは実際には**より多くのデータ**を含むものを返せるようにしたいとします。
レスポンスモデルにはデフォルト値を設定することができます:
FastAPIにはレスポンスモデルを使用してデータを**フィルタリング**し続けてほしいです。つまり、関数がより多くのデータを返しても、レスポンスにはレスポンスモデルで宣言されたフィールドのみが含まれます
{* ../../docs_src/response_model/tutorial004.py hl[11,13,14] *}
前の例ではクラスが異なるため `response_model` パラメータを使う必要がありました。しかしそれは、エディタやツールによる関数の戻り値の型チェックのサポートを受けられないことも意味します。
* `description: str = None``None`がデフォルト値です。
* `tax: float = 10.5``10.5`がデフォルト値です。
* `tags: List[str] = []` は空のリスト(`[]`)がデフォルト値です。
しかし、このようなことが必要になる多くのケースでは、この例のようにモデルでデータの一部を**フィルタ/削除**したいだけです。
しかし、実際に保存されていない場合には結果からそれらを省略した方が良いかもしれません
そのような場合、クラスと継承を利用して関数の**型アノテーション**を活用し、エディタやツールのサポートを改善しつつ、FastAPIの**データフィルタリング**も得られます
{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
これにより、このコードは型として正しいためエディタやmypyからのツール支援を得られますし、FastAPIによるデータフィルタリングも得られます。
これはどのように動作するのでしょうか?確認してみましょう。🤓
### 型アノテーションとツール支援 { #type-annotations-and-tooling }
まず、エディタ、mypy、その他のツールがこれをどう見るかを見てみます。
`BaseUser` には基本フィールドがあります。次に `UserIn``BaseUser` を継承して `password` フィールドを追加するため、両方のモデルのフィールドがすべて含まれます。
関数の戻り値の型を `BaseUser` としてアノテーションしますが、実際には `UserIn` インスタンスを返しています。
エディタやmypyなどのツールはこれに文句を言いません。typingの観点では、`UserIn``BaseUser` のサブクラスであり、期待されるものが `BaseUser` であれば `UserIn` は*有効*な型だからです。
### FastAPIのデータフィルタリング { #fastapi-data-filtering }
一方FastAPIでは、戻り値の型を見て、返す内容にその型で宣言されたフィールド**だけ**が含まれることを確認します。
FastAPIは、返却データのフィルタリングにクラス継承の同じルールが使われてしまわないようにするため、内部でPydanticを使っていくつかの処理を行っています。そうでないと、期待以上に多くのデータを返してしまう可能性があります。
この方法で、**ツール支援**付きの型アノテーションと**データフィルタリング**の両方という、いいとこ取りができます。
## ドキュメントを見る { #see-it-in-the-docs }
自動ドキュメントを見ると、入力モデルと出力モデルがそれぞれ独自のJSON Schemaを持っていることが確認できます:
<img src="/img/tutorial/response-model/image01.png">
そして、両方のモデルは対話型のAPIドキュメントに使用されます:
<img src="/img/tutorial/response-model/image02.png">
## その他の戻り値の型アノテーション { #other-return-type-annotations }
Pydanticフィールドとして有効ではないものを返し、ツールエディタやmypyなどが提供するサポートを得るためだけに、関数でそれをアテーションするケースがあるかもしれません。
### レスポンスを直接返す { #return-a-response-directly }
最も一般的なケースは、[高度なドキュメントで後述する「Responseを直接返す」](../advanced/response-directly.md){.internal-link target=_blank}場合です。
{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
このシンプルなケースは、戻り値の型アノテーションが `Response` のクラスまたはサブクラスであるため、FastAPIが自動的に処理します。
また `RedirectResponse``JSONResponse` の両方は `Response` のサブクラスなので、ツールも型アノテーションが正しいとして問題にしません。
### `Response`のサブクラスをアノテーションする { #annotate-a-response-subclass }
型アノテーションで `Response` のサブクラスを使うこともできます:
{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
これは `RedirectResponse``Response` のサブクラスであり、FastAPIがこのシンプルなケースを自動処理するため、同様に動作します。
### 無効な戻り値の型アノテーション { #invalid-return-type-annotations }
しかし、Pydantic型として有効ではない別の任意のオブジェクト例: データベースオブジェクトを返し、関数でそのようにアテーションすると、FastAPIはその型アテーションからPydanticレスポンスモデルを作成しようとして失敗します。
同様に、<abbr title='複数の型のunionは「これらの型のいずれか」を意味します。'>union</abbr>のように、複数の型のうち1つ以上がPydantic型として有効でないものを含む場合も起こります。例えば次は失敗します 💥:
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
...これは、型アテーションがPydantic型ではなく、単一の `Response` クラス(またはサブクラス)でもないために失敗します。`Response``dict` の間のunionどちらかになっているからです。
### レスポンスモデルを無効化する { #disable-response-model }
上の例を続けると、FastAPIが実行するデフォルトのデータ検証、ドキュメント化、フィルタリングなどを行いたくないこともあるでしょう。
しかし、エディタや型チェッカー(例: mypyなどのツール支援を得るために、関数の戻り値の型アテーションは残したいかもしれません。
その場合、`response_model=None` を設定することでレスポンスモデルの生成を無効にできます:
{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
これによりFastAPIはレスポンスモデル生成をスキップし、FastAPIアプリケーションに影響させずに必要な戻り値の型アテーションを付けられます。🤓
## レスポンスモデルのエンコーディングパラメータ { #response-model-encoding-parameters }
レスポンスモデルには次のようにデフォルト値を設定できます:
{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}
* `description: Union[str, None] = None`またはPython 3.10では `str | None = None`)はデフォルトが `None` です。
* `tax: float = 10.5` はデフォルトが `10.5` です。
* `tags: List[str] = []` はデフォルトが空のリスト `[]` です。
ただし、それらが実際には保存されていない場合、結果から省略したいことがあります。
例えば、NoSQLデータベースに多くのオプション属性を持つモデルがあるが、デフォルト値でいっぱいの非常に長いJSONレスポンスを送信したくない場合です。
### `response_model_exclude_unset`パラメータの使用
### `response_model_exclude_unset`パラメータの使用 { #use-the-response-model-exclude-unset-parameter }
*path operation デコレータ*に`response_model_exclude_unset=True`パラメータを設定することができます:
*パスオペレーションデコレータ*のパラメータ `response_model_exclude_unset=True` を設定できます:
{* ../../docs_src/response_model/tutorial004.py hl[24] *}
{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}
して、これらのデフォルト値はレスポンスに含まれず、実際に設定された値のみが含まれます。
うすると、デフォルト値はレスポンスに含まれず、実際に設定された値のみが含まれます。
そのため、*path operation*にID`foo`が設定されたitemのリクエストを送ると、レスポンスは以下のようになります(デフォルト値を含まない):
そのため、ID `foo` のitemに対してその *パスオペレーション*リクエストを送ると、レスポンスは以下のようになります(デフォルト値を含まない):
```JSON
{
@@ -116,26 +252,20 @@ FastAPIは`response_model`を使って以下のことをします:
/// info | 情報
FastAPIはこれをするために、Pydanticモデルの`.dict()`を<a href="https://docs.pydantic.dev/latest/concepts/serialization/#modeldict" class="external-link" target="_blank">その`exclude_unset`パラメータ</a>で使用しています
///
/// info | 情報
以下も使用することができます:
以下も使用できます:
* `response_model_exclude_defaults=True`
* `response_model_exclude_none=True`
`exclude_defaults``exclude_none`については、<a href="https://docs.pydantic.dev/latest/concepts/serialization/#modeldict" class="external-link" target="_blank">Pydanticのドキュメント</a>で説明されている通りです。
`exclude_defaults``exclude_none` については、<a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">Pydanticのドキュメント</a>で説明されている通りです。
///
#### デフォルト値を持つフィールドの値を持つデータ
#### デフォルト値を持つフィールドに値があるデータ { #data-with-values-for-fields-with-defaults }
しかし、ID`bar`のitemのように、デフォルト値が設定されているモデルのフィールドに値が設定されている場合:
しかし、ID `bar` のitemのように、デフォルト値が設定されているモデルのフィールドに値が設定されている場合:
```Python hl_lines="3 5"
```Python hl_lines="3 5"
{
"name": "Bar",
"description": "The bartenders",
@@ -146,11 +276,11 @@ FastAPIはこれをするために、Pydanticモデルの`.dict()`を<a href="ht
それらはレスポンスに含まれます。
#### デフォルト値と同じ値を持つデータ
#### デフォルト値と同じ値を持つデータ { #data-with-the-same-values-as-the-defaults }
ID`baz`のitemのようにデフォルト値と同じ値を持つデータの場合:
ID `baz` のitemのようにデフォルト値と同じ値を持つデータの場合:
```Python hl_lines="3 5 6"
```Python hl_lines="3 5-6"
{
"name": "Baz",
"description": None,
@@ -160,53 +290,54 @@ ID`baz`のitemのようにデフォルト値と同じ値を持つデータの場
}
```
FastAPIは十分に賢いので実際には、Pydanticが十分に賢い`description``tax`、`tags`デフォルト値と同じ値を持っているにもかかわらず、明示的に設定されていることを理解しています。(デフォルトから取得するのではなく)
FastAPIは十分に賢いので実際には、Pydanticが十分に賢い`description``tax`、`tags`デフォルト値と同じ値であっても、明示的に設定された(デフォルトから取得されたのではない)ことを理解します。
そのため、それらはJSONレスポンスに含まれることになります。
そのため、それらはJSONレスポンスに含まれます。
/// tip | 豆知識
デフォルト値は`None`だけでなく、なんでも良いことに注意してください。
例えば、リスト(`[]`)や`10.5`の`float`などです。
デフォルト値は `None` だけでないことに注意してください。
リスト(`[]`)や `10.5` の `float` などでも構いません。
///
### `response_model_include`と`response_model_exclude`
### `response_model_include`と`response_model_exclude` { #response-model-include-and-response-model-exclude }
*path operationデコレータ*として`response_model_include``response_model_exclude`も使用することができます。
*パスオペレーションデコレータ*のパラメータ `response_model_include``response_model_exclude` も使用できます。
属性名を持つ`str``set`を受け取り、含める(残りを省略する)か、除外(残りを含む)します。
これらは、含める(残りを省略する)または除外する(残りを含む)属性名を持つ `str``set` を受け取ります。
これは、Pydanticモデルがつしかなく、出力からいくつかのデータを削除したい場合のクイックショートカットとして使用することができます。
これは、Pydanticモデルが1つしかなく、出力からいくつかのデータを削除したい場合のクイックショートカットとして使用できます。
/// tip | 豆知識
それでも、これらのパラメータではなく、複数のクラスを使用して、上記のようなアイデアを使うことをおすすめします。
それでも、これらのパラメータではなく、上で示したアイデアのように複数のクラスを使うことが推奨されます。
これは`response_model_include``response_mode_exclude`を使用していくつかの属性を省略しても、アプリケーションのOpenAPIとドキュメントで生成されJSON Schemaが完全なモデルになるからです。
これは`response_model_include``response_model_exclude` を使ていくつかの属性を省略しても、アプリのOpenAPIとドキュメントで生成されJSON Schemaが完全なモデルのままになるためです。
同様に動作する`response_model_by_alias`にも当てはまります。
同様に動作する `response_model_by_alias` にも当てはまります。
///
{* ../../docs_src/response_model/tutorial005.py hl[31,37] *}
{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}
/// tip | 豆知識
`{"name", "description"}`の構文はれらつの値をもつ`set`を作成します。
`{"name", "description"}` の構文は、それら2つの値を持つ `set` を作成します。
これは`set(["name", "description"])`と同等です。
これは `set(["name", "description"])` と同等です。
///
#### `set`の代わりに`list`を使用する
#### `set`の代わりに`list`を使用する { #using-lists-instead-of-sets }
もし`set`を使用することを忘れて、代わりに`list``tuple`を使用しても、FastAPIはそれを`set`に変換して正しく動作します:
もし `set` を使用することを忘れて、代わりに `list``tuple` を使用しても、FastAPIはそれを `set` に変換して正しく動作します:
{* ../../docs_src/response_model/tutorial006.py hl[31,37] *}
{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}
## まとめ
## まとめ { #recap }
*path operationデコレータの*`response_model`パラメータを使用してレスポンスモデルを定義し、にプライベートデータがフィルタリングされていることを保証します。
*パスオペレーションデコレータ*のパラメータ `response_model` を使用してレスポンスモデルを定義し、とくにプライベートデータがフィルタリングされることを保証します。
明示的に設定された値のみを返すには、`response_model_exclude_unset`を使用します。
明示的に設定された値のみを返すには、`response_model_exclude_unset` を使用します。

View File

@@ -1,4 +1,4 @@
# レスポンスステータスコード
# レスポンスステータスコード { #response-status-code }
レスポンスモデルを指定するのと同じ方法で、レスポンスに使用されるHTTPステータスコードを以下の*path operations*のいずれかの`status_code`パラメータで宣言することもできます。
@@ -6,13 +6,13 @@
* `@app.post()`
* `@app.put()`
* `@app.delete()`
* など。
* etc.
{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
/// note | 備考
`status_code`は「デコレータ」メソッド(`get``post`など)のパラメータであることに注意してください。すべてのパラメータやボディのように、*path operation関数*のものではありません。
`status_code`は「デコレータ」メソッド(`get``post`など)のパラメータであることに注意してください。すべてのパラメータやボディのように、*path operation function*のものではありません。
///
@@ -29,7 +29,7 @@
* レスポンスでステータスコードを返します。
* OpenAPIスキーマおよびユーザーインターフェースに以下のように文書化します:
<img src="https://fastapi.tiangolo.com/img/tutorial/response-status-code/image01.png">
<img src="/img/tutorial/response-status-code/image01.png">
/// note | 備考
@@ -39,7 +39,7 @@ FastAPIはこれを知っていて、レスポンスボディがないというO
///
## HTTPステータスコードについて
## HTTPステータスコードについて { #about-http-status-codes }
/// note | 備考
@@ -47,34 +47,34 @@ FastAPIはこれを知っていて、レスポンスボディがないというO
///
HTTPでは、レスポンスの一部として桁の数字のステータスコードを送信します。
HTTPでは、レスポンスの一部として3桁の数字のステータスコードを送信します。
これらのステータスコードは、それらを認識するために関連付けられた名前を持っていますが、重要な部分は番号です。
つまり:
* `100`以上は「情報」のためのものです。直接使うことはほとんどありません。これらのステータスコードを持つレスポンスはボディを持つことができません。
* **`200`** 以上は「成功」のレスポンスのためのものです。これらは最も利用するであろうものです。
* `100 - 199` は「情報」のためのものです。直接使うことはほとんどありません。これらのステータスコードを持つレスポンスはボディを持つことができません。
* **`200 - 299`** は「成功」のレスポンスのためのものです。これらは最も利用するであろうものです。
* `200`はデフォルトのステータスコードで、すべてが「OK」であったことを意味します。
* 別の例としては、`201`Createdがあります。これはデータベースに新しいレコードを作成した後によく使用されます。
* 特殊なケースとして、`204`No Contentがあります。このレスポンスはクライアントに返すコンテンツがない場合に使用されます。そしてこのレスポンスはボディを持つことはできません。
* **`300`** 以上は「リダイレクト」のためのものです。これらのステータスコードを持つレスポンスは`304`Not Modifiedを除き、ボディを持つことも持たないこともできます。
* **`400`** 以上は「クライアントエラー」のレスポンスのためのものです。これらは、おそらく最も多用するであろう番目のタイプです。
* 特殊なケースとして、`204`No Contentがあります。このレスポンスはクライアントに返すコンテンツがない場合に使用されるため、レスポンスはボディを持ってはいけません。
* **`300 - 399`** は「リダイレクト」のためのものです。これらのステータスコードを持つレスポンスは`304`Not Modifiedを除き、ボディを持つことも持たないこともできます。`304`はボディを持ってはいけません。
* **`400 - 499`** は「クライアントエラー」のレスポンスのためのものです。これらは、おそらく最も多用するであろう2番目のタイプです。
* 例えば、`404`は「Not Found」レスポンスです。
* クライアントからの一般的なエラーについては、`400`を使用することができます。
* `500`以上はサーバーエラーのためのものです。これらを直接使うことはほとんどありません。アプリケーションコードやサーバーのどこかで何か問題が発生した場合、これらのステータスコードのいずれかが自動的に返されます。
* `500 - 599` はサーバーエラーのためのものです。これらを直接使うことはほとんどありません。アプリケーションコードやサーバーのどこかで何か問題が発生した場合、これらのステータスコードのいずれかが自動的に返されます。
/// tip | 豆知識
それぞれのステータスコードとどのコードが何のためのコードなのかについて詳細は<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> HTTP レスポンスステータスコードについてのドキュメント</a>を参照してください。
それぞれのステータスコードとどのコードが何のためのコードなのかについて詳細は<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> documentation about HTTP status codes</a>を参照してください。
///
## 名前を覚えるための近道
## 名前を覚えるための近道 { #shortcut-to-remember-the-names }
先ほどの例をもう一度見てみましょう:
{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *}
`201`は「作成完了」のためのステータスコードです。
@@ -82,11 +82,11 @@ HTTPでは、レスポンスの一部として桁の数字のステータス
`fastapi.status`の便利な変数を利用することができます。
{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *}
{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *}
それらは便利です。それらは同じ番号を保持しており、その方法ではエディタの自動補完を使用してそれらを見つけることができます。
それらは単なる便利なものであり、同じ番号を保持しています。しかし、その方法ではエディタの自動補完を使用してそれらを見つけることができます。
<img src="https://fastapi.tiangolo.com/img/tutorial/response-status-code/image02.png">
<img src="/img/tutorial/response-status-code/image02.png">
/// note | 技術詳細
@@ -96,6 +96,6 @@ HTTPでは、レスポンスの一部として桁の数字のステータス
///
## デフォルトの変更
## デフォルトの変更 { #changing-the-default }
後に、[高度なユーザーガイド](../advanced/response-change-status-code.md){.internal-link target=_blank}で、ここで宣言しているデフォルトとは異なるステータスコードを返す方法を見ていきます。

View File

@@ -1,55 +1,202 @@
# スキーマの追加 - 例
# リクエストのExampleデータの宣言 { #declare-request-example-data }
JSON Schemaに追加する情報を定義することができます。
アプリが受け取れるデータの例を宣言できます。
一般的なユースケースはこのドキュメントで示されているように`example`を追加することです。
ここでは、それを行ういくつかの方法を紹介します。
JSON Schemaの追加情報を宣言する方法はいくつかあります。
## Pydanticモデルでの追加JSON Schemaデータ { #extra-json-schema-data-in-pydantic-models }
## Pydanticの`schema_extra`
生成されるJSON Schemaに追加されるPydanticモデルの`examples`を宣言できます。
<a href="https://docs.pydantic.dev/latest/concepts/json_schema/#schema-customization" class="external-link" target="_blank">Pydanticのドキュメント: スキーマのカスタマイズ</a>で説明されているように、`Config``schema_extra`を使ってPydanticモデルの例を宣言することができます:
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
{* ../../docs_src/schema_extra_example/tutorial001.py hl[15,16,17,18,19,20,21,22,23] *}
その追加情報は、そのモデルの出力**JSON Schema**にそのまま追加され、APIドキュメントで使用されます。
その追加情報はそのまま出力され、JSON Schemaに追加されます。
<a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Pydanticのドキュメント: Configuration</a>で説明されているように、`dict`を受け取る属性`model_config`を使用できます。
## `Field`の追加引数
生成されるJSON Schemaに表示したい追加データ`examples`を含む)を含む`dict`を使って、`"json_schema_extra"`を設定できます。
後述する`Field``Path``Query``Body`などでは、任意の引数を関数に渡すことでJSON Schemaの追加情報を宣言することもできます:
/// tip | 豆知識
{* ../../docs_src/schema_extra_example/tutorial002.py hl[4,10,11,12,13] *}
同じ手法を使ってJSON Schemaを拡張し、独自のカスタム追加情報を追加できます。
/// warning | 注意
これらの追加引数が渡されても、文書化のためのバリデーションは追加されず、注釈だけが追加されることを覚えておいてください。
例えば、フロントエンドのユーザーインターフェースのためのメタデータを追加する、などに使えます。
///
## `Body`の追加引数
/// info | 情報
追加情報を`Field`に渡すのと同じように、`Path``Query``Body`などでも同じことができます
OpenAPI 3.1.0FastAPI 0.99.0以降で使用)では、**JSON Schema**標準の一部である`examples`がサポートされました
例えば、`Body`にボディリクエストの`example`を渡すことができます:
それ以前は、単一の例を持つキーワード`example`のみがサポートされていました。これはOpenAPI 3.1.0でも引き続きサポートされていますが、非推奨であり、JSON Schema標準の一部ではありません。そのため、`example`から`examples`への移行が推奨されます。🤓
{* ../../docs_src/schema_extra_example/tutorial003.py hl[21,22,23,24,25,26] *}
詳細はこのページの最後で読めます。
## ドキュメントのUIの例
///
## `Field`の追加引数 { #field-additional-arguments }
Pydanticモデルで`Field()`を使う場合、追加の`examples`も宣言できます:
{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}
## JSON Schema内の`examples` - OpenAPI { #examples-in-json-schema-openapi }
以下のいずれかを使用する場合:
* `Path()`
* `Query()`
* `Header()`
* `Cookie()`
* `Body()`
* `Form()`
* `File()`
追加情報を含む`examples`のグループを宣言でき、それらは**OpenAPI**内のそれぞれの**JSON Schemas**に追加されます。
### `examples`を使う`Body` { #body-with-examples }
ここでは、`Body()`で期待されるデータの例を1つ含む`examples`を渡します:
{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}
### ドキュメントUIでの例 { #example-in-the-docs-ui }
上記のいずれの方法でも、`/docs`の中では以下のようになります:
<img src="https://fastapi.tiangolo.com/img/tutorial/body-fields/image01.png">
<img src="/img/tutorial/body-fields/image01.png">
## 技術詳細
### 複数の`examples`を使う`Body` { #body-with-multiple-examples }
`example``examples`について...
もちろん、複数の`examples`を渡すこともできます:
JSON Schemaの最新バージョンでは<a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a>というフィールドを定義していますが、OpenAPIは`examples`を持たない古いバージョンのJSON Schemaをベースにしています。
{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}
そのため、OpenAPIでは同じ目的のために<a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#fixed-fields-20" class="external-link" target="_blank">`example`</a>を独自に定義しており(`examples`ではなく`example`として、それがdocs UISwagger UIを使用で使用されています。
この場合、examplesはそのボディデータの内部**JSON Schema**の一部になります。
つまり、`example`はJSON Schemaの一部ではありませんが、OpenAPIの一部であり、それがdocs UIで使用されることになります
それでも、<abbr title="2023-08-26">執筆時点</abbr>では、ドキュメントUIの表示を担当するツールであるSwagger UIは、**JSON Schema**内のデータに対して複数の例を表示することをサポートしていません。しかし、回避策については以下を読んでください
## その他の情報
### OpenAPI固有の`examples` { #openapi-specific-examples }
同じように、フロントエンドのユーザーインターフェースなどをカスタマイズするために、各モデルのJSON Schemaに追加される独自の追加情報を追加することができます
**JSON Schema**が`examples`をサポートする前から、OpenAPIは同じく`examples`という別のフィールドをサポートしていました
この**OpenAPI固有**の`examples`は、OpenAPI仕様の別のセクションに入ります。各JSON Schemaの中ではなく、**各*パスオペレーション*の詳細**に入ります。
そしてSwagger UIは、この特定の`examples`フィールドを以前からサポートしています。そのため、これを使って**ドキュメントUIに異なる例を表示**できます。
このOpenAPI固有フィールド`examples`の形は**複数の例**`list`ではなく)を持つ`dict`であり、それぞれに追加情報が含まれ、その追加情報は**OpenAPI**にも追加されます。
これはOpenAPIに含まれる各JSON Schemaの中には入らず、外側の、*パスオペレーション*に直接入ります。
### `openapi_examples`パラメータの使用 { #using-the-openapi-examples-parameter }
FastAPIでは、以下に対してパラメータ`openapi_examples`を使って、OpenAPI固有の`examples`を宣言できます:
* `Path()`
* `Query()`
* `Header()`
* `Cookie()`
* `Body()`
* `Form()`
* `File()`
`dict`のキーは各例を識別し、各値は別の`dict`です。
`examples`内の各特定の例`dict`には、次の内容を含められます:
* `summary`: 例の短い説明。
* `description`: Markdownテキストを含められる長い説明。
* `value`: 実際に表示される例(例: `dict`)。
* `externalValue`: `value`の代替で、例を指すURLです。ただし、`value`ほど多くのツールでサポートされていない可能性があります。
次のように使えます:
{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}
### ドキュメントUIのOpenAPI Examples { #openapi-examples-in-the-docs-ui }
`Body()``openapi_examples`を追加すると、`/docs`は次のようになります:
<img src="/img/tutorial/body-fields/image02.png">
## 技術詳細 { #technical-details }
/// tip | 豆知識
すでに**FastAPI**バージョン**0.99.0以上**を使用している場合、おそらくこれらの詳細は**スキップ**できます。
これらは、OpenAPI 3.1.0が利用可能になる前の古いバージョンにより関連します。
これは簡単なOpenAPIとJSON Schemaの**歴史の授業**だと考えられます。🤓
///
/// warning | 注意
ここでは、標準である**JSON Schema**と**OpenAPI**についての非常に技術的な詳細を扱います。
上のアイデアがすでにうまく動いているなら、それで十分かもしれませんし、おそらくこの詳細は不要です。気軽にスキップしてください。
///
OpenAPI 3.1.0より前は、OpenAPIは古く改変されたバージョンの**JSON Schema**を使用していました。
JSON Schemaには`examples`がなかったため、OpenAPIは自身が改変したバージョンに独自の`example`フィールドを追加しました。
OpenAPIは、仕様の他の部分にも`example``examples`フィールドを追加しました:
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object" class="external-link" target="_blank">`Parameter Object`(仕様内)</a>。FastAPIの以下で使用されました:
* `Path()`
* `Query()`
* `Header()`
* `Cookie()`
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object" class="external-link" target="_blank">`Request Body Object`。仕様内の`Media Type Object``content`フィールド(仕様内)</a>。FastAPIの以下で使用されました:
* `Body()`
* `File()`
* `Form()`
/// info | 情報
この古いOpenAPI固有の`examples`パラメータは、FastAPI `0.103.0`以降は`openapi_examples`になりました。
///
### JSON Schemaの`examples`フィールド { #json-schemas-examples-field }
しかしその後、JSON Schemaは新しいバージョンの仕様に<a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a>フィールドを追加しました。
そして、新しいOpenAPI 3.1.0は、この新しいフィールド`examples`を含む最新バージョンJSON Schema 2020-12に基づくようになりました。
そして現在、この新しい`examples`フィールドは、古い単一(かつカスタム)の`example`フィールドより優先され、`example`は現在非推奨です。
JSON Schemaのこの新しい`examples`フィールドは、OpenAPIの他の場所上で説明にあるような追加メタデータを持つdictではなく、**単なる例の`list`**です。
/// info | 情報
OpenAPI 3.1.0がこのJSON Schemaとの新しいよりシンプルな統合とともにリリースされた後も、しばらくの間、自動ドキュメントを提供するツールであるSwagger UIはOpenAPI 3.1.0をサポートしていませんでしたバージョン5.0.0からサポートされています🎉)。
そのため、FastAPI 0.99.0より前のバージョンは、OpenAPI 3.1.0より低いバージョンのOpenAPIをまだ使用していました。
///
### PydanticとFastAPIの`examples` { #pydantic-and-fastapi-examples }
Pydanticモデル内で、`schema_extra`または`Field(examples=["something"])`を使って`examples`を追加すると、その例はそのPydanticモデルの**JSON Schema**に追加されます。
そしてそのPydanticモデルの**JSON Schema**はAPIの**OpenAPI**に含まれ、ドキュメントUIで使用されます。
FastAPI 0.99.0より前のバージョン0.99.0以上は新しいOpenAPI 3.1.0を使用)では、他のユーティリティ(`Query()``Body()`など)で`example`または`examples`を使っても、それらの例はそのデータを説明するJSON SchemaOpenAPI独自版のJSON Schemaでさえには追加されず、OpenAPI内の*パスオペレーション*宣言に直接追加されていましたJSON Schemaを使用するOpenAPIの部分の外側
しかし、FastAPI 0.99.0以上ではOpenAPI 3.1.0を使用し、それはJSON Schema 2020-12とSwagger UI 5.0.0以上を使うため、すべてがより一貫し、例はJSON Schemaに含まれます。
### Swagger UIとOpenAPI固有の`examples` { #swagger-ui-and-openapi-specific-examples }
Swagger UIは複数のJSON Schema examplesをサポートしていなかった2023-08-26時点ため、ユーザーはドキュメントで複数の例を表示する手段がありませんでした。
それを解決するため、FastAPI `0.103.0`は、新しいパラメータ`openapi_examples`で、同じ古い**OpenAPI固有**の`examples`フィールドを宣言するための**サポートを追加**しました。🤓
### まとめ { #summary }
昔は歴史があまり好きではないと言っていました...が、今の私は「技術の歴史」の授業をしています。😅
要するに、**FastAPI 0.99.0以上にアップグレード**してください。そうすれば、物事はもっと**シンプルで一貫性があり直感的**になり、これらの歴史的詳細を知る必要もありません。😎

View File

@@ -1,4 +1,4 @@
# セキュリティ - 最初の一歩
# セキュリティ - 最初の一歩 { #security-first-steps }
あるドメインに、**バックエンド** APIを持っているとしましょう。
@@ -12,25 +12,31 @@
**FastAPI**が提供するツールを使って、セキュリティを制御してみましょう。
## どう見えるか
## どう見えるか { #how-it-looks }
まずはこのコードを使って、どう動くか観察します。その後で、何が起こっているのか理解しましょう。
## `main.py`を作成
## `main.py`を作成 { #create-main-py }
`main.py`に、下記の例をコピーします:
{* ../../docs_src/security/tutorial001.py *}
{* ../../docs_src/security/tutorial001_an_py39.py *}
## 実行
## 実行 { #run-it }
/// info | 情報
まず<a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>インストールます。
<a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a> パッケージは、`pip install "fastapi[standard]"` コマンドを実行すると **FastAPI** と一緒に自動的にインストールされます。
例えば`pip install python-multipart`
しかし`pip install fastapi` コマンドを使用する場合、`python-multipart` パッケージはデフォルトでは含まれません
これは、**OAuth2**が `ユーザー名``パスワード` を送信するために、「フォームデータ」を使うからです。
手動でインストールするには、[仮想環境](../../virtual-environments.md){.internal-link target=_blank}を作成して有効化し、次のコマンドでインストールしてください:
```console
$ pip install python-multipart
```
これは、**OAuth2**が `username``password` を送信するために、「フォームデータ」を使うからです。
///
@@ -39,14 +45,14 @@
<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)
```
</div>
## 確認
## 確認 { #check-it }
次のインタラクティブなドキュメントにアクセスしてください: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>。
@@ -58,11 +64,11 @@ $ uvicorn main:app --reload
すでにピカピカの新しい「Authorize」ボタンがあります。
そして、あなたの*path operation*には、右上にクリックできる小さな鍵アイコンがあります。
そして、あなたの*パスオペレーション*には、右上にクリックできる小さな鍵アイコンがあります。
///
それをクリックすると、`ユーザー名``パスワード` (およびその他のオプションフィールド) を入力する小さな認フォームが表示されます:
それをクリックすると、`username``password`およびその他のオプションフィールドを入力する小さな認フォームが表示されます:
<img src="/img/tutorial/security/image02.png">
@@ -80,11 +86,11 @@ $ uvicorn main:app --reload
また、同じアプリケーションのデバッグ、チェック、テストのためにも利用できます。
## `パスワード` フロー
## `password` フロー { #the-password-flow }
では、少し話を戻して、どうなっているか理解しましょう。
`パスワード`の「フロー」は、OAuth2で定義されているセキュリティと認証を扱う方法 (「フロー」) の1つです。
`password`の「フロー」は、OAuth2で定義されているセキュリティと認証を扱う方法 (「フロー」) の1つです。
OAuth2は、バックエンドやAPIがユーザーを認証するサーバーから独立したものとして設計されていました。
@@ -92,9 +98,9 @@ OAuth2は、バックエンドやAPIがユーザーを認証するサーバー
そこで、簡略化した箇所から見直してみましょう:
* ユーザーはフロントエンドで`ユーザー名``パスワード`を入力し、`Enter`を押します。
* フロントエンド (ユーザーのブラウザで実行中) は、`ユーザー名``パスワード`をAPIの特定のURL (`tokenUrl="token"`で宣言された) に送信します。
* APIは`ユーザー名``パスワード`をチェックし、「トークン」を返却します (まだ実装していません)。
* ユーザーはフロントエンドで`username``password`を入力し、`Enter`を押します。
* フロントエンド (ユーザーのブラウザで実行中) は、`username``password`をAPIの特定のURL (`tokenUrl="token"`で宣言された) に送信します。
* APIは`username``password`をチェックし、「トークン」を返却します (まだ実装していません)。
* 「トークン」はただの文字列であり、あとでこのユーザーを検証するために使用します。
* 通常、トークンは時間が経つと期限切れになるように設定されています。
* トークンが期限切れの場合は、再度ログインする必要があります。
@@ -106,11 +112,11 @@ OAuth2は、バックエンドやAPIがユーザーを認証するサーバー
* したがって、APIで認証するため、HTTPヘッダー`Authorization``Bearer`の文字列とトークンを加えた値を送信します。
* トークンに`foobar`が含まれている場合、`Authorization`ヘッダーの内容は次のようになります: `Bearer foobar`
## **FastAPI**の`OAuth2PasswordBearer`
## **FastAPI**の`OAuth2PasswordBearer` { #fastapis-oauth2passwordbearer }
**FastAPI**は、これらのセキュリティ機能を実装するために、抽象度の異なる複数のツールを提供しています。
この例では、**Bearer**トークンを使用して**OAuth2**を**パスワード**フローで使用します。これには`OAuth2PasswordBearer`クラスを使用します。
この例では、**Bearer**トークンを使用して**OAuth2**を**Password**フローで使用します。これには`OAuth2PasswordBearer`クラスを使用します。
/// info | 情報
@@ -124,9 +130,9 @@ OAuth2は、バックエンドやAPIがユーザーを認証するサーバー
///
`OAuth2PasswordBearer` クラスのインスタンスを作成する時に、パラメーター`tokenUrl`を渡します。このパラメーターには、クライアント (ユーザーのブラウザで動作するフロントエンド) がトークンを取得するために`ユーザー名``パスワード`を送信するURLを指定します。
`OAuth2PasswordBearer` クラスのインスタンスを作成する時に、パラメーター`tokenUrl`を渡します。このパラメーターには、クライアント (ユーザーのブラウザで動作するフロントエンド) がトークンを取得するために`username``password`を送信するURLを指定します。
{* ../../docs_src/security/tutorial001.py hl[6] *}
{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}
/// tip | 豆知識
@@ -134,13 +140,13 @@ OAuth2は、バックエンドやAPIがユーザーを認証するサーバー
相対URLを使っているので、APIが`https://example.com/`にある場合、`https://example.com/token`を参照します。しかし、APIが`https://example.com/api/v1/`にある場合は`https://example.com/api/v1/token`を参照することになります。
相対 URL を使うことは、[プロキシと接続](../../advanced/behind-a-proxy.md){.internal-link target=_blank}のような高度なユースケースでもアプリケーションを動作させ続けるために重要です。
相対 URL を使うことは、[プロキシの背後](../../advanced/behind-a-proxy.md){.internal-link target=_blank}のような高度なユースケースでもアプリケーションを動作させ続けるために重要です。
///
このパラメーターはエンドポイント/ *path operation*を作成しません。しかし、URL`/token`はクライアントがトークンを取得するために使用するものであると宣言します。この情報は OpenAPI やインタラクティブな API ドキュメントシステムで使われます。
このパラメーターはエンドポイント/ *パスオペレーション*を作成しません。しかし、URL`/token`はクライアントがトークンを取得するために使用するものであると宣言します。この情報は OpenAPI やインタラクティブな API ドキュメントシステムで使われます。
実際のpath operationもすぐに作ります。
実際のパスオペレーションもすぐに作ります。
/// info | 情報
@@ -160,13 +166,13 @@ oauth2_scheme(some, parameters)
そのため、`Depends`と一緒に使うことができます。
### 使い方
### 使い方 { #use-it }
これで`oauth2_scheme``Depends`で依存関係に渡すことができます。
{* ../../docs_src/security/tutorial001.py hl[10] *}
{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
この依存関係は、*path operation function*のパラメーター`token`に代入される`str`を提供します。
この依存関係は、*パスオペレーション関数*のパラメーター`token`に代入される`str`を提供します。
**FastAPI**は、この依存関係を使用してOpenAPIスキーマ (および自動APIドキュメント) で「セキュリティスキーム」を定義できることを知っています。
@@ -178,13 +184,13 @@ OpenAPIと統合するセキュリティユーティリティ (および自動AP
///
## どのように動作するか
## 何をするか { #what-it-does }
リクエストの中に`Authorization`ヘッダーを探しに行き、その値が`Bearer`と何らかのトークンを含んでいるかどうかをチェックし、そのトークンを`str`として返します。
リクエストの中に`Authorization`ヘッダーを探しに行き、その値が`Bearer `と何らかのトークンを含んでいるかどうかをチェックし、そのトークンを`str`として返します。
もし`Authorization`ヘッダーが見つからなかったり、値が`Bearer`トークンを持っていなかったりすると、401 ステータスコードエラー (`UNAUTHORIZED`) で直接応答します。
もし`Authorization`ヘッダーが見つからなかったり、値が`Bearer `トークンを持っていなかったりすると、401 ステータスコードエラー (`UNAUTHORIZED`) で直接応答します。
トークンが存在するかどうかをチェックしてエラーを返す必要はありません。関数が実行された場合、そのトークンに`str`が含まれているか確認できます。
トークンが存在するかどうかをチェックしてエラーを返す必要はありません。関数が実行された場合、そのトークンに`str`が含まれていることを確信できます。
インタラクティブなドキュメントですでに試すことができます:
@@ -192,6 +198,6 @@ OpenAPIと統合するセキュリティユーティリティ (および自動AP
まだトークンの有効性を検証しているわけではありませんが、これはもう始まっています。
## まとめ
## まとめ { #recap }
つまり、たった3~4行の追加で、すでに何らかの基礎的なセキュリティの形になっています。

View File

@@ -1,22 +1,22 @@
# 現在のユーザーの取得
# 現在のユーザーの取得 { #get-current-user }
一つ前の章では、(依存性注入システムに基づいた)セキュリティシステムは、 *path operation関数*`str` として `token` を与えていました:
一つ前の章では、(依存性注入システムに基づいた)セキュリティシステムは、 *パスオペレーション関数*`str` として `token` を与えていました:
{* ../../docs_src/security/tutorial001.py hl[10] *}
{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
しかし、それはまだそんなに有用ではありません。
現在のユーザーを取得するようにしてみましょう。
## ユーザーモデルの作成
## ユーザーモデルの作成 { #create-a-user-model }
まずは、Pydanticのユーザーモデルを作成しましょう。
ボディを宣言するのにPydanticを使用するのと同じやり方で、Pydanticを別のどんなところでも使うことができます:
{* ../../docs_src/security/tutorial002.py hl[5,12:16] *}
{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
## 依存関係 `get_current_user` を作成
## 依存関係 `get_current_user` を作成 { #create-a-get-current-user-dependency }
依存関係 `get_current_user` を作ってみましょう。
@@ -24,21 +24,21 @@
`get_current_user` は前に作成した `oauth2_scheme` と同じ依存関係を持ちます。
以前直接 *path operation* の中でしていたのと同じように、新しい依存関係である `get_current_user``str` として `token` を受け取るようになります:
以前直接 *パスオペレーション* の中でしていたのと同じように、新しい依存関係である `get_current_user`サブ依存関係である `oauth2_scheme` から `str` として `token` を受け取るようになります:
{* ../../docs_src/security/tutorial002.py hl[25] *}
{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}
## ユーザーの取得
## ユーザーの取得 { #get-the-user }
`get_current_user` は作成した(偽物の)ユーティリティ関数を使って、 `str` としてトークンを受け取り、先ほどのPydanticの `User` モデルを返却します:
{* ../../docs_src/security/tutorial002.py hl[19:22,26:27] *}
{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}
## 現在のユーザーの注入
## 現在のユーザーの注入 { #inject-the-current-user }
ですので、 `get_current_user` に対して同様に *path operation* の中で `Depends` を利用できます。
ですので、 `get_current_user` に対して同様に *パスオペレーション* の中で `Depends` を利用できます。
{* ../../docs_src/security/tutorial002.py hl[31] *}
{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}
Pydanticモデルの `User` として、 `current_user` の型を宣言することに注意してください。
@@ -54,15 +54,15 @@ Pydanticモデルの `User` として、 `current_user` の型を宣言するこ
/// check | 確認
依存関係システムがこのように設計されているおかげで、 `User` モデルを返却する別の依存関係(別の"dependables")を持つことができます。
依存関係システムがこのように設計されているおかげで、 `User` モデルを返却する別の依存関係(別のdependables)を持つことができます。
同じデータ型を返却する依存関係は一つだけしか持てない、という制約が入ることはないのです。
///
## 別のモデル
## 別のモデル { #other-models }
これで、*path operation関数* の中で現在のユーザーを直接取得し、`Depends` を使って、 **依存性注入** レベルでセキュリティメカニズムを処理できるようになりました。
これで、*パスオペレーション関数* の中で現在のユーザーを直接取得し、`Depends` を使って、 **依存性注入** レベルでセキュリティメカニズムを処理できるようになりました。
そして、セキュリティ要件のためにどんなモデルやデータでも利用することができます。(この場合は、 Pydanticモデルの `User`
@@ -76,10 +76,9 @@ Pydanticモデルの `User` として、 `current_user` の型を宣言するこ
あなたのアプリケーションに必要なのがどんな種類のモデル、どんな種類のクラス、どんな種類のデータベースであったとしても、 **FastAPI** は依存性注入システムでカバーしてくれます。
## コードサイズ { #code-size }
## コードサイズ
この例は冗長に見えるかもしれません。セキュリティとデータモデルユーティリティ関数および *path operations* が同じファイルに混在しているということを覚えておいてください。
この例は冗長に見えるかもしれません。セキュリティとデータモデルユーティリティ関数および *パスオペレーション* が同じファイルに混在しているということを覚えておいてください。
しかし、ここに重要なポイントがあります。
@@ -87,20 +86,20 @@ Pydanticモデルの `User` として、 `current_user` の型を宣言するこ
そして、それは好きなだけ複雑にすることができます。それでも、一箇所に、一度だけ書くのです。すべての柔軟性を備えます。
しかし、同じセキュリティシステムを使って何千ものエンドポイント(*path operations*)を持つことができます。
しかし、同じセキュリティシステムを使って何千ものエンドポイント(*パスオペレーション*)を持つことができます。
そして、それらエンドポイントのすべて(必要な、どの部分でも)がこうした依存関係や、あなたが作成する別の依存関係を再利用する利点を享受できるのです。
さらに、こうした何千もの *path operations* は、たった3行で表現できるのです:
さらに、こうした何千もの *パスオペレーション* は、たった3行で表現できるのです:
{* ../../docs_src/security/tutorial002.py hl[30:32] *}
{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}
## まとめ
## まとめ { #recap }
これで、 *path operation関数* の中で直接現在のユーザーを取得できるようになりました。
これで、 *パスオペレーション関数* の中で直接現在のユーザーを取得できるようになりました。
既に半分のところまで来ています。
あとは、 `username``password`実際にそのユーザーやクライアントに送る、 *path operation* を追加する必要があるだけです。
あとは、ユーザー/クライアントが実際に `username``password`送信するための *パスオペレーション* を追加する必要があるだけです。
次はそれを説明します。

View File

@@ -1,4 +1,4 @@
# パスワードおよびハッシュ化によるOAuth2、JWTトークンによるBearer
# パスワードおよびハッシュ化によるOAuth2、JWTトークンによるBearer { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }
これでセキュリティの流れが全てわかったので、<abbr title="JSON Web Tokens">JWT</abbr>トークンと安全なパスワードのハッシュ化を使用して、実際にアプリケーションを安全にしてみましょう。
@@ -6,7 +6,7 @@
本章では、前章の続きから始めて、コードをアップデートしていきます。
## JWT について
## JWT について { #about-jwt }
JWTとは「JSON Web Tokens」の略称です。
@@ -26,33 +26,31 @@ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4
JWT トークンを使って遊んでみたいという方は、<a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a> をチェックしてください。
## `python-jose` のインストール
## `PyJWT` のインストール { #install-pyjwt }
PythonでJWTトークンの生成と検証を行うために、`python-jose`をインストールする必要があります
PythonでJWTトークンの生成と検証を行うために、`PyJWT`をインストールする必要があります
[仮想環境](../../virtual-environments.md){.internal-link target=_blank}を作成し、アクティベートしてから、`pyjwt`をインストールしてください。
<div class="termy">
```console
$ pip install python-jose[cryptography]
$ pip install pyjwt
---> 100%
```
</div>
また、<a href="https://github.com/mpdavis/python-jose" class="external-link" target="_blank">Python-jose</a>だけではなく、暗号を扱うためのパッケージを追加で必要とします。
/// info | 情報
ここでは、推奨されているものを使用します:<a href="https://cryptography.io/" class="external-link" target="_blank">pyca/cryptography</a>
RSAやECDSAのようなデジタル署名アルゴリズムを使用する予定がある場合は、cryptographyライブラリの依存関係`pyjwt[crypto]`をインストールしてください
/// tip | 豆知識
このチュートリアルでは以前、<a href="https://pyjwt.readthedocs.io/" class="external-link" target="_blank">PyJWT</a>を使用していました。
しかし、Python-joseは、PyJWTのすべての機能に加えて、後に他のツールと統合して構築する際におそらく必要となる可能性のあるいくつかの追加機能を提供しています。そのため、代わりにPython-joseを使用するように更新されました。
詳細は<a href="https://pyjwt.readthedocs.io/en/latest/installation.html" class="external-link" target="_blank">PyJWT Installation docs</a>で確認できます。
///
## パスワードのハッシュ化
## パスワードのハッシュ化 { #password-hashing }
「ハッシュ化」とは、あるコンテンツ(ここではパスワード)を、規則性のないバイト列(単なる文字列)に変換することです。
@@ -60,26 +58,26 @@ $ pip install python-jose[cryptography]
しかし、規則性のないバイト列から元のパスワードに戻すことはできません。
### パスワードのハッシュ化を使う理由
### パスワードのハッシュ化を使う理由 { #why-use-password-hashing }
データベースが盗まれても、ユーザーの平文のパスワードは盗まれず、ハッシュ値だけが盗まれます。
したがって、泥棒はそのパスワードを別のシステムで使えません(多くのユーザーはどこでも同じパスワードを使用しているため、危険性があります)。
## `passlib` のインストール
## `pwdlib` のインストール { #install-pwdlib }
PassLib は、パスワードのハッシュを処理するための優れたPythonパッケージです。
pwdlib は、パスワードのハッシュを処理するための優れたPythonパッケージです。
このパッケージは、多くの安全なハッシュアルゴリズムとユーティリティをサポートします。
推奨されるアルゴリズムは「Bcrypt」です。
推奨されるアルゴリズムは「Argon2」です。
そのため、Bcryptを指定してPassLibをインストールします:
[仮想環境](../../virtual-environments.md){.internal-link target=_blank}を作成し、アクティベートしてから、Argon2付きでpwdlibをインストールしてください。
<div class="termy">
```console
$ pip install passlib[bcrypt]
$ pip install "pwdlib[argon2]"
---> 100%
```
@@ -88,7 +86,7 @@ $ pip install passlib[bcrypt]
/// tip | 豆知識
`passlib`を使用すると、**Django**や**Flask**のセキュリティプラグインなどで作成されたパスワードを読み取れるように設定できます。
`pwdlib`を使用すると、**Django**や**Flask**のセキュリティプラグインなどで作成されたパスワードを読み取れるように設定できます。
例えば、Djangoアプリケーションからデータベース内の同じデータをFastAPIアプリケーションと共有できるだけではなく、同じデータベースを使用してDjangoアプリケーションを徐々に移行することもできます。
@@ -96,17 +94,17 @@ $ pip install passlib[bcrypt]
///
## パスワードのハッシュ化と検証
## パスワードのハッシュ化と検証 { #hash-and-verify-the-passwords }
必要なツールを `passlib`からインポートします。
必要なツールを `pwdlib`からインポートします。
PassLib の「context」を作成します。これは、パスワードのハッシュ化と検証に使用されるものです。
推奨設定でPasswordHashインスタンスを作成します。これは、パスワードのハッシュ化と検証に使用されす。
/// tip | 豆知識
PassLibのcontextには、検証だけが許された非推奨の古いハッシュアルゴリズムを含む、様々なハッシュアルゴリズムを使用した検証機能もあります。
pwdlibはbcryptハッシュアルゴリズムもサポートしていますが、レガシーアルゴリズムは含みません。古いハッシュを扱うには、passlibライブラリを使用することが推奨されます。
例えば、この機能を使用して、別のシステムDjangoなどによって生成されたパスワードを読み取って検証し、Bcryptなどの別のアルゴリズムを使用して新しいパスワードをハッシュするといったことができます。
例えば、この機能を使用して、別のシステムDjangoなどによって生成されたパスワードを読み取って検証し、Argon2やBcryptなどの別のアルゴリズムを使用して新しいパスワードをハッシュするといったことができます。
そして、同時にそれらはすべてに互換性があります。
@@ -118,15 +116,15 @@ PassLibのcontextには、検証だけが許された非推奨の古いハッシ
さらに、ユーザーを認証して返す関数も作成します。
{* ../../docs_src/security/tutorial004.py hl[7,48,55:56,59:60,69:75] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
/// note | 備考
新しい(偽の)データベース`fake_users_db`を確認すると、ハッシュ化されたパスワードが次のようになっていることがわかります:`"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`
新しい(偽の)データベース`fake_users_db`を確認すると、ハッシュ化されたパスワードが次のようになっていることがわかります:`"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`
///
## JWTトークンの取り扱い
## JWTトークンの取り扱い { #handle-jwt-tokens }
インストールした複数のモジュールをインポートします。
@@ -148,33 +146,33 @@ $ openssl rand -hex 32
JWTトークンの署名に使用するアルゴリズム`"HS256"`を指定した変数`ALGORITHM`を作成します。
トークンの有効期限を指定した変数`ACCESS_TOKEN_EXPIRE_MINUTES`を作成します。
トークンの有効期限を指定した変数を作成します。
レスポンスのトークンエンドポイントで使用するPydanticモデルを定義します。
新しいアクセストークンを生成するユーティリティ関数を作成します。
{* ../../docs_src/security/tutorial004.py hl[6,12:14,28:30,78:86] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
## 依存関係の更新
## 依存関係の更新 { #update-the-dependencies }
`get_current_user`を更新して、先ほどと同じトークンを受け取るようにしますが、今回はJWTトークンを使用します。
受け取ったトークンを復号して検証し、現在のユーザーを返します。
受け取ったトークンをデコードして検証し、現在のユーザーを返します。
トークンが無効な場合は、すぐにHTTPエラーを返します。
{* ../../docs_src/security/tutorial004.py hl[89:106] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
## `/token` パスオペレーションの更新
## `/token` *パスオペレーション* の更新 { #update-the-token-path-operation }
トークンの有効期限を表す`timedelta`を作成します。
JWTアクセストークンを作成し、それを返します。
実際のJWTアクセストークンを作成し、それを返します。
{* ../../docs_src/security/tutorial004.py hl[115:130] *}
{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
### JWTの"subject" `sub` についての技術的な詳細
### JWTのsubject`sub` についての技術的な詳細 { #technical-details-about-the-jwt-subject-sub }
JWTの仕様では、トークンのsubjectを表すキー`sub`があるとされています。
@@ -192,13 +190,13 @@ JWTは、ユーザーを識別して、そのユーザーがAPI上で直接操
しかしながら、それらのエンティティのいくつかが同じIDを持つ可能性があります。例えば、`foo`(ユーザー`foo`、車 `foo`、ブログ投稿`foo`)などです。
IDの衝突を回避するために、ユーザーのJWTトークンを作成するとき、subキーの値にプレフィックスを付けることができます例えば、`username:`)。したがって、この例では、`sub`の値は次のようになっている可能性があります:`username:johndoe`
IDの衝突を回避するために、ユーザーのJWTトークンを作成するとき、subキーの値にプレフィックスを付けることができます例えば、`username:`)。したがって、この例では、`sub`の値は次のようになっている可能性があります:`username:johndoe`
覚えておくべき重要なことは、`sub`キーはアプリケーション全体で一意の識別子を持ち、文字列である必要があるということです。
## 確認
## 確認 { #check-it }
サーバーを実行し、ドキュメントに移動します:<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>
次のようなユーザーインターフェイスが表示されます:
@@ -232,17 +230,17 @@ Password: `secret`
<img src="/img/tutorial/security/image09.png">
開発者ツールを開くと、送信されるデータにはトークンだけが含まれており、パスワードはユーザーを認証してアクセストークンを取得する最初のリクエストでのみ送信され、その後は送信されないことがわかります
開発者ツールを開くと、送信されるデータにはトークンだけが含まれており、パスワードはユーザーを認証してアクセストークンを取得する最初のリクエストでのみ送信され、その後は送信されないことがわかります
<img src="/img/tutorial/security/image10.png">
/// note | 備考
ヘッダーの`Authorization`には、`Bearer`で始まる値があります。
ヘッダーの`Authorization`には、`Bearer `で始まる値があります。
///
## `scopes` を使った高度なユースケース
## `scopes` を使った高度なユースケース { #advanced-usage-with-scopes }
OAuth2には、「スコープ」という概念があります。
@@ -252,7 +250,7 @@ OAuth2には、「スコープ」という概念があります。
これらの使用方法や**FastAPI**への統合方法については、**高度なユーザーガイド**で後ほど説明します。
## まとめ
## まとめ { #recap }
ここまでの説明で、OAuth2やJWTなどの規格を使った安全な**FastAPI**アプリケーションを設定することができます。
@@ -266,7 +264,7 @@ OAuth2には、「スコープ」という概念があります。
そのため、プロジェクトに合わせて自由に選択することができます。
また、**FastAPI**は外部パッケージを統合するために複雑な仕組みを必要としないため、`passlib``python-jose`のようなよく整備され広く使われている多くのパッケージを直接使用することができます。
また、**FastAPI**は外部パッケージを統合するために複雑な仕組みを必要としないため、`pwdlib``PyJWT`のようなよく整備され広く使われている多くのパッケージを直接使用することができます。
しかし、柔軟性、堅牢性、セキュリティを損なうことなく、可能な限りプロセスを簡素化するためのツールを提供します。

View File

@@ -1,13 +1,13 @@
# 静的ファイル
# 静的ファイル { #static-files }
`StaticFiles` を使用して、ディレクトリから静的ファイルを自動的に提供できます。
## `StaticFiles` の使用
## `StaticFiles` の使用 { #use-staticfiles }
* `StaticFiles` をインポート。
* `StaticFiles()` インスタンスを生成し、特定のパスに「マウント」。
* `StaticFiles()` インスタンスを特定のパスに「マウント」。
{* ../../docs_src/static_files/tutorial001.py hl[2,6] *}
{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *}
/// note | 技術詳細
@@ -17,15 +17,15 @@
///
### 「マウント」とは
### 「マウント」とは { #what-is-mounting }
「マウント」とは、特定のパスに完全な「独立した」アプリケーションを追加することを意味します。これにより、すべてのサブパスの処理がなされます。
これは、マウントされたアプリケーションが完全に独立しているため、`APIRouter` とは異なります。メインアプリケーションのOpenAPIとドキュメントには、マウントされたアプリケーションの内容などは含まれません。
これについて詳しくは、**高度なユーザーガイド** をご覧ください。
これについて詳しくは、[高度なユーザーガイド](../advanced/index.md){.internal-link target=_blank} をご覧ください。
## 詳細
## 詳細 { #details }
最初の `"/static"` は、この「サブアプリケーション」が「マウント」されるサブパスを指します。したがって、`"/static"` から始まるパスはすべてサブアプリケーションによって処理されます。
@@ -33,8 +33,8 @@
`name="static"` は、**FastAPI** が内部で使用できる名前を付けます。
これらのパラメータはすべて「`静的`」とは異なる場合があり、独自のアプリケーションのニーズと詳細に合わせて調整します。
これらのパラメータはすべて「`static`」とは異なる場合があり、独自のアプリケーションのニーズと詳細に合わせて調整します。
## より詳しい情報
## より詳しい情報 { #more-info }
詳細とオプションについては、<a href="https://www.starlette.dev/staticfiles/" class="external-link" target="_blank">Starletteの静的ファイルに関するドキュメント</a>を確認してください。

View File

@@ -1,12 +1,24 @@
# テスト
# テスト { #testing }
<a href="https://www.starlette.dev/testclient/" class="external-link" target="_blank">Starlette</a> のおかげで、**FastAPI** アプリケーションのテストは簡単で楽しいものになっています。
<a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> がベースなので、非常に使いやすく直感的です。
<a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> がベースで、さらにその設計は Requests をベースにしているため、とても馴染みがあり直感的です。
これを使用すると、**FastAPI** と共に <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a> を直接利用できます。
## `TestClient` を使用
## `TestClient` を使用 { #using-testclient }
/// info | 情報
`TestClient` を使用するには、まず <a href="https://www.python-httpx.org" class="external-link" target="_blank">`httpx`</a> をインストールします。
[仮想環境](../virtual-environments.md){.internal-link target=_blank} を作成し、それを有効化してから、例えば以下のようにインストールしてください:
```console
$ pip install httpx
```
///
`TestClient` をインポートします。
@@ -16,9 +28,9 @@
`httpx` と同じ様に `TestClient` オブジェクトを使用します。
チェックしたい Python の標準的な式と共に、シンプルに `assert` 文を記述します。
チェックしたい Python の標準的な式と共に、シンプルに `assert` 文を記述します (これも `pytest` の標準です)
{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *}
{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *}
/// tip | 豆知識
@@ -44,48 +56,81 @@ FastAPIアプリケーションへのリクエストの送信とは別に、テ
///
## テストの分離
## テストの分離 { #separating-tests }
実際のアプリケーションでは、おそらくテストを別のファイルに保存します。
また、**FastAPI** アプリケーションは、複数のファイル/モジュールなどで構成されている場合もあります。
### **FastAPI** アプリファイル
### **FastAPI** アプリファイル { #fastapi-app-file }
**FastAPI** アプリに `main.py` ファイルがあるとします:
[Bigger Applications](bigger-applications.md){.internal-link target=_blank} で説明されている、次のようなファイル構成があるとします:
{* ../../docs_src/app_testing/main.py *}
```
.
├── app
│   ├── __init__.py
│   └── main.py
```
### テストファイル
ファイル `main.py`**FastAPI** アプリがあります:
次に、テストを含む `test_main.py` ファイルを作成し、`main` モジュール (`main.py`) から `app` をインポートします:
{* ../../docs_src/app_testing/test_main.py *}
{* ../../docs_src/app_testing/app_a_py39/main.py *}
## テスト: 例の拡張
### テストファイル { #testing-file }
次に、テストを含む `test_main.py` ファイルを用意できます。これは同じ Python パッケージ (`__init__.py` ファイルがある同じディレクトリ) に置けます:
``` hl_lines="5"
.
├── app
│   ├── __init__.py
│   ├── main.py
│   └── test_main.py
```
このファイルは同じパッケージ内にあるため、相対インポートを使って `main` モジュール (`main.py`) からオブジェクト `app` をインポートできます:
{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *}
...そして、これまでと同じようにテストコードを書けます。
## テスト: 例の拡張 { #testing-extended-example }
次に、この例を拡張し、詳細を追加して、さまざまなパーツをテストする方法を確認しましょう。
### 拡張版 **FastAPI** アプリファイル { #extended-fastapi-app-file }
### 拡張版 **FastAPI** アプリファイル
先ほどと同じファイル構成で続けます:
**FastAPI** アプリに `main_b.py` ファイルがあるとします。
```
.
├── app
│   ├── __init__.py
│   ├── main.py
│   └── test_main.py
```
そのファイルには、エラーを返す可能性のある `GET` オペレーションがあります。
ここで、**FastAPI** アプリがある `main.py` ファイルには、他のパスオペレーションがあります。
また、いくつかのエラーを返す可能性のある `POST` オペレーションあります。
エラーを返す可能性のある `GET` オペレーションあります。
これらの *path operation* には `X-Token` ヘッダーが必要です。
いくつかのエラーを返す可能性のある `POST` オペレーションもあります。
{* ../../docs_src/app_testing/app_b_py310/main.py *}
両方の *path operation* には `X-Token` ヘッダーが必要です。
### 拡張版テストファイル
{* ../../docs_src/app_testing/app_b_an_py310/main.py *}
次に、先程のものに拡張版テストを加えた、`test_main_b.py` を作成します。
### 拡張版テストファイル { #extended-testing-file }
{* ../../docs_src/app_testing/app_b/test_main.py *}
次に、拡張版のテストで `test_main.py` を更新できます:
リクエストに情報を渡せるクライアントが必要で、その方法がわからない場合はいつでも、`httpx` での実現方法を検索 (Google) できます。
{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}
リクエストに情報を渡せるクライアントが必要で、その方法がわからない場合はいつでも、`httpx` での実現方法、あるいは HTTPX の設計が Requests の設計をベースにしているため `requests` での実現方法を検索 (Google) できます。
テストでも同じことを行います。
@@ -107,9 +152,11 @@ FastAPIアプリケーションへのリクエストの送信とは別に、テ
///
## 実行
## 実行 { #run-it }
後は、`pytest` をインストールするだけです:
その後、`pytest` をインストールするだけです
[仮想環境](../virtual-environments.md){.internal-link target=_blank} を作成し、それを有効化してから、例えば以下のようにインストールしてください:
<div class="termy">
@@ -121,7 +168,7 @@ $ pip install pytest
</div>
ファイルを検知し、自動テストを実行し、結果のレポートを返します。
ファイルとテストを自動的に検出し、実行し、結果のレポートを返します。
以下でテストを実行します:

View File

@@ -1,10 +1,10 @@
# 仮想環境
# 仮想環境 { #virtual-environments }
Pythonプロジェクトの作業では、**仮想環境**(または類似の仕組み)を使用し、プロジェクトごとにインストールするパッケージを分離するべきでしょう。
/// info | 情報
もし、仮想環境の概要や作成方法、使用方法について既にご存知なら、このセクションをスキップすることができます。🤓
もし、仮想環境の概要や作成方法、使用方法について既にご存知なら、このセクションをスキップした方がよいかもしれません。🤓
///
@@ -25,7 +25,7 @@ Pythonプロジェクトの作業では、**仮想環境**(または類似の
///
## プロジェクトの作成
## プロジェクトの作成 { #create-a-project }
まず、プロジェクト用のディレクトリを作成します。
@@ -48,9 +48,9 @@ $ cd awesome-project
</div>
## 仮想環境の作成
## 仮想環境の作成 { #create-a-virtual-environment }
Pythonプロジェクトでの**初めての**作業を開始する際には、**<abbr title="他の選択肢もありますが、これはシンプルなガイドラインです">プロジェクト内</abbr>**に仮想環境を作成してください。
Pythonプロジェクトでの**初めての**作業を開始する際には、**<abbr title="there are other options, this is a simple guideline 他の選択肢もありますが、これはシンプルなガイドラインです">プロジェクト内</abbr>**に仮想環境を作成してください。
/// tip | 豆知識
@@ -72,10 +72,10 @@ $ python -m venv .venv
/// details | このコマンドの意味
- `python` : `python` というプログラムを呼び出します
- `-m` : モジュールをスクリプトとして呼び出します。どのモジュールを呼び出すのか、この次に指定します
- `venv` : 通常Pythonに付随してインストールされる `venv`モジュールを使用します
- `.venv` : 仮想環境を`.venv`という新しいディレクトリに作成します
* `python`: `python` というプログラムを呼び出します
* `-m`: モジュールをスクリプトとして呼び出します。どのモジュールを呼び出すのか、この次に指定します
* `venv`: 通常Pythonに付随してインストールされる `venv`モジュールを使用します
* `.venv`: 仮想環境を`.venv`という新しいディレクトリに作成します
///
@@ -111,13 +111,13 @@ $ uv venv
///
## 仮想環境の有効化
## 仮想環境の有効化 { #activate-the-virtual-environment }
実行されるPythonコマンドやインストールされるパッケージが新しく作成した仮想環境を使用するよう、その仮想環境を有効化しましょう。
/// tip | 豆知識
そのプロジェクトの作業で**新しいターミナルセッション**を開始する際には、**毎回**有効化が必要です
そのプロジェクトの作業で**新しいターミナルセッション**を開始する際には、**毎回**有効化してください
///
@@ -161,13 +161,13 @@ $ source .venv/Scripts/activate
/// tip | 豆知識
**新しいパッケージ**を仮想環境にインストールするときには、再度**有効化**してください。
**新しいパッケージ**を仮想環境にインストールするたびに、環境をもう一度**有効化**してください。
こうすることで、そのパッケージがインストールした**ターミナル(<abbr title="command line interface">CLI</abbr>)プログラム**を使用する場合に、仮想環境内のものが確実に使われ、グローバル環境にインストールされている別のもの(おそらく必要なものとは異なるバージョン)を誤って使用することを防ぎます。
///
## 仮想環境が有効であることを確認する
## 仮想環境が有効であることを確認する { #check-the-virtual-environment-is-active }
仮想環境が有効である(前のコマンドが正常に機能した)ことを確認します。
@@ -197,7 +197,7 @@ $ which python
<div class="termy">
``` console
```console
$ Get-Command python
C:\Users\user\code\awesome-project\.venv\Scripts\python
@@ -209,7 +209,7 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
////
## `pip` をアップグレードする
## `pip` をアップグレードする { #upgrade-pip }
/// tip | 豆知識
@@ -239,7 +239,27 @@ $ python -m pip install --upgrade pip
</div>
## `.gitignore` を追加する
/// tip | 豆知識
ときどき、pip をアップグレードしようとすると **`No module named pip`** エラーが表示されることがあります。
その場合は、以下のコマンドで pip をインストールしてアップグレードしてください:
<div class="termy">
```console
$ python -m ensurepip --upgrade
---> 100%
```
</div>
このコマンドは、pip がまだインストールされていなければ pip をインストールし、また、インストールされる pip のバージョンが `ensurepip` で利用可能なもの以上に新しいことも保証します。
///
## `.gitignore` を追加する { #add-gitignore }
**Git**を使用している場合(使用するべきでしょう)、 `.gitignore` ファイルを追加して、 `.venv` 内のあらゆるファイルをGitの管理対象から除外します。
@@ -265,9 +285,9 @@ $ echo "*" > .venv/.gitignore
/// details | このコマンドの意味
- `echo "*"` : ターミナルに `*` というテキストを「表示」しようとします。(次の部分によってその動作が少し変わります)
- `>` : `>` の左側のコマンドがターミナルに表示しようとする内容を、ターミナルには表示せず、 `>` の右側のファイルに書き込みます。
- `.gitignore` : `*` を書き込むファイル名。
* `echo "*"`: ターミナルに `*` というテキストを「表示」しようとします。(次の部分によってその動作が少し変わります)
* `>`: `>` の左側のコマンドがターミナルに表示しようとする内容を、ターミナルには表示せず、 `>` の右側のファイルに書き込みます。
* `.gitignore`: `*` を書き込むファイル名。
ここで、Gitにおける `*` は「すべて」を意味するので、このコマンドによって `.venv` ディレクトリ内のすべてがGitに無視されるようになります。
@@ -279,7 +299,7 @@ $ echo "*" > .venv/.gitignore
///
## パッケージのインストール
## パッケージのインストール { #install-packages }
仮想環境を有効化した後、その中でパッケージをインストールできます。
@@ -291,7 +311,7 @@ $ echo "*" > .venv/.gitignore
///
### パッケージを直接インストールする
### パッケージを直接インストールする { #install-packages-directly }
急いでいて、プロジェクトのパッケージ要件を宣言するファイルを使いたくない場合、パッケージを直接インストールできます。
@@ -330,7 +350,7 @@ $ uv pip install "fastapi[standard]"
////
### `requirements.txt` からインストールする
### `requirements.txt` からインストールする { #install-from-requirements-txt }
もし `requirements.txt` があるなら、パッケージのインストールに使用できます。
@@ -373,7 +393,7 @@ pydantic==2.8.0
///
## プログラムを実行する
## プログラムを実行する { #run-your-program }
仮想環境を有効化した後、プログラムを実行できます。この際、仮想環境内のPythonと、そこにインストールしたパッケージが使用されます。
@@ -387,7 +407,7 @@ Hello World
</div>
## エディタの設定
## エディタの設定 { #configure-your-editor }
プロジェクトではおそらくエディタを使用するでしょう。コード補完やインラインエラーの表示ができるように、作成した仮想環境をエディタでも使えるよう設定してください。(多くの場合、自動検出されます)
@@ -402,7 +422,7 @@ Hello World
///
## 仮想環境の無効化
## 仮想環境の無効化 { #deactivate-the-virtual-environment }
プロジェクトの作業が終了したら、その仮想環境を**無効化**できます。
@@ -416,9 +436,11 @@ $ deactivate
これにより、 `python` コマンドを実行しても、そのプロジェクト用(のパッケージがインストールされた)仮想環境から `python` プログラムを呼び出そうとはしなくなります。
## 作業準備完了
## 作業準備完了 { #ready-to-work }
これで、プロジェクトの作業を始める準備が整いました。
ここまでで、プロジェクトの作業を始める準備が整いました。
/// tip | 豆知識
@@ -428,9 +450,9 @@ $ deactivate
///
## なぜ仮想環境?
## なぜ仮想環境? { #why-virtual-environments }
FastAPIを使った作業をするには、 [Python](https://www.python.org/) のインストールが必要です。
FastAPIを使った作業をするには、<a href="https://www.python.org/" class="external-link" target="_blank">Python</a> のインストールが必要です。
それから、FastAPIや、使用したいその他の**パッケージ**を**インストール**する必要があります。
@@ -438,7 +460,7 @@ FastAPIを使った作業をするには、 [Python](https://www.python.org/)
ただし、`pip` を直接使用すると、パッケージは**グローバルなPython環境**OS全体にインストールされたPython環境にインストールされます。
### 問題点
### 問題点 { #the-problem }
では、グローバルPython環境にパッケージをインストールすることの問題点は何でしょうか
@@ -521,7 +543,7 @@ Pythonのパッケージでは、**新しいバージョン**で**互換性を
また、使用しているOSLinux、Windows、macOS などによっては、Pythonがすでにインストールされていることがあります。この場合、特定のバージョンのパッケージが**OSの動作に必要である**ことがあります。グローバル環境にパッケージをインストールすると、OSに付属するプログラムを**壊してしまう**可能性があります。
## パッケージのインストール先
## パッケージのインストール先 { #where-are-packages-installed }
Pythonをインストールしたとき、ファイルを含んだいくつかのディレクトリが作成されます。
@@ -539,7 +561,7 @@ $ pip install "fastapi[standard]"
</div>
FastAPIのコードを含む圧縮ファイルが、通常は [PyPI](https://pypi.org/project/fastapi/) からダウンロードされます。
FastAPIのコードを含む圧縮ファイルが、通常は <a href="https://pypi.org/project/fastapi/" class="external-link" target="_blank">PyPI</a> からダウンロードされます。
また、FastAPIが依存する他のパッケージも**ダウンロード**されます。
@@ -547,7 +569,7 @@ FastAPIのコードを含む圧縮ファイルが、通常は [PyPI](https://pyp
デフォルトでは、これらのファイルはPythonのインストール時に作成されるディレクトリ、つまり**グローバル環境**に配置されます。
## 仮想環境とは
## 仮想環境とは { #what-are-virtual-environments }
すべてのパッケージをグローバル環境に配置することによって生じる問題の解決策は、作業する**プロジェクトごとの仮想環境**を使用することです。
@@ -572,7 +594,7 @@ flowchart TB
stone-project ~~~ azkaban-project
```
## 仮想環境の有効化とは
## 仮想環境の有効化とは { #what-does-activating-a-virtual-environment-mean }
仮想環境を有効にしたとき、例えば次のコマンドを実行した場合を考えます:
@@ -620,7 +642,7 @@ $ source .venv/Scripts/activate
/// tip | 豆知識
`PATH` 変数についての詳細は [環境変数](environment-variables.md#path環境変数){.internal-link target=_blank} を参照してください。
`PATH` 変数についての詳細は [環境変数](environment-variables.md#path-environment-variable){.internal-link target=_blank} を参照してください。
///
@@ -701,7 +723,7 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
仮想環境を有効にして変更されることは他にもありますが、これが最も重要な変更のひとつです。
## 仮想環境の確認
## 仮想環境の確認 { #checking-a-virtual-environment }
仮想環境が有効かどうか、例えば次のように確認できます。:
@@ -753,7 +775,7 @@ LinuxやmacOSでは `which` を、Windows PowerShellでは `Get-Command` を使
///
## なぜ仮想環境を無効化するのか
## なぜ仮想環境を無効化するのか { #why-deactivate-a-virtual-environment }
例えば、`philosophers-stone` (賢者の石)というプロジェクトで作業をしていて、**その仮想環境を有効にし**、必要なパッケージをインストールしてその環境内で作業を進めているとします。
@@ -786,7 +808,7 @@ Traceback (most recent call last):
</div>
しかし、その仮想環境を無効化し、 `prisoner-of-azkaban` (アズカバンの囚人)のための新しい仮想環境を有効にすれば、 `python` を実行したときに `prisoner-of-azkaban` (アズカバンの囚人)の仮想環境の Python が使用されるようになります。
しかし、その仮想環境を無効化し、 `prisoner-of-askaban` のための新しい仮想環境を有効にすれば、 `python` を実行したときに `prisoner-of-azkaban` (アズカバンの囚人)の仮想環境の Python が使用されるようになります。
<div class="termy">
@@ -807,7 +829,7 @@ I solemnly swear 🐺
</div>
## 代替手段
## 代替手段 { #alternatives }
これは、あらゆる仕組みを**根本から**学ぶためのシンプルな入門ガイドです。
@@ -824,7 +846,7 @@ I solemnly swear 🐺
* パッケージとそのバージョンの、依存関係を含めた**厳密な**組み合わせを保持し、これによって、本番環境で、開発環境と全く同じようにプロジェクトを実行できる(これは**locking**と呼ばれます)
* その他のさまざまな機能
## まとめ
## まとめ { #conclusion }
ここまで読みすべて理解したなら、世間の多くの開発者と比べて、仮想環境について**あなたはより多くのことを知っています**。🤓

View File

@@ -8,7 +8,6 @@ Language code: ko.
- Use polite, instructional Korean (e.g. 합니다/하세요 style).
- Keep the tone consistent with the existing Korean FastAPI docs.
- Do not translate “You” literally as “당신”. Use “여러분” where appropriate, or omit the subject if it sounds more natural in Korean.
### Headings

View File

@@ -1,8 +1,8 @@
# Arquivo de teste de LLM { #llm-test-file }
Este documento testa se o <abbr title="Large Language Model - Modelo de Linguagem de Grande Porte">LLM</abbr>, que traduz a documentação, entende o `general_prompt` em `scripts/translate.py` e o prompt específico do idioma em `docs/{language code}/llm-prompt.md`. O prompt específico do idioma é anexado ao `general_prompt`.
Este documento testa se o <abbr title="Large Language Model Modelo de Linguagem de Grande Porte">LLM</abbr>, que traduz a documentação, entende o `general_prompt` em `scripts/translate.py` e o prompt específico do idioma em `docs/{language code}/llm-prompt.md`. O prompt específico do idioma é anexado ao `general_prompt`.
Os testes adicionados aqui serão vistos por todos os designers dos prompts específicos de idioma.
Os testes adicionados aqui serão vistos por todos os autores dos prompts específicos de idioma.
Use da seguinte forma:
@@ -23,7 +23,7 @@ Este é um trecho de código: `foo`. E este é outro trecho de código: `bar`. E
////
//// tab | Informação
//// tab | Informações
O conteúdo dos trechos de código deve ser deixado como está.
@@ -45,9 +45,9 @@ O LLM provavelmente vai traduzir isso errado. O interessante é apenas se ele ma
////
//// tab | Informação
//// tab | Informações
O designer do prompt pode escolher se quer converter aspas neutras em aspas tipográficas. Também é aceitável deixá-las como estão.
O autor do prompt pode escolher se deseja converter aspas neutras em aspas tipográficas. Também é aceitável deixá-las como estão.
Veja, por exemplo, a seção `### Quotes` em `docs/de/llm-prompt.md`.
@@ -67,7 +67,7 @@ Pesado: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you ha
////
//// tab | Informação
//// tab | Informações
... No entanto, as aspas dentro de trechos de código devem permanecer como estão.
@@ -95,24 +95,24 @@ $ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid
...e outro exemplo de código de console...
```console
// Criar um diretório "Code"
// Crie um diretório "Code"
$ mkdir code
// Mudar para esse diretório
// Entre nesse diretório
$ cd code
```
...e um exemplo de código Python...
```Python
wont_work() # This won't work 😱
works(foo="bar") # This works 🎉
wont_work() # Isto não vai funcionar 😱
works(foo="bar") # Isto funciona 🎉
```
...e é isso.
////
//// tab | Informação
//// tab | Informações
O código em blocos de código não deve ser modificado, com exceção dos comentários.
@@ -154,7 +154,7 @@ Algum texto
////
//// tab | Informação
//// tab | Informações
Abas e blocos `Info`/`Note`/`Warning`/etc. devem ter a tradução do seu título adicionada após uma barra vertical (`|`).
@@ -181,7 +181,7 @@ O texto do link deve ser traduzido, o endereço do link deve apontar para a trad
////
//// tab | Informação
//// tab | Informações
Os links devem ser traduzidos, mas seus endereços devem permanecer inalterados. Uma exceção são links absolutos para páginas da documentação do FastAPI. Nesse caso, devem apontar para a tradução.
@@ -197,10 +197,10 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
### O abbr fornece uma frase completa { #the-abbr-gives-a-full-phrase }
* <abbr title="Getting Things Done">GTD</abbr>
* <abbr title="less than - menos que"><code>lt</code></abbr>
* <abbr title="XML Web Token">XWT</abbr>
* <abbr title="Parallel Server Gateway Interface - Interface de Gateway de Servidor Paralelo">PSGI</abbr>
* <abbr title="Getting Things Done Fazer as Coisas">GTD</abbr>
* <abbr title="menos que"><code>lt</code></abbr>
* <abbr title="XML Web Token Token Web XML">XWT</abbr>
* <abbr title="Parallel Server Gateway Interface Interface de Gateway de Servidor Paralelo">PSGI</abbr>
### O abbr fornece uma explicação { #the-abbr-gives-an-explanation }
@@ -209,12 +209,12 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
### O abbr fornece uma frase completa e uma explicação { #the-abbr-gives-a-full-phrase-and-an-explanation }
* <abbr title="Mozilla Developer Network: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
* <abbr title="Input/Output: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
* <abbr title="Mozilla Developer Network Rede de Desenvolvedores da Mozilla: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
* <abbr title="Input/Output Entrada/Saída: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
////
//// tab | Informação
//// tab | Informações
Os atributos "title" dos elementos "abbr" são traduzidos seguindo algumas instruções específicas.
@@ -228,7 +228,7 @@ Veja a seção `### HTML abbr elements` no prompt geral em `scripts/translate.py
//// tab | Teste
### Desenvolver uma webapp - um tutorial { #develop-a-webapp-a-tutorial }
### Desenvolver uma aplicação web - um tutorial { #develop-a-webapp-a-tutorial }
Olá.
@@ -242,7 +242,7 @@ Olá novamente.
////
//// tab | Informação
//// tab | Informações
A única regra rígida para títulos é que o LLM deixe a parte do hash dentro de chaves inalterada, o que garante que os links não quebrem.
@@ -494,9 +494,9 @@ Para algumas instruções específicas do idioma, veja, por exemplo, a seção `
////
//// tab | Informação
//// tab | Informações
Esta é uma lista não completa e não normativa de termos (principalmente) técnicos vistos na documentação. Pode ser útil para o designer do prompt descobrir para quais termos o LLM precisa de uma ajudinha. Por exemplo, quando ele continua revertendo uma boa tradução para uma tradução subótima. Ou quando tem problemas para conjugar/declinar um termo no seu idioma.
Esta é uma lista não completa e não normativa de termos (principalmente) técnicos vistos na documentação. Pode ser útil para o autor do prompt descobrir para quais termos o LLM precisa de uma ajudinha. Por exemplo, quando ele continua revertendo uma boa tradução para uma tradução subótima. Ou quando tem problemas para conjugar/declinar um termo no seu idioma.
Veja, por exemplo, a seção `### List of English terms and their preferred German translations` em `docs/de/llm-prompt.md`.

View File

@@ -10,7 +10,7 @@ Se você não é um "especialista" no OpenAPI, você provavelmente não precisa
Você pode definir o `operationId` do OpenAPI que será utilizado na sua *operação de rota* com o parâmetro `operation_id`.
Você deveria ter certeza que ele é único para cada operação.
Você precisa ter certeza que ele é único para cada operação.
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
@@ -18,13 +18,13 @@ Você deveria ter certeza que ele é único para cada operação.
Se você quiser utilizar o nome das funções da sua API como `operationId`s, você pode iterar sobre todos esses nomes e sobrescrever o `operation_id` em cada *operação de rota* utilizando o `APIRoute.name` dela.
Você deveria fazer isso depois de adicionar todas as suas *operações de rota*.
Você deve fazer isso depois de adicionar todas as suas *operações de rota*.
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
/// tip | Dica
Se você chamar `app.openapi()` manualmente, você deveria atualizar os `operationId`s antes dessa chamada.
Se você chamar `app.openapi()` manualmente, os `operationId`s devem ser atualizados antes dessa chamada.
///
@@ -44,11 +44,11 @@ Para excluir uma *operação de rota* do esquema OpenAPI gerado (e por consequê
## Descrição avançada a partir de docstring { #advanced-description-from-docstring }
Você pode limitar as linhas utilizadas a partir da docstring de uma *função de operação de rota* para o OpenAPI.
Você pode limitar as linhas utilizadas a partir de uma docstring de uma *função de operação de rota* para o OpenAPI.
Adicionar um `\f` (um caractere de escape para "form feed") faz com que o **FastAPI** trunque a saída usada para o OpenAPI até esse ponto.
Adicionar um `\f` (um caractere de escape para alimentação de formulário) faz com que o **FastAPI** restrinja a saída utilizada pelo OpenAPI até esse ponto.
Ele não será mostrado na documentação, mas outras ferramentas (como o Sphinx) serão capazes de utilizar o resto.
Ele não será mostrado na documentação, mas outras ferramentas (como o Sphinx) serão capazes de utilizar o resto do texto.
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
@@ -131,38 +131,70 @@ E se você olhar o esquema OpenAPI resultante (na rota `/openapi.json` da sua AP
### Esquema de *operação de rota* do OpenAPI personalizado { #custom-openapi-path-operation-schema }
O dicionário em `openapi_extra` vai ser mesclado profundamente com o esquema OpenAPI gerado automaticamente para a *operação de rota*.
O dicionário em `openapi_extra` vai ter todos os seus níveis mesclados dentro do esquema OpenAPI gerado automaticamente para a *operação de rota*.
Então, você pode adicionar dados extras ao esquema gerado automaticamente.
Então, você pode adicionar dados extras para o esquema gerado automaticamente.
Por exemplo, você poderia decidir ler e validar a requisição com seu próprio código, sem usar as funcionalidades automáticas do FastAPI com o Pydantic, mas ainda assim querer definir a requisição no esquema OpenAPI.
Por exemplo, você poderia optar por ler e validar a requisição com seu próprio código, sem utilizar funcionalidades automatizadas do FastAPI com o Pydantic, mas você ainda pode quere definir a requisição no esquema OpenAPI.
Você pode fazer isso com `openapi_extra`:
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
Nesse exemplo, nós não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da requisição não está nem mesmo <abbr title="converted from some plain format, like bytes, into Python objects - convertido de algum formato simples, como bytes, em objetos Python">analisado</abbr> como JSON, ele é lido diretamente como `bytes`, e a função `magic_data_reader()` seria a responsável por analisar ele de alguma forma.
Nesse exemplo, nós não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da requisição não está nem mesmo <abbr title="convertido de um formato plano, como bytes, para objetos Python">analisado</abbr> como JSON, ele é lido diretamente como `bytes` e a função `magic_data_reader()` seria a responsável por analisar ele de alguma forma.
De toda forma, nós podemos declarar o esquema esperado para o corpo da requisição.
### Tipo de conteúdo do OpenAPI personalizado { #custom-openapi-content-type }
Utilizando esse mesmo truque, você pode usar um modelo Pydantic para definir o JSON Schema que é então incluído na seção do esquema personalizado do OpenAPI na *operação de rota*.
Utilizando esse mesmo truque, você pode utilizar um modelo Pydantic para definir o JSON Schema que é então incluído na seção do esquema personalizado do OpenAPI na *operação de rota*.
E você pode fazer isso até mesmo quando o tipo de dados na requisição não é JSON.
E você pode fazer isso até mesmo quando os dados da requisição não seguem o formato JSON.
Por exemplo, nesta aplicação nós não usamos a funcionalidade integrada ao FastAPI de extrair o JSON Schema dos modelos Pydantic nem a validação automática para JSON. Na verdade, estamos declarando o tipo de conteúdo da requisição como YAML, em vez de JSON:
Por exemplo, nesta aplicação nós não usamos a funcionalidade integrada ao FastAPI de extrair o JSON Schema dos modelos Pydantic nem a validação automática do JSON. Na verdade, estamos declarando o tipo do conteúdo da requisição como YAML, em vez de JSON:
//// tab | Pydantic v2
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
Entretanto, mesmo que não utilizemos a funcionalidade integrada por padrão, ainda estamos usando um modelo Pydantic para gerar um JSON Schema manualmente para os dados que queremos receber em YAML.
////
Então utilizamos a requisição diretamente e extraímos o corpo como `bytes`. Isso significa que o FastAPI não vai sequer tentar analisar o payload da requisição como JSON.
//// tab | Pydantic v1
E então no nosso código, nós analisamos o conteúdo YAML diretamente e, em seguida, estamos usando novamente o mesmo modelo Pydantic para validar o conteúdo YAML:
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[15:20, 22] *}
////
/// info | Informação
Na versão 1 do Pydantic, o método para obter o JSON Schema de um modelo é `Item.schema()`, na versão 2 do Pydantic, o método é `Item.model_json_schema()`.
///
Entretanto, mesmo que não utilizemos a funcionalidade integrada por padrão, ainda estamos usando um modelo Pydantic para gerar um JSON Schema manualmente para os dados que queremos receber no formato YAML.
Então utilizamos a requisição diretamente, e extraímos o corpo como `bytes`. Isso significa que o FastAPI não vai sequer tentar analisar o corpo da requisição como JSON.
E então no nosso código, nós analisamos o conteúdo YAML diretamente, e estamos utilizando o mesmo modelo Pydantic para validar o conteúdo YAML:
//// tab | Pydantic v2
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
////
//// tab | Pydantic v1
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[24:31] *}
////
/// info | Informação
Na versão 1 do Pydantic, o método para analisar e validar um objeto era `Item.parse_obj()`, na versão 2 do Pydantic, o método é chamado de `Item.model_validate()`.
///
/// tip | Dica
Aqui reutilizamos o mesmo modelo do Pydantic.

View File

@@ -46,6 +46,12 @@ $ pip install "fastapi[all]"
</div>
/// info | Informação
No Pydantic v1 ele vinha incluído no pacote principal. Agora é distribuído como um pacote independente para que você possa optar por instalá-lo ou não, caso não precise dessa funcionalidade.
///
### Criar o objeto `Settings` { #create-the-settings-object }
Importe `BaseSettings` do Pydantic e crie uma subclasse, muito parecido com um modelo do Pydantic.
@@ -54,8 +60,24 @@ Da mesma forma que com modelos do Pydantic, você declara atributos de classe co
Você pode usar as mesmas funcionalidades e ferramentas de validação que usa em modelos do Pydantic, como diferentes tipos de dados e validações adicionais com `Field()`.
//// tab | Pydantic v2
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
////
//// tab | Pydantic v1
/// info | Informação
No Pydantic v1 você importaria `BaseSettings` diretamente de `pydantic` em vez de `pydantic_settings`.
///
{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *}
////
/// tip | Dica
Se você quer algo rápido para copiar e colar, não use este exemplo, use o último abaixo.
@@ -193,6 +215,8 @@ APP_NAME="ChimichangApp"
E então atualizar seu `config.py` com:
//// tab | Pydantic v2
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
/// tip | Dica
@@ -201,6 +225,26 @@ O atributo `model_config` é usado apenas para configuração do Pydantic. Você
///
////
//// tab | Pydantic v1
{* ../../docs_src/settings/app03_an_py39/config_pv1.py hl[9:10] *}
/// tip | Dica
A classe `Config` é usada apenas para configuração do Pydantic. Você pode ler mais em <a href="https://docs.pydantic.dev/1.10/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
///
////
/// info | Informação
Na versão 1 do Pydantic a configuração era feita em uma classe interna `Config`, na versão 2 do Pydantic é feita em um atributo `model_config`. Esse atributo recebe um `dict`, e para ter autocompletar e erros inline você pode importar e usar `SettingsConfigDict` para definir esse `dict`.
///
Aqui definimos a configuração `env_file` dentro da sua classe `Settings` do Pydantic e definimos o valor como o nome do arquivo dotenv que queremos usar.
### Criando o `Settings` apenas uma vez com `lru_cache` { #creating-the-settings-only-once-with-lru-cache }

View File

@@ -2,23 +2,21 @@
Se você tem uma aplicação FastAPI antiga, pode estar usando o Pydantic versão 1.
O FastAPI versão 0.100.0 tinha suporte ao Pydantic v1 ou v2. Ele usaria aquele que você tivesse instalado.
O FastAPI tem suporte ao Pydantic v1 ou v2 desde a versão 0.100.0.
O FastAPI versão 0.119.0 introduziu suporte parcial ao Pydantic v1 a partir de dentro do Pydantic v2 (como `pydantic.v1`), para facilitar a migração para o v2.
Se você tiver o Pydantic v2 instalado, ele será utilizado. Se, em vez disso, tiver o Pydantic v1, será ele que será utilizado.
O FastAPI 0.126.0 removeu o suporte ao Pydantic v1, enquanto ainda oferece suporte a `pydantic.v1` por mais algum tempo.
O Pydantic v1 está agora descontinuado e o suporte a ele será removido nas próximas versões do FastAPI, você deveria migrar para o Pydantic v2. Assim, você terá as funcionalidades, melhorias e correções mais recentes.
/// warning | Atenção
A equipe do Pydantic interrompeu o suporte ao Pydantic v1 para as versões mais recentes do Python, a partir do **Python 3.14**.
Isso inclui `pydantic.v1`, que não é mais suportado no Python 3.14 e superiores.
Além disso, a equipe do Pydantic interrompeu o suporte ao Pydantic v1 para as versões mais recentes do Python, a partir do **Python 3.14**.
Se quiser usar as funcionalidades mais recentes do Python, você precisará garantir que usa o Pydantic v2.
///
Se você tem uma aplicação FastAPI antiga com Pydantic v1, aqui vou mostrar como migrá-la para o Pydantic v2, e as **funcionalidades no FastAPI 0.119.0** para ajudar em uma migração gradual.
Se você tem uma aplicação FastAPI antiga com Pydantic v1, aqui vou mostrar como migrá-la para o Pydantic v2 e as **novas funcionalidades no FastAPI 0.119.0** para ajudar em uma migração gradual.
## Guia oficial { #official-guide }
@@ -46,7 +44,7 @@ Depois disso, você pode rodar os testes e verificar se tudo funciona. Se funcio
## Pydantic v1 no v2 { #pydantic-v1-in-v2 }
O Pydantic v2 inclui tudo do Pydantic v1 como um submódulo `pydantic.v1`. Mas isso não é mais suportado em versões acima do Python 3.13.
O Pydantic v2 inclui tudo do Pydantic v1 como um submódulo `pydantic.v1`.
Isso significa que você pode instalar a versão mais recente do Pydantic v2 e importar e usar os componentes antigos do Pydantic v1 a partir desse submódulo, como se tivesse o Pydantic v1 antigo instalado.
@@ -68,7 +66,7 @@ Tenha em mente que, como a equipe do Pydantic não oferece mais suporte ao Pydan
### Pydantic v1 e v2 na mesma aplicação { #pydantic-v1-and-v2-on-the-same-app }
Não é **suportado** pelo Pydantic ter um modelo do Pydantic v2 com campos próprios definidos como modelos do Pydantic v1, ou vice-versa.
Não é suportado pelo Pydantic ter um modelo do Pydantic v2 com campos próprios definidos como modelos do Pydantic v1, ou vice-versa.
```mermaid
graph TB
@@ -88,7 +86,7 @@ graph TB
style V2Field fill:#f9fff3
```
...mas, você pode ter modelos separados usando Pydantic v1 e v2 na mesma aplicação.
...but, you can have separated models using Pydantic v1 and v2 in the same app.
```mermaid
graph TB
@@ -108,7 +106,7 @@ graph TB
style V2Field fill:#f9fff3
```
Em alguns casos, é até possível ter modelos Pydantic v1 e v2 na mesma **operação de rota** na sua aplicação FastAPI:
Em alguns casos, é até possível ter modelos Pydantic v1 e v2 na mesma operação de rota na sua aplicação FastAPI:
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
@@ -124,7 +122,7 @@ Se você precisar usar algumas das ferramentas específicas do FastAPI para par
/// tip | Dica
Primeiro tente com o `bump-pydantic`, se seus testes passarem e isso funcionar, então você concluiu tudo com um único comando. ✨
Primeiro tente com o `bump-pydantic`; se seus testes passarem e isso funcionar, então você concluiu tudo com um único comando. ✨
///

View File

@@ -1,8 +1,8 @@
# Esquemas OpenAPI Separados para Entrada e Saída ou Não { #separate-openapi-schemas-for-input-and-output-or-not }
Desde que o **Pydantic v2** foi lançado, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎
Ao usar **Pydantic v2**, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎
De fato, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles possuem **valores padrão**.
Inclusive, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles possuem **valores padrão**.
Vamos ver como isso funciona e como alterar se for necessário.
@@ -95,8 +95,10 @@ O suporte para `separate_input_output_schemas` foi adicionado no FastAPI `0.102.
### Mesmo Esquema para Modelos de Entrada e Saída na Documentação { #same-schema-for-input-and-output-models-in-docs }
E agora haverá um único esquema para entrada e saída para o modelo, apenas `Item`, e ele terá `description` como **não obrigatório**:
E agora haverá um único esquema para entrada e saída para o modelo, apenas `Item`, e `description` **não será obrigatório**:
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
</div>
Esse é o mesmo comportamento do Pydantic v1. 🤓

View File

@@ -40,8 +40,8 @@ Os recursos chave são:
* **Rápido**: alta performance, equivalente a **NodeJS** e **Go** (graças ao Starlette e Pydantic). [Um dos frameworks mais rápidos disponíveis](#performance).
* **Rápido para codar**: Aumenta a velocidade para desenvolver recursos entre 200% a 300%. *
* **Poucos bugs**: Reduz cerca de 40% de erros induzidos por humanos (desenvolvedores). *
* **Intuitivo**: Grande suporte a editores. <abbr title="também conhecido como auto-complete, autocompletion, IntelliSense">Completação</abbr> em todos os lugares. Menos tempo debugando.
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo docs.
* **Intuitivo**: Grande suporte a _IDEs_. <abbr title="também conhecido como autocompletar, preenchimento automático, IntelliSense">Preenchimento automático</abbr> em todos os lugares. Menos tempo debugando.
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo documentação.
* **Enxuto**: Minimize duplicação de código. Múltiplas funcionalidades para cada declaração de parâmetro. Menos bugs.
* **Robusto**: Tenha código pronto para produção. E com documentação interativa automática.
* **Baseado em padrões**: Baseado em (e totalmente compatível com) os padrões abertos para APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (anteriormente conhecido como Swagger) e <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
@@ -73,7 +73,7 @@ Os recursos chave são:
## Opiniões { #opinions }
"_[...] Estou usando **FastAPI** muito esses dias. [...] Estou na verdade planejando utilizar ele em todos os times de **serviços ML na Microsoft**. Alguns deles estão sendo integrados no _core_ do produto **Windows** e alguns produtos **Office**._"
"*[...] Estou usando **FastAPI** muito esses dias. [...] Estou na verdade planejando utilizar ele em todos os times de **serviços _Machine Learning_ na Microsoft**. Alguns deles estão sendo integrados no _core_ do produto **Windows** e alguns produtos **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>
@@ -91,45 +91,39 @@ Os recursos chave são:
---
"_Estou muito entusiasmado com o **FastAPI**. É tão divertido!_"
"*Estou extremamente entusiasmado com o **FastAPI**. É tão divertido!*"
<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> apresentador do podcast</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
<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> podcaster</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
---
"_Honestamente, o que você construiu parece super sólido e refinado. De muitas formas, é o que eu queria que o **Hug** fosse - é realmente inspirador ver alguém construir isso._"
"*Honestamente, o que você construiu parece super sólido e rebuscado. De muitas formas, eu queria que o **Hug** fosse assim - é realmente inspirador ver alguém que construiu ele.*"
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong>criador do<a href="https://github.com/hugapi/hug" target="_blank">Hug</a></strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
---
"_Se você está procurando aprender um **framework moderno** para construir APIs REST, dê uma olhada no **FastAPI** [...] É rápido, fácil de usar e fácil de aprender [...]_"
"*Se você está procurando aprender um **_framework_ moderno** para construir aplicações _REST_, dê uma olhada no **FastAPI** [...] É rápido, fácil de usar e fácil de aprender [...]*"
"_Nós trocamos nossas **APIs** por **FastAPI** [...] Acredito que você gostará dele [...]_"
"*Nós trocamos nossas **APIs** por **FastAPI** [...] Acredito que vocês gostarão dele [...]*"
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong>fundadores da <a href="https://explosion.ai" target="_blank">Explosion AI</a> - criadores da <a href="https://spacy.io" target="_blank">spaCy</a></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>
---
"_Se alguém estiver procurando construir uma API Python para produção, eu recomendaria fortemente o **FastAPI**. Ele é **lindamente projetado**, **simples de usar** e **altamente escalável**, e se tornou um **componente chave** para a nossa estratégia de desenvolvimento API first, impulsionando diversas automações e serviços, como o nosso Virtual TAC Engineer._"
"_Se alguém estiver procurando construir uma API Python para produção, eu recomendaria fortemente o **FastAPI**. Ele é **lindamente projetado**, **simples de usar** e **altamente escalável**. Ele se tornou um **componente chave** para a nossa estratégia API first de desenvolvimento e está impulsionando diversas automações e serviços, como o nosso 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>
---
## Mini documentário do FastAPI { #fastapi-mini-documentary }
Há um <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">mini documentário do FastAPI</a> lançado no fim de 2025, você pode assisti-lo online:
<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**, o FastAPI das interfaces de linhas de comando { #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>
Se você estiver construindo uma aplicação <abbr title="Command Line Interface - Interface de Linha de Comando">CLI</abbr> para ser utilizada no terminal ao invés de uma API web, dê uma olhada no <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
Se você estiver construindo uma aplicação <abbr title="Command Line Interface Interface de Linha de Comando">CLI</abbr> para ser utilizada em um terminal ao invés de uma aplicação web, dê uma olhada no <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
**Typer** é o irmão menor do FastAPI. E seu propósito é ser o **FastAPI das CLIs**. ⌨️ 🚀
**Typer** é o irmão menor do FastAPI. E seu propósito é ser o **FastAPI das _CLIs_**. ⌨️ 🚀
## Requisitos { #requirements }
@@ -261,10 +255,10 @@ Você verá a resposta JSON como:
Você acabou de criar uma API que:
* Recebe requisições HTTP nos _paths_ `/` e `/items/{item_id}`.
* Ambos _paths_ fazem <em>operações</em> `GET` (também conhecido como _métodos_ HTTP).
* O _path_ `/items/{item_id}` tem um _parâmetro de path_ `item_id` que deve ser um `int`.
* O _path_ `/items/{item_id}` tem um _parâmetro query_ `q` `str` opcional.
* Recebe requisições HTTP nas _rotas_ `/` e `/items/{item_id}`.
* Ambas _rotas_ fazem <em>operações</em> `GET` (também conhecido como _métodos_ HTTP).
* A _rota_ `/items/{item_id}` tem um _parâmetro de rota_ `item_id` que deve ser um `int`.
* A _rota_ `/items/{item_id}` tem um _parâmetro query_ `q` `str` opcional.
### Documentação Interativa da API { #interactive-api-docs }
@@ -284,7 +278,7 @@ Você verá a documentação automática alternativa (fornecida por <a href="htt
## Evoluindo o Exemplo { #example-upgrade }
Agora modifique o arquivo `main.py` para receber um corpo de uma requisição `PUT`.
Agora modifique o arquivo `main.py` para receber um corpo para uma requisição `PUT`.
Declare o corpo utilizando tipos padrão Python, graças ao Pydantic.
@@ -340,7 +334,7 @@ Agora vá para <a href="http://127.0.0.1:8000/docs" class="external-link" target
E agora, vá para <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
* A documentação alternativa também irá refletir o novo parâmetro query e o corpo:
* A documentação alternativa também irá refletir o novo parâmetro da _query_ e o corpo:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
@@ -374,15 +368,15 @@ item: Item
* Validação de dados:
* Erros automáticos e claros quando o dado é inválido.
* Validação até para objetos JSON profundamente aninhados.
* <abbr title="também conhecido como: serialization, parsing, marshalling">Conversão</abbr> de dados de entrada: vindo da rede para dados e tipos Python. Consegue ler:
* <abbr title="também conhecido como: serialização, parsing, marshalling">Conversão</abbr> de dados de entrada: vindo da rede para dados e tipos Python. Consegue ler:
* JSON.
* Parâmetros de path.
* Parâmetros query.
* Cookies.
* Parâmetros de rota.
* Parâmetros de _query_ .
* _Cookies_.
* Cabeçalhos.
* Formulários.
* Arquivos.
* <abbr title="também conhecido como: serialization, parsing, marshalling">Conversão</abbr> de dados de saída: convertendo de tipos e dados Python para dados de rede (como JSON):
* <abbr title="também conhecido como: serialização, parsing, marshalling">Conversão</abbr> de dados de saída de tipos e dados Python para dados de rede (como JSON):
* Converte tipos Python (`str`, `int`, `float`, `bool`, `list` etc).
* Objetos `datetime`.
* Objetos `UUID`.
@@ -396,17 +390,17 @@ item: Item
Voltando ao código do exemplo anterior, **FastAPI** irá:
* Validar que existe um `item_id` no path para requisições `GET` e `PUT`.
* Validar que existe um `item_id` na rota para requisições `GET` e `PUT`.
* Validar que `item_id` é do tipo `int` para requisições `GET` e `PUT`.
* Se não for, o cliente verá um erro útil e claro.
* Verificar se existe um parâmetro query opcional nomeado como `q` (como em `http://127.0.0.1:8000/items/foo?q=somequery`) para requisições `GET`.
* Se não é validado, o cliente verá um útil, claro erro.
* Verificar se existe um parâmetro de _query_ opcional nomeado como `q` (como em `http://127.0.0.1:8000/items/foo?q=somequery`) para requisições `GET`.
* Como o parâmetro `q` é declarado com `= None`, ele é opcional.
* Sem o `None` ele seria obrigatório (como o corpo no caso de `PUT`).
* Sem o `None` ele poderia ser obrigatório (como o corpo no caso de `PUT`).
* Para requisições `PUT` para `/items/{item_id}`, lerá o corpo como JSON:
* Verifica que tem um atributo obrigatório `name` que deve ser `str`.
* Verifica que tem um atributo obrigatório `price` que tem que ser um `float`.
* Verifica que tem um atributo opcional `is_offer`, que deve ser um `bool`, se presente.
* Tudo isso também funcionaria para objetos JSON profundamente aninhados.
* Verifica que tem um atributo obrigatório `price` que deve ser `float`.
* Verifica que tem an atributo opcional `is_offer`, que deve ser `bool`, se presente.
* Tudo isso também funciona para objetos JSON profundamente aninhados.
* Converter de e para JSON automaticamente.
* Documentar tudo com OpenAPI, que poderá ser usado por:
* Sistemas de documentação interativos.
@@ -415,7 +409,7 @@ Voltando ao código do exemplo anterior, **FastAPI** irá:
---
Nós apenas arranhamos a superfície, mas você já tem ideia de como tudo funciona.
Nós apenas arranhamos a superfície, mas você já tem idéia de como tudo funciona.
Experimente mudar a seguinte linha:
@@ -443,22 +437,22 @@ Para um exemplo mais completo incluindo mais recursos, veja <a href="https://fas
**Alerta de Spoiler**: o tutorial - guia do usuário inclui:
* Declaração de **parâmetros** de diferentes lugares como: **cabeçalhos**, **cookies**, **campos de formulários** e **arquivos**.
* Como configurar **limitações de validação** como `maximum_length` ou `regex`.
* Um poderoso e fácil de usar sistema de **<abbr title="também conhecido como components, resources, providers, services, injectables">Injeção de Dependência</abbr>**.
* Segurança e autenticação, incluindo suporte para **OAuth2** com autenticação com **JWT tokens** e **HTTP Basic**.
* Declaração de **parâmetetros** de diferentes lugares como: **cabeçalhos**, **cookies**, **campos de formulários** e **arquivos**.
* Como configurar **Limitações de Validação** como `maximum_length` ou `regex`.
* Um poderoso e fácil de usar sistema de **<abbr title="também conhecido como componentes, recursos, fornecedores, serviços, injetáveis">Injeção de Dependência</abbr>**.
* Segurança e autenticação, incluindo suporte para **OAuth2** com autenticação **JWT tokens** e **HTTP Basic**.
* Técnicas mais avançadas (mas igualmente fáceis) para declaração de **modelos JSON profundamente aninhados** (graças ao Pydantic).
* Integrações **GraphQL** com o <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> e outras bibliotecas.
* Muitos recursos extras (graças ao Starlette) como:
* **WebSockets**
* testes extremamente fáceis baseados em HTTPX e `pytest`
* testes extrememamente fáceis baseados em HTTPX e `pytest`
* **CORS**
* **Cookie Sessions**
* ...e mais.
### Implemente sua aplicação (opcional) { #deploy-your-app-optional }
Você pode opcionalmente implantar sua aplicação FastAPI na <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, vá e entre na lista de espera se ainda não o fez. 🚀
Você pode opcionalmente implantar sua aplicação FastAPI na <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, inscreva-se na lista de espera se ainda não o fez. 🚀
Se você já tem uma conta na **FastAPI Cloud** (nós convidamos você da lista de espera 😉), pode implantar sua aplicação com um único comando.
@@ -512,7 +506,7 @@ Siga os tutoriais do seu provedor de nuvem para implantar aplicações FastAPI c
Testes de performance da _Independent TechEmpower_ mostram aplicações **FastAPI** rodando sob Uvicorn como <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">um dos _frameworks_ Python mais rápidos disponíveis</a>, somente atrás de Starlette e Uvicorn (utilizados internamente pelo FastAPI). (*)
Para entender mais sobre isso, veja a seção <a href="https://fastapi.tiangolo.com/pt/benchmarks/" class="internal-link" target="_blank">Comparações</a>.
Para entender mais sobre performance, veja a seção <a href="https://fastapi.tiangolo.com/pt/benchmarks/" class="internal-link" target="_blank">Comparações</a>.
## Dependências { #dependencies }
@@ -520,7 +514,7 @@ O FastAPI depende do Pydantic e do Starlette.
### Dependências `standard` { #standard-dependencies }
Quando você instala o FastAPI com `pip install "fastapi[standard]"`, ele vem com o grupo `standard` de dependências opcionais:
Quando você instala o FastAPI com `pip install "fastapi[standard]"`, ele vêm com o grupo `standard` (padrão) de dependências opcionais:
Utilizado pelo Pydantic:
@@ -530,7 +524,7 @@ Utilizado pelo Starlette:
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Obrigatório caso você queira utilizar o `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Obrigatório se você quer utilizar a configuração padrão de templates.
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obrigatório se você deseja suporte a <abbr title="converting the string that comes from an HTTP request into Python data - convertendo a string que vem de uma requisição HTTP em dados Python">"parsing"</abbr> de formulário, com `request.form()`.
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obrigatório se você deseja suporte a <abbr title="convertendo a string que vem de uma requisição HTTP em dados Python">"parsing"</abbr> de formulário, com `request.form()`.
Utilizado pelo FastAPI:
@@ -553,7 +547,7 @@ Existem algumas dependências adicionais que você pode querer instalar.
Dependências opcionais adicionais do Pydantic:
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - para gerenciamento de configurações.
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - para tipos extras a serem utilizados com o Pydantic.
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - tipos extras para serem utilizados com o Pydantic.
Dependências opcionais adicionais do FastAPI:

View File

@@ -31,7 +31,7 @@ Digamos que você tenha uma estrutura de arquivos como esta:
/// tip | Dica
Existem vários arquivos `__init__.py`: um em cada diretório ou subdiretório.
Existem vários arquivos `__init__.py` presentes em cada diretório ou subdiretório.
Isso permite a importação de código de um arquivo para outro.
@@ -43,32 +43,32 @@ from app.routers import items
///
* O diretório `app` contém tudo. E possui um arquivo vazio `app/__init__.py`, então ele é um "pacote Python" (uma coleção de "módulos Python"): `app`.
* Ele contém um arquivo `app/main.py`. Como está dentro de um pacote Python (um diretório com um arquivo `__init__.py`), ele é um "módulo" desse pacote: `app.main`.
* Existe também um arquivo `app/dependencies.py`, assim como `app/main.py`, ele é um "módulo": `app.dependencies`.
* O diretório `app` contém todo o código da aplicação. Ele possui um arquivo `app/__init__.py` vazio, o que o torna um "pacote Python" (uma coleção de "módulos Python"): `app`.
* Dentro dele, o arquivo `app/main.py` está localizado em um pacote Python (diretório com `__init__.py`). Portanto, ele é um "módulo" desse pacote: `app.main`.
* Existem também um arquivo `app/dependencies.py`, assim como o `app/main.py`, ele é um "módulo": `app.dependencies`.
* Há um subdiretório `app/routers/` com outro arquivo `__init__.py`, então ele é um "subpacote Python": `app.routers`.
* O arquivo `app/routers/items.py` está dentro de um pacote, `app/routers/`, portanto é um submódulo: `app.routers.items`.
* O mesmo com `app/routers/users.py`, ele é outro submódulo: `app.routers.users`.
* Há também um subdiretório `app/internal/` com outro arquivo `__init__.py`, então ele é outro "subpacote Python": `app.internal`.
* O arquivo `app/routers/items.py` está dentro de um pacote, `app/routers/`, portanto, é um "submódulo": `app.routers.items`.
* O mesmo com `app/routers/users.py`, ele é outro submódulo: `app.routers.users`.
* Há também um subdiretório `app/internal/` com outro arquivo `__init__.py`, então ele é outro "subpacote Python":`app.internal`.
* E o arquivo `app/internal/admin.py` é outro submódulo: `app.internal.admin`.
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
A mesma estrutura de arquivos com comentários:
```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
├── app # "app" é um pacote Python
│   ├── __init__.py # este arquivo torna "app" um "pacote Python"
│   ├── main.py # "main" módulo, e.g. import app.main
│   ├── dependencies.py # "dependencies" módulo, e.g. import app.dependencies
│   └── routers # "routers" é um "subpacote Python"
│   │ ├── __init__.py # torna "routers" um "subpacote Python"
│   │ ├── items.py # "items" submódulo, e.g. import app.routers.items
│   │ └── users.py # "users" submódulo, e.g. import app.routers.users
│   └── internal # "internal" é um "subpacote Python"
│   ├── __init__.py # torna "internal" um "subpacote Python"
│   └── admin.py # "admin" submódulo, e.g. import app.internal.admin
```
## `APIRouter` { #apirouter }
@@ -79,11 +79,11 @@ Você quer manter as *operações de rota* relacionadas aos seus usuários separ
Mas ele ainda faz parte da mesma aplicação/web API **FastAPI** (faz parte do mesmo "pacote Python").
Você pode criar as *operações de rota* para esse módulo usando o `APIRouter`.
Você pode criar as *operações de rotas* para esse módulo usando o `APIRouter`.
### Importe `APIRouter` { #import-apirouter }
Você o importa e cria uma "instância" da mesma maneira que faria com a classe `FastAPI`:
você o importa e cria uma "instância" da mesma maneira que faria com a classe `FastAPI`:
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
@@ -91,7 +91,7 @@ Você o importa e cria uma "instância" da mesma maneira que faria com a classe
E então você o utiliza para declarar suas *operações de rota*.
Utilize-o da mesma maneira que utilizaria a classe `FastAPI`:
Utilize-o da mesma maneira que utilizaria a classe `FastAPI`:
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
@@ -151,7 +151,7 @@ Então, em vez de adicionar tudo isso a cada *operação de rota*, podemos adici
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
Como o path de cada *operação de rota* tem que começar com `/`, como em:
Como o caminho de cada *operação de rota* deve começar com `/`, como em:
```Python hl_lines="1"
@router.get("/{item_id}")
@@ -163,9 +163,9 @@ async def read_item(item_id: str):
Então, o prefixo neste caso é `/items`.
Também podemos adicionar uma list de `tags` e `responses` extras que serão aplicadas a todas as *operações de rota* incluídas neste router.
Também podemos adicionar uma lista de `tags` e `responses` extras que serão aplicadas a todas as *operações de rota* incluídas neste roteador.
E podemos adicionar uma list de `dependencies` que serão adicionadas a todas as *operações de rota* no router e serão executadas/resolvidas para cada request feita a elas.
E podemos adicionar uma lista de `dependencies` que serão adicionadas a todas as *operações de rota* no roteador e serão executadas/resolvidas para cada request feita a elas.
/// tip | Dica
@@ -173,7 +173,7 @@ Observe que, assim como [dependências em *decoradores de operação de rota*](d
///
O resultado final é que os paths dos itens agora são:
O resultado final é que os caminhos dos itens agora são:
* `/items/`
* `/items/{item_id}`
@@ -183,9 +183,9 @@ O resultado final é que os paths dos itens agora são:
* Elas serão marcadas com uma lista de tags que contêm uma única string `"items"`.
* Essas "tags" são especialmente úteis para os sistemas de documentação interativa automática (usando OpenAPI).
* Todas elas incluirão as `responses` predefinidas.
* Todas essas *operações de rota* terão a list de `dependencies` avaliada/executada antes delas.
* Todas essas *operações de rota* terão a lista de `dependencies` avaliada/executada antes delas.
* Se você também declarar dependências em uma *operação de rota* específica, **elas também serão executadas**.
* As dependências do router são executadas primeiro, depois as [`dependencies` no decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} e, em seguida, as dependências de parâmetros normais.
* As dependências do roteador são executadas primeiro, depois as [`dependencies` no decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} e, em seguida, as dependências de parâmetros normais.
* Você também pode adicionar [dependências de `Segurança` com `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
/// tip | Dica
@@ -246,7 +246,7 @@ from ..dependencies import get_token_header
significa:
* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) vive (o diretório `app/routers/`)...
* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) reside (o diretório `app/routers/`)...
* vá para o pacote pai (o diretório `app/`)...
* e lá, encontre o módulo `dependencies` (o arquivo em `app/dependencies.py`)...
* e dele, importe a função `get_token_header`.
@@ -283,9 +283,9 @@ Mas ainda podemos adicionar _mais_ `tags` que serão aplicadas a uma *operação
/// tip | Dica
Esta última operação de rota terá a combinação de tags: `["items", "custom"]`.
Esta última operação de caminho terá a combinação de tags: `["items", "custom"]`.
E também terá ambas as responses na documentação, uma para `404` e uma para `403`.
E também terá ambas as respostas na documentação, uma para `404` e uma para `403`.
///
@@ -325,7 +325,7 @@ from .routers import items, users
significa:
* Começando no mesmo pacote em que este módulo (o arquivo `app/main.py`) vive (o diretório `app/`)...
* Começando no mesmo pacote em que este módulo (o arquivo `app/main.py`) reside (o diretório `app/`)...
* procure o subpacote `routers` (o diretório em `app/routers/`)...
* e dele, importe o submódulo `items` (o arquivo em `app/routers/items.py`) e `users` (o arquivo em `app/routers/users.py`)...
@@ -376,7 +376,7 @@ Então, para poder usar ambos no mesmo arquivo, importamos os submódulos direta
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
### Inclua os `APIRouter`s para `users` e `items` { #include-the-apirouters-for-users-and-items }
### Inclua os `APIRouter`s para `usuários` e `itens` { #include-the-apirouters-for-users-and-items }
Agora, vamos incluir os `router`s dos submódulos `users` e `items`:
@@ -392,7 +392,7 @@ E `items.router` contém o `APIRouter` dentro do arquivo `app/routers/items.py`.
Com `app.include_router()` podemos adicionar cada `APIRouter` ao aplicativo principal `FastAPI`.
Ele incluirá todas as rotas daquele router como parte dele.
Ele incluirá todas as rotas daquele roteador como parte dele.
/// note | Detalhes Técnicos
@@ -404,7 +404,7 @@ Então, nos bastidores, ele realmente funcionará como se tudo fosse o mesmo apl
/// check | Verifique
Você não precisa se preocupar com desempenho ao incluir routers.
Você não precisa se preocupar com desempenho ao incluir roteadores.
Isso levará microssegundos e só acontecerá na inicialização.
@@ -453,7 +453,7 @@ e funcionará corretamente, junto com todas as outras *operações de rota* adic
/// note | Detalhes Técnicos Avançados
**Nota**: este é um detalhe muito técnico que você provavelmente pode **simplesmente pular**.
**Observação**: este é um detalhe muito técnico que você provavelmente pode **simplesmente pular**.
---
@@ -479,15 +479,15 @@ $ fastapi dev app/main.py
</div>
E abra a documentação em <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
E abra os documentos em <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Você verá a documentação automática da API, incluindo os paths de todos os submódulos, usando os paths (e prefixos) corretos e as tags corretas:
Você verá a documentação automática da API, incluindo os caminhos de todos os submódulos, usando os caminhos (e prefixos) corretos e as tags corretas:
<img src="/img/tutorial/bigger-applications/image01.png">
## Inclua o mesmo router várias vezes com `prefix` diferentes { #include-the-same-router-multiple-times-with-different-prefix }
## Inclua o mesmo roteador várias vezes com `prefix` diferentes { #include-the-same-router-multiple-times-with-different-prefix }
Você também pode usar `.include_router()` várias vezes com o *mesmo* router usando prefixos diferentes.
Você também pode usar `.include_router()` várias vezes com o *mesmo* roteador usando prefixos diferentes.
Isso pode ser útil, por exemplo, para expor a mesma API sob prefixos diferentes, por exemplo, `/api/v1` e `/api/latest`.
@@ -495,10 +495,10 @@ Esse é um uso avançado que você pode não precisar, mas está lá caso precis
## Inclua um `APIRouter` em outro { #include-an-apirouter-in-another }
Da mesma forma que você pode incluir um `APIRouter` em uma aplicação `FastAPI`, você pode incluir um `APIRouter` em outro `APIRouter` usando:
Da mesma forma que você pode incluir um `APIRouter` em um aplicativo `FastAPI`, você pode incluir um `APIRouter` em outro `APIRouter` usando:
```Python
router.include_router(other_router)
```
Certifique-se de fazer isso antes de incluir `router` na aplicação `FastAPI`, para que as *operações de rota* de `other_router` também sejam incluídas.
Certifique-se de fazer isso antes de incluir `router` no aplicativo `FastAPI`, para que as *operações de rota* de `other_router` também sejam incluídas.

View File

@@ -1,6 +1,6 @@
# Corpo - Atualizações { #body-updates }
## Atualização substituindo com `PUT` { #update-replacing-with-put }
## Atualização de dados existentes com `PUT` { #update-replacing-with-put }
Para atualizar um item, você pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a>.
@@ -22,13 +22,13 @@ Isso significa que, se você quiser atualizar o item `bar` usando `PUT` com um c
}
```
como ele não inclui o atributo já armazenado `"tax": 20.2`, o modelo de entrada assumiria o valor padrão de `"tax": 10.5`.
Como ele não inclui o atributo já armazenado `"tax": 20.2`, o modelo de entrada assumiria o valor padrão de `"tax": 10.5`.
E os dados seriam salvos com esse "novo" `tax` de `10.5`.
## Atualizações parciais com `PATCH` { #partial-updates-with-patch }
Você também pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> para atualizar dados *parcialmente*.
Você também pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> para atualizar parcialmente os dados.
Isso significa que você pode enviar apenas os dados que deseja atualizar, deixando o restante intacto.
@@ -40,17 +40,25 @@ E muitas equipes usam apenas `PUT`, mesmo para atualizações parciais.
Você é **livre** para usá-los como preferir, **FastAPI** não impõe restrições.
Mas este guia mostra, mais ou menos, como eles são destinados a serem usados.
Mas este guia te dá uma ideia de como eles são destinados a serem usados.
///
### Usando o parâmetro `exclude_unset` do Pydantic { #using-pydantics-exclude-unset-parameter }
Se você quiser receber atualizações parciais, é muito útil usar o parâmetro `exclude_unset` no `.model_dump()` do modelo do Pydantic.
Se você quiser receber atualizações parciais, é muito útil usar o parâmetro `exclude_unset` no método `.model_dump()` do modelo do Pydantic.
Como `item.model_dump(exclude_unset=True)`.
Isso geraria um `dict` com apenas os dados que foram definidos ao criar o modelo `item`, excluindo os valores padrão.
/// info | Informação
No Pydantic v1, o método que era chamado `.dict()` e foi descontinuado (mas ainda suportado) no Pydantic v2. Agora, deve-se usar o método `.model_dump()`.
Os exemplos aqui usam `.dict()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` a partir do Pydantic v2.
///
Isso gera um `dict` com apenas os dados definidos ao criar o modelo `item`, excluindo os valores padrão.
Então, você pode usar isso para gerar um `dict` com apenas os dados definidos (enviados na solicitação), omitindo valores padrão:
@@ -60,23 +68,31 @@ Então, você pode usar isso para gerar um `dict` com apenas os dados definidos
Agora, você pode criar uma cópia do modelo existente usando `.model_copy()`, e passar o parâmetro `update` com um `dict` contendo os dados para atualizar.
/// info | Informação
No Pydantic v1, o método era chamado `.copy()`, ele foi descontinuado (mas ainda suportado) no Pydantic v2, e renomeado para `.model_copy()`.
Os exemplos aqui usam `.copy()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_copy()` com o Pydantic v2.
///
Como `stored_item_model.model_copy(update=update_data)`:
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
### Recapitulando as atualizações parciais { #partial-updates-recap }
Resumindo, para aplicar atualizações parciais você deveria:
Resumindo, para aplicar atualizações parciais você pode:
* (Opcionalmente) usar `PATCH` em vez de `PUT`.
* Recuperar os dados armazenados.
* Colocar esses dados em um modelo do Pydantic.
* Gerar um `dict` sem valores padrão a partir do modelo de entrada (usando `exclude_unset`).
* Dessa forma, você pode atualizar apenas os valores realmente definidos pelo usuário, em vez de substituir valores já armazenados por valores padrão do modelo.
* Dessa forma, você pode atualizar apenas os valores definidos pelo usuário, em vez de substituir os valores já armazenados com valores padrão em seu modelo.
* Criar uma cópia do modelo armazenado, atualizando seus atributos com as atualizações parciais recebidas (usando o parâmetro `update`).
* Converter o modelo copiado em algo que possa ser armazenado no seu BD (por exemplo, usando o `jsonable_encoder`).
* Isso é comparável a usar o método `.model_dump()` do modelo novamente, mas garante (e converte) os valores para tipos de dados que possam ser convertidos em JSON, por exemplo, `datetime` para `str`.
* Salvar os dados no seu BD.
* Converter o modelo copiado em algo que possa ser armazenado no seu banco de dados (por exemplo, usando o `jsonable_encoder`).
* Isso é comparável ao uso do método `.model_dump()`, mas garante (e converte) os valores para tipos de dados que possam ser convertidos em JSON, por exemplo, `datetime` para `str`.
* Salvar os dados no seu banco de dados.
* Retornar o modelo atualizado.
{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
@@ -93,8 +109,8 @@ Mas o exemplo aqui usa `PATCH` porque foi criado para esses casos de uso.
Observe que o modelo de entrada ainda é validado.
Portanto, se você quiser receber atualizações parciais que possam omitir todos os atributos, você precisa ter um modelo com todos os atributos marcados como opcionais (com valores padrão ou `None`).
Portanto, se você quiser receber atualizações parciais que possam omitir todos os atributos, precisa ter um modelo com todos os atributos marcados como opcionais (com valores padrão ou `None`).
Para distinguir entre os modelos com todos os valores opcionais para **atualizações** e modelos com valores obrigatórios para **criação**, você pode usar as ideias descritas em [Modelos Adicionais](extra-models.md){.internal-link target=_blank}.
Para distinguir os modelos com todos os valores opcionais para **atualizações** e modelos com valores obrigatórios para **criação**, você pode usar as ideias descritas em [Modelos Adicionais](extra-models.md){.internal-link target=_blank}.
///

View File

@@ -10,11 +10,11 @@ Para declarar um corpo da **requisição**, você utiliza os modelos do <a href=
/// info | Informação
Para enviar dados, você deveria usar um dos: `POST` (o mais comum), `PUT`, `DELETE` ou `PATCH`.
Para enviar dados, você deve usar um dos: `POST` (o mais comum), `PUT`, `DELETE` ou `PATCH`.
Enviar um corpo em uma requisição `GET` não tem um comportamento definido nas especificações, porém é suportado pelo FastAPI, apenas para casos de uso bem complexos/extremos.
Como é desencorajado, a documentação interativa com Swagger UI não irá mostrar a documentação para o corpo da requisição ao usar `GET`, e proxies intermediários podem não suportá-lo.
Como é desencorajado, a documentação interativa com Swagger UI não irá mostrar a documentação para o corpo da requisição para um `GET`, e proxies que intermediarem podem não suportar o corpo da requisição.
///
@@ -32,8 +32,7 @@ Utilize os tipos Python padrão para todos os atributos:
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele não é obrigatório. Caso contrário, é obrigatório. Use `None` para torná-lo apenas opcional.
Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele se torna opcional. Caso contrário, se torna obrigatório. Use `None` para torná-lo opcional.
Por exemplo, o modelo acima declara um JSON "`object`" (ou `dict` no Python) como esse:
@@ -67,7 +66,7 @@ Para adicioná-lo à sua *operação de rota*, declare-o da mesma maneira que vo
Apenas com essa declaração de tipos do Python, o **FastAPI** irá:
* Ler o corpo da requisição como JSON.
* Ler o corpo da requisição como um JSON.
* Converter os tipos correspondentes (se necessário).
* Validar os dados.
* Se algum dado for inválido, irá retornar um erro bem claro, indicando exatamente onde e o que estava incorreto.
@@ -128,6 +127,14 @@ Dentro da função, você pode acessar todos os atributos do objeto do modelo di
{* ../../docs_src/body/tutorial002_py310.py *}
/// info | Informação
No Pydantic v1 o método se chamava `.dict()`, ele foi descontinuado (mas ainda é suportado) no Pydantic v2, e renomeado para `.model_dump()`.
Os exemplos aqui usam `.dict()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` se puder usar o Pydantic v2.
///
## Corpo da requisição + parâmetros de rota { #request-body-path-parameters }
Você pode declarar parâmetros de rota e corpo da requisição ao mesmo tempo.
@@ -136,7 +143,6 @@ O **FastAPI** irá reconhecer que os parâmetros da função que combinam com pa
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
## Corpo da requisição + parâmetros de rota + parâmetros de consulta { #request-body-path-query-parameters }
Você também pode declarar parâmetros de **corpo**, **rota** e **consulta**, ao mesmo tempo.

View File

@@ -22,13 +22,21 @@ Aqui está uma ideia geral de como os modelos poderiam parecer com seus campos d
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
### Sobre `**user_in.model_dump()` { #about-user-in-model-dump }
/// info | Informação
#### O `.model_dump()` do Pydantic { #pydantics-model-dump }
No Pydantic v1 o método se chamava `.dict()`, ele foi descontinuado (mas ainda é suportado) no Pydantic v2 e renomeado para `.model_dump()`.
Os exemplos aqui usam `.dict()` por compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` se puder usar o Pydantic v2.
///
### Sobre `**user_in.dict()` { #about-user-in-dict }
#### O `.dict()` do Pydantic { #pydantics-dict }
`user_in` é um modelo Pydantic da classe `UserIn`.
Os modelos Pydantic possuem um método `.model_dump()` que retorna um `dict` com os dados do modelo.
Os modelos Pydantic possuem um método `.dict()` que retorna um `dict` com os dados do modelo.
Então, se criarmos um objeto Pydantic `user_in` como:
@@ -39,7 +47,7 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
e depois chamarmos:
```Python
user_dict = user_in.model_dump()
user_dict = user_in.dict()
```
agora temos um `dict` com os dados na variável `user_dict` (é um `dict` em vez de um objeto de modelo Pydantic).
@@ -95,20 +103,20 @@ UserInDB(
#### Um modelo Pydantic a partir do conteúdo de outro { #a-pydantic-model-from-the-contents-of-another }
Como no exemplo acima, obtivemos o `user_dict` a partir do `user_in.model_dump()`, este código:
Como no exemplo acima, obtivemos o `user_dict` a partir do `user_in.dict()`, este código:
```Python
user_dict = user_in.model_dump()
user_dict = user_in.dict()
UserInDB(**user_dict)
```
seria equivalente a:
```Python
UserInDB(**user_in.model_dump())
UserInDB(**user_in.dict())
```
...porque `user_in.model_dump()` é um `dict`, e depois fazemos o Python "desembrulhá-lo" passando-o para `UserInDB` precedido por `**`.
...porque `user_in.dict()` é um `dict`, e depois fazemos o Python "desembrulhá-lo" passando-o para `UserInDB` precedido por `**`.
Então, obtemos um modelo Pydantic a partir dos dados em outro modelo Pydantic.
@@ -117,7 +125,7 @@ Então, obtemos um modelo Pydantic a partir dos dados em outro modelo Pydantic.
E, então, adicionando o argumento de palavra-chave extra `hashed_password=hashed_password`, como em:
```Python
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
UserInDB(**user_in.dict(), hashed_password=hashed_password)
```
...acaba sendo como:

View File

@@ -33,7 +33,7 @@ Para isso, primeiro importe:
O FastAPI adicionou suporte a `Annotated` (e passou a recomendá-lo) na versão 0.95.0.
Se você tiver uma versão mais antiga, teria erros ao tentar usar `Annotated`.
Se você tiver uma versão mais antiga, terá erros ao tentar usar `Annotated`.
Certifique-se de [Atualizar a versão do FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} para pelo menos 0.95.1 antes de usar `Annotated`.
@@ -109,7 +109,7 @@ Agora o FastAPI vai:
## Alternativa (antiga): `Query` como valor padrão { #alternative-old-query-as-the-default-value }
Versões anteriores do FastAPI (antes de <abbr title="before 2023-03 - antes de 2023-03">0.95.0</abbr>) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`, há uma grande chance de você ver código usando isso por aí, então vou explicar.
Versões anteriores do FastAPI (antes de <abbr title="antes de 2023-03">0.95.0</abbr>) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`. É muito provável que você veja código assim por aí, então vou te explicar.
/// tip | Dica
@@ -192,7 +192,7 @@ Você também pode adicionar um parâmetro `min_length`:
## Adicione expressões regulares { #add-regular-expressions }
Você pode definir um `pattern` de <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings. - Uma expressão regular, regex ou regexp é uma sequência de caracteres que define um padrão de busca para strings.">expressão regular</abbr> que o parâmetro deve corresponder:
Você pode definir um `pattern` de <abbr title="Uma expressão regular, regex ou regexp é uma sequência de caracteres que define um padrão de busca para strings.">expressão regular</abbr> que o parâmetro deve corresponder:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
@@ -206,6 +206,20 @@ Se você se sentir perdido com essas ideias de **"expressão regular"**, não se
Agora você sabe que, sempre que precisar delas, pode usá-las no **FastAPI**.
### Pydantic v1 `regex` em vez de `pattern` { #pydantic-v1-regex-instead-of-pattern }
Antes da versão 2 do Pydantic e antes do FastAPI 0.100.0, o parâmetro se chamava `regex` em vez de `pattern`, mas agora está descontinuado.
Você ainda pode ver algum código usando isso:
//// tab | Pydantic v1
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
////
Mas saiba que isso está descontinuado e deve ser atualizado para usar o novo parâmetro `pattern`. 🤓
## Valores padrão { #default-values }
Você pode, claro, usar valores padrão diferentes de `None`.
@@ -266,7 +280,7 @@ Então, com uma URL como:
http://localhost:8000/items/?q=foo&q=bar
```
você receberia os múltiplos valores dos *parâmetros de consulta* `q` (`foo` e `bar`) em uma `list` Python dentro da sua *função de operação de rota*, no *parâmetro da função* `q`.
você receberá os múltiplos valores do *parâmetro de consulta* `q` (`foo` e `bar`) em uma `list` Python dentro da sua *função de operação de rota*, no *parâmetro da função* `q`.
Assim, a resposta para essa URL seria:
@@ -336,7 +350,7 @@ Essas informações serão incluídas no OpenAPI gerado e usadas pelas interface
Tenha em mente que ferramentas diferentes podem ter níveis diferentes de suporte ao OpenAPI.
Algumas delas podem ainda não mostrar todas as informações extras declaradas, embora na maioria dos casos a funcionalidade ausente já esteja planejada para desenvolvimento.
Algumas delas podem ainda não mostrar todas as informações extras declaradas, embora na maioria dos casos o recurso ausente já esteja planejado para desenvolvimento.
///
@@ -372,7 +386,7 @@ Então você pode declarar um `alias`, e esse alias será usado para encontrar o
Agora digamos que você não gosta mais desse parâmetro.
Você tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está <abbr title="obsolete, recommended not to use it - obsoleto, recomenda-se não usá-lo">deprecated</abbr>.
Você tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está <abbr title="obsoleto, recomenda-se não usá-lo">descontinuado</abbr>.
Então passe o parâmetro `deprecated=True` para `Query`:
@@ -402,7 +416,7 @@ O Pydantic também tem <a href="https://docs.pydantic.dev/latest/concepts/valida
///
Por exemplo, este validador personalizado verifica se o ID do item começa com `isbn-` para um número de livro <abbr title="ISBN means International Standard Book Number - ISBN significa Número Padrão Internacional de Livro">ISBN</abbr> ou com `imdb-` para um ID de URL de filme <abbr title="IMDB (Internet Movie Database) is a website with information about movies - IMDB (Internet Movie Database) é um site com informações sobre filmes">IMDB</abbr>:
Por exemplo, este validador personalizado verifica se o ID do item começa com `isbn-` para um número de livro <abbr title="ISBN significa Número Padrão Internacional de Livro">ISBN</abbr> ou com `imdb-` para um ID de URL de filme <abbr title="IMDB (Internet Movie Database) é um site com informações sobre filmes">IMDB</abbr>:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
@@ -414,7 +428,7 @@ Isso está disponível com a versão 2 do Pydantic ou superior. 😎
/// tip | Dica
Se você precisar fazer qualquer tipo de validação que exija comunicação com algum **componente externo**, como um banco de dados ou outra API, você deveria usar **Dependências do FastAPI** em vez disso; você aprenderá sobre elas mais adiante.
Se você precisar fazer qualquer tipo de validação que exija comunicação com algum **componente externo**, como um banco de dados ou outra API, você deve usar **Dependências do FastAPI** em vez disso; você aprenderá sobre elas mais adiante.
Esses validadores personalizados são para coisas que podem ser verificadas **apenas** com os **mesmos dados** fornecidos na requisição.
@@ -426,7 +440,7 @@ O ponto importante é apenas usar **`AfterValidator` com uma função dentro de
---
Mas se você estiver curioso sobre este exemplo de código específico e ainda entretido, aqui vão alguns detalhes extras.
Mas se você está curioso sobre este exemplo específico e ainda entretido, aqui vão alguns detalhes extras.
#### String com `value.startswith()` { #string-with-value-startswith }
@@ -436,7 +450,7 @@ Percebeu? Uma string usando `value.startswith()` pode receber uma tupla, e verif
#### Um item aleatório { #a-random-item }
Com `data.items()` obtemos um <abbr title="Something we can iterate on with a for loop, like a list, set, etc. - Algo que podemos iterar com um laço for, como uma list, set, etc.">objeto iterável</abbr> com tuplas contendo a chave e o valor de cada item do dicionário.
Com `data.items()` obtemos um <abbr title="Algo que podemos iterar com um laço for, como uma list, set, etc.">objeto iterável</abbr> com tuplas contendo a chave e o valor de cada item do dicionário.
Convertimos esse objeto iterável em uma `list` adequada com `list(data.items())`.

View File

@@ -252,6 +252,20 @@ Então, se você enviar uma solicitação para essa *operação de rota* para o
/// info | Informação
No Pydantic v1, o método era chamado `.dict()`, ele foi descontinuado (mas ainda suportado) no Pydantic v2 e renomeado para `.model_dump()`.
Os exemplos aqui usam `.dict()` para compatibilidade com Pydantic v1, mas você deve usar `.model_dump()` em vez disso se puder usar Pydantic v2.
///
/// info | Informação
O FastAPI usa `.dict()` do modelo Pydantic com <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">seu parâmetro `exclude_unset`</a> para chegar a isso.
///
/// info | Informação
Você também pode usar:
* `response_model_exclude_defaults=True`

View File

@@ -8,17 +8,39 @@ Aqui estão várias maneiras de fazer isso.
Você pode declarar `examples` para um modelo Pydantic que serão adicionados ao JSON Schema gerado.
//// tab | Pydantic v2
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
////
//// tab | Pydantic v1
{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
////
Essas informações extras serão adicionadas como estão ao **JSON Schema** de saída para esse modelo e serão usadas na documentação da API.
Você pode usar o atributo `model_config`, que recebe um `dict`, conforme descrito na <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">documentação do Pydantic: Configuration</a>.
//// tab | Pydantic v2
Na versão 2 do Pydantic, você usaria o atributo `model_config`, que recebe um `dict`, conforme descrito na <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">documentação do Pydantic: Configuration</a>.
Você pode definir `"json_schema_extra"` com um `dict` contendo quaisquer dados adicionais que você queira que apareçam no JSON Schema gerado, incluindo `examples`.
////
//// tab | Pydantic v1
Na versão 1 do Pydantic, você usaria uma classe interna `Config` e `schema_extra`, conforme descrito na <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">documentação do Pydantic: Schema customization</a>.
Você pode definir `schema_extra` com um `dict` contendo quaisquer dados adicionais que você queira que apareçam no JSON Schema gerado, incluindo `examples`.
////
/// tip | Dica
Você poderia usar a mesma técnica para estender o JSON Schema e adicionar suas próprias informações extras personalizadas.
Você pode usar a mesma técnica para estender o JSON Schema e adicionar suas próprias informações extras personalizadas.
Por exemplo, você poderia usá-la para adicionar metadados para uma interface de usuário de front-end, etc.
@@ -28,7 +50,7 @@ Por exemplo, você poderia usá-la para adicionar metadados para uma interface d
O OpenAPI 3.1.0 (usado desde o FastAPI 0.99.0) adicionou suporte a `examples`, que faz parte do padrão **JSON Schema**.
Antes disso, ele suportava apenas a palavrachave `example` com um único exemplo. Isso ainda é suportado pelo OpenAPI 3.1.0, mas é descontinuado e não faz parte do padrão JSON Schema. Portanto, você é incentivado a migrar de `example` para `examples`. 🤓
Antes disso, ele suportava apenas a palavrachave `example` com um único exemplo. Isso ainda é suportado pelo OpenAPI 3.1.0, mas é descontinuado e não faz parte do padrão JSON Schema. Portanto, é recomendado migrar de `example` para `examples`. 🤓
Você pode ler mais no final desta página.
@@ -80,7 +102,7 @@ No entanto, <abbr title="2023-08-26">no momento em que isto foi escrito</abbr>,
Antes do **JSON Schema** suportar `examples`, o OpenAPI já tinha suporte para um campo diferente também chamado `examples`.
Esse `examples` **específico do OpenAPI** vai em outra seção da especificação OpenAPI. Ele fica nos **detalhes de cada *operação de rota***, não dentro de cada JSON Schema.
Esse `examples` específico do OpenAPI vai em outra seção da especificação. Ele fica nos **detalhes de cada função de operação de rota**, não dentro de cada JSON Schema.
E o Swagger UI tem suportado esse campo `examples` particular há algum tempo. Então, você pode usá-lo para **mostrar** diferentes **exemplos na UI da documentação**.
@@ -167,9 +189,9 @@ Depois, o JSON Schema adicionou um campo <a href="https://json-schema.org/draft/
E então o novo OpenAPI 3.1.0 passou a se basear na versão mais recente (JSON Schema 2020-12), que incluiu esse novo campo `examples`.
E agora esse novo campo `examples` tem precedência sobre o antigo campo único (e customizado) `example`, que agora está descontinuado.
Agora, esse novo campo `examples` tem precedência sobre o antigo (e customizado) campo único `example`, que agora está descontinuado.
Esse novo campo `examples` no JSON Schema é **apenas uma `list`** de exemplos, não um dict com metadados extras como nos outros lugares do OpenAPI (descritos acima).
Esse novo campo `examples` no JSON Schema é **apenas uma `list`** de exemplos, não um `dict` com metadados extras como nos outros lugares do OpenAPI (descritos acima).
/// info | Informação
@@ -191,7 +213,7 @@ Mas agora que o FastAPI 0.99.0 e superiores usam o OpenAPI 3.1.0, que usa o JSON
### Swagger UI e `examples` específicos do OpenAPI { #swagger-ui-and-openapi-specific-examples }
Agora, como o Swagger UI não suportava vários exemplos no JSON Schema (em 2023-08-26), os usuários não tinham uma forma de mostrar vários exemplos na documentação.
Como o Swagger UI não suportava vários exemplos no JSON Schema (em 2023-08-26), os usuários não tinham uma forma de mostrar vários exemplos na documentação.
Para resolver isso, o FastAPI `0.103.0` **adicionou suporte** para declarar o mesmo antigo campo **específico do OpenAPI** `examples` com o novo parâmetro `openapi_examples`. 🤓

View File

@@ -1,8 +1,8 @@
# Тестовый файл LLM { #llm-test-file }
Этот документ проверяет, понимает ли <abbr title="Large Language Model - Большая языковая модель">LLM</abbr>, переводящая документацию, `general_prompt` в `scripts/translate.py` и языковой специфичный промпт в `docs/{language code}/llm-prompt.md`. Языковой специфичный промпт добавляется к `general_prompt`.
Этот документ проверяет, понимает ли <abbr title="Large Language Model Большая языковая модель">LLM</abbr>, переводящая документацию, `general_prompt` в `scripts/translate.py` и языковой специфичный промпт в `docs/{language code}/llm-prompt.md`. Языковой специфичный промпт добавляется к `general_prompt`.
Тесты, добавленные здесь, увидят все создатели языковых специфичных промптов.
Тесты, добавленные здесь, увидят все создатели языковых промптов.
Использование:
@@ -11,7 +11,7 @@
* Проверьте, всё ли в порядке в переводе.
* При необходимости улучшите ваш языковой специфичный промпт, общий промпт или английский документ.
* Затем вручную исправьте оставшиеся проблемы в переводе, чтобы он был хорошим.
* Переведите заново, имея хороший перевод на месте. Идеальным результатом будет ситуация, когда LLM больше не вносит изменений в перевод. Это означает, что общий промпт и ваш языковой специфичный промпт настолько хороши, насколько это возможно (иногда он будет делать несколько, казалось бы, случайных изменений, причина в том, что <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM — недетерминированные алгоритмы</a>).
* Переведите заново, имея хороший перевод на месте. Идеальным результатом будет ситуация, когда LLM больше не вносит изменений в перевод. Это означает, что общий промпт и ваш языковой специфичный промпт максимально хороши (иногда он будет делать несколько, казалось бы, случайных изменений, причина в том, что <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM — недетерминированные алгоритмы</a>).
Тесты:
@@ -197,10 +197,10 @@ works(foo="bar") # Это работает 🎉
### 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 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-an-explanation }
@@ -209,8 +209,8 @@ works(foo="bar") # Это работает 🎉
### 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>.
* <abbr title="Mozilla Developer Network Сеть разработчиков Mozilla: документация для разработчиков, созданная командой Firefox">MDN</abbr>
* <abbr title="Input/Output Ввод/Вывод: чтение или запись на диск, сетевое взаимодействие.">I/O</abbr>.
////

View File

@@ -14,7 +14,7 @@
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
### Использование имени *функции-обработчика пути* как operationId { #using-the-path-operation-function-name-as-the-operationid }
### Использование имени функции-обработчика пути как operationId { #using-the-path-operation-function-name-as-the-operationid }
Если вы хотите использовать имена функций ваших API в качестве `operationId`, вы можете пройти по всем из них и переопределить `operation_id` каждой *операции пути* с помощью их `APIRoute.name`.
@@ -38,7 +38,7 @@
## Исключить из OpenAPI { #exclude-from-openapi }
Чтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматических систем документации), используйте параметр `include_in_schema` и установите его в `False`:
Чтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматической документации), используйте параметр `include_in_schema` и установите его в `False`:
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
@@ -48,7 +48,7 @@
Добавление `\f` (экранированного символа «form feed») заставит **FastAPI** обрезать текст, используемый для OpenAPI, в этой точке.
Это не отобразится в документации, но другие инструменты (например, Sphinx) смогут использовать остальное.
Эта часть не попадёт в документацию, но другие инструменты (например, Sphinx) смогут использовать остальное.
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
@@ -56,7 +56,7 @@
Вы, вероятно, уже видели, как объявлять `response_model` и `status_code` для *операции пути*.
Это определяет метаданные об основном HTTP-ответе *операции пути*.
Это определяет метаданные об основном ответе *операции пути*.
Также можно объявлять дополнительные ответы с их моделями, статус-кодами и т.д.
@@ -76,7 +76,7 @@
Там есть `tags`, `parameters`, `requestBody`, `responses` и т.д.
Эта специфичная для *операции пути* схема OpenAPI обычно генерируется автоматически **FastAPI**, но вы также можете её расширить.
Эта спецификация OpenAPI, специфичная для *операции пути*, обычно генерируется автоматически **FastAPI**, но вы также можете её расширить.
/// tip | Совет
@@ -129,13 +129,13 @@
}
```
### Пользовательская схема OpenAPI для *операции пути* { #custom-openapi-path-operation-schema }
### Пользовательская схема OpenAPI для операции пути { #custom-openapi-path-operation-schema }
Словарь в `openapi_extra` будет глубоко объединён с автоматически сгенерированной схемой OpenAPI для *операции пути*.
Словарь в `openapi_extra` будет объединён с автоматически сгенерированной схемой OpenAPI для *операции пути*.
Таким образом, вы можете добавить дополнительные данные к автоматически сгенерированной схеме.
Например, вы можете решить читать и валидировать HTTP-запрос своим кодом, не используя автоматические возможности FastAPI и Pydantic, но при этом захотите описать HTTP-запрос в схеме OpenAPI.
Например, вы можете решить читать и валидировать запрос своим кодом, не используя автоматические возможности FastAPI и Pydantic, но при этом захотите описать запрос в схеме OpenAPI.
Это можно сделать с помощью `openapi_extra`:
@@ -149,20 +149,52 @@
Используя тот же приём, вы можете воспользоваться Pydantic-моделью, чтобы определить JSON Schema, которая затем будет включена в пользовательский раздел схемы OpenAPI для *операции пути*.
И вы можете сделать это, даже если тип данных в HTTP-запросе — не JSON.
И вы можете сделать это, даже если тип данных в запросе — не JSON.
Например, в этом приложении мы не используем встроенную функциональность FastAPI для извлечения JSON Schema из моделей Pydantic, равно как и автоматическую валидацию JSON. Мы объявляем тип содержимого HTTP-запроса как YAML, а не JSON:
Например, в этом приложении мы не используем встроенную функциональность FastAPI для извлечения JSON Schema из моделей Pydantic, равно как и автоматическую валидацию JSON. Мы объявляем тип содержимого запроса как YAML, а не JSON:
//// tab | Pydantic v2
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
////
//// tab | Pydantic v1
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[15:20, 22] *}
////
/// info | Информация
В Pydantic версии 1 метод для получения JSON Schema модели назывался `Item.schema()`, в Pydantic версии 2 метод называется `Item.model_json_schema()`.
///
Тем не менее, хотя мы не используем встроенную функциональность по умолчанию, мы всё равно используем Pydantic-модель, чтобы вручную сгенерировать JSON Schema для данных, которые мы хотим получить в YAML.
Затем мы работаем с HTTP-запросом напрямую и извлекаем тело как `bytes`. Это означает, что FastAPI даже не попытается распарсить полезную нагрузку HTTP-запроса как JSON.
Затем мы работаем с запросом напрямую и извлекаем тело как `bytes`. Это означает, что FastAPI даже не попытается распарсить полезную нагрузку запроса как JSON.
А затем в нашем коде мы напрямую парсим это содержимое YAML и снова используем ту же Pydantic-модель, чтобы валидировать YAML-содержимое:
А затем в нашем коде мы напрямую парсим этот YAML и снова используем ту же Pydantic-модель для валидации YAML-содержимого:
//// tab | Pydantic v2
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
////
//// tab | Pydantic v1
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[24:31] *}
////
/// info | Информация
В Pydantic версии 1 метод для парсинга и валидации объекта назывался `Item.parse_obj()`, в Pydantic версии 2 метод называется `Item.model_validate()`.
///
/// tip | Совет
Здесь мы переиспользуем ту же Pydantic-модель.

View File

@@ -46,6 +46,12 @@ $ pip install "fastapi[all]"
</div>
/// info | Информация
В Pydantic v1 он входил в основной пакет. Теперь он распространяется как отдельный пакет, чтобы вы могли установить его только при необходимости.
///
### Создание объекта `Settings` { #create-the-settings-object }
Импортируйте `BaseSettings` из Pydantic и создайте подкласс, очень похожий на Pydanticмодель.
@@ -54,8 +60,24 @@ $ pip install "fastapi[all]"
Вы можете использовать все те же возможности валидации и инструменты, что и для Pydanticмоделей, например разные типы данных и дополнительную валидацию через `Field()`.
//// tab | Pydantic v2
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
////
//// tab | Pydantic v1
/// info | Информация
В Pydantic v1 вы бы импортировали `BaseSettings` напрямую из `pydantic`, а не из `pydantic_settings`.
///
{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *}
////
/// tip | Совет
Если вам нужно что-то быстро скопировать и вставить, не используйте этот пример — воспользуйтесь последним ниже.
@@ -193,6 +215,8 @@ APP_NAME="ChimichangApp"
Затем обновите ваш `config.py` так:
//// tab | Pydantic v2
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
/// tip | Совет
@@ -201,6 +225,26 @@ APP_NAME="ChimichangApp"
///
////
//// tab | Pydantic v1
{* ../../docs_src/settings/app03_an_py39/config_pv1.py hl[9:10] *}
/// tip | Совет
Класс `Config` используется только для конфигурации Pydantic. Подробнее см. <a href="https://docs.pydantic.dev/1.10/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
///
////
/// info | Информация
В Pydantic версии 1 конфигурация задавалась во внутреннем классе `Config`, в Pydantic версии 2 — в атрибуте `model_config`. Этот атрибут принимает `dict`, и чтобы получить автозавершение и ошибки «на лету», вы можете импортировать и использовать `SettingsConfigDict` для описания этого `dict`.
///
Здесь мы задаем параметр конфигурации `env_file` внутри вашего класса Pydantic `Settings` и устанавливаем значение равным имени файла dotenv, который хотим использовать.
### Создание `Settings` только один раз с помощью `lru_cache` { #creating-the-settings-only-once-with-lru-cache }

View File

@@ -2,23 +2,21 @@
Если у вас старое приложение FastAPI, возможно, вы используете Pydantic версии 1.
FastAPI версии 0.100.0 поддерживал либо Pydantic v1, либо v2. Он использовал ту версию, которая была установлена.
FastAPI поддерживает и Pydantic v1, и v2 начиная с версии 0.100.0.
FastAPI версии 0.119.0 добавил частичную поддержку Pydantic v1 изнутри Pydantic v2 (как `pydantic.v1`), чтобы упростить миграцию на v2.
Если у вас был установлен Pydantic v2, использовался он. Если вместо этого был установлен Pydantic v1 — использовался он.
FastAPI 0.126.0 убрал поддержку Pydantic v1, при этом ещё некоторое время продолжал поддерживать `pydantic.v1`.
Сейчас Pydantic v1 объявлен устаревшим, и поддержка его будет удалена в следующих версиях FastAPI, поэтому вам следует **перейти на Pydantic v2**. Так вы получите последние возможности, улучшения и исправления.
/// warning | Предупреждение
Команда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с **Python 3.14**.
Это включает `pydantic.v1`, который больше не поддерживается в Python 3.14 и выше.
Кроме того, команда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с **Python 3.14**.
Если вы хотите использовать последние возможности Python, вам нужно убедиться, что вы используете Pydantic v2.
///
Если у вас старое приложение FastAPI с Pydantic v1, здесь я покажу, как мигрировать на Pydantic v2, и **возможности FastAPI 0.119.0**, которые помогут выполнить постепенную миграцию.
Если у вас старое приложение FastAPI с Pydantic v1, здесь я покажу, как мигрировать на Pydantic v2, и **новые возможности в FastAPI 0.119.0**, которые помогут выполнить постепенную миграцию.
## Официальное руководство { #official-guide }
@@ -40,13 +38,13 @@ FastAPI 0.126.0 убрал поддержку Pydantic v1, при этом ещ
Вы можете использовать <a href="https://github.com/pydantic/bump-pydantic" class="external-link" target="_blank">`bump-pydantic`</a> от той же команды Pydantic.
Этот инструмент поможет автоматически изменить большую часть кода, который нужно изменить.
Этот инструмент поможет автоматически внести большую часть необходимых изменений в код.
После этого вы можете запустить тесты и проверить, что всё работает. Если да — на этом всё. 😎
После этого запустите тесты и проверьте, что всё работает. Если да — на этом всё. 😎
## Pydantic v1 в v2 { #pydantic-v1-in-v2 }
Pydantic v2 включает всё из Pydantic v1 как подмодуль `pydantic.v1`. Но это больше не поддерживается в версиях Python выше 3.13.
Pydantic v2 включает всё из Pydantic v1 как подмодуль `pydantic.v1`.
Это означает, что вы можете установить последнюю версию Pydantic v2 и импортировать и использовать старые компоненты Pydantic v1 из этого подмодуля так, как если бы у вас был установлен старый Pydantic v1.
@@ -54,7 +52,7 @@ Pydantic v2 включает всё из Pydantic v1 как подмодуль `
### Поддержка FastAPI для Pydantic v1 внутри v2 { #fastapi-support-for-pydantic-v1-in-v2 }
Начиная с FastAPI 0.119.0, есть также частичная поддержка Pydantic v1 изнутри Pydantic v2, чтобы упростить миграцию на v2.
Начиная с FastAPI 0.119.0, есть также частичная поддержка Pydantic v1 в составе Pydantic v2, чтобы упростить миграцию на v2.
Таким образом, вы можете обновить Pydantic до последней версии 2 и сменить импорты на подмодуль `pydantic.v1` — во многих случаях всё просто заработает.
@@ -108,7 +106,7 @@ graph TB
style V2Field fill:#f9fff3
```
В некоторых случаях можно использовать и модели Pydantic v1, и v2 в одной и той же **операции пути** (обработчике пути) вашего приложения FastAPI:
В некоторых случаях можно использовать и модели Pydantic v1, и v2 в одной и той же операции пути (обработчике пути) вашего приложения FastAPI:
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
@@ -124,12 +122,12 @@ graph TB
/// tip | Совет
Сначала попробуйте `bump-pydantic`: если тесты проходят и всё работает, вы справились одной командой. ✨
Сначала попробуйте `bump-pydantic`. Если тесты проходят и всё работает, вы справились одной командой. ✨
///
Если `bump-pydantic` не подходит для вашего случая, вы можете использовать поддержку одновременной работы моделей Pydantic v1 и v2 в одном приложении, чтобы мигрировать на Pydantic v2 постепенно.
Сначала вы можете обновить Pydantic до последней 2-й версии и изменить импорты так, чтобы все ваши модели использовали `pydantic.v1`.
Сначала обновите Pydantic до последней 2-й версии и измените импорты так, чтобы все ваши модели использовали `pydantic.v1`.
Затем вы можете начать мигрировать ваши модели с Pydantic v1 на v2 группами, поэтапно. 🚶
Затем начните мигрировать ваши модели с Pydantic v1 на v2 группами, поэтапно. 🚶

View File

@@ -2,7 +2,7 @@
При использовании **Pydantic v2** сгенерированный OpenAPI становится чуть более точным и **корректным**, чем раньше. 😎
На самом деле, в некоторых случаях в OpenAPI будет даже **две JSON-схемы** для одной и той же Pydanticмодели: для входа и для выхода — в зависимости от наличия **значений по умолчанию**.
На самом деле, в некоторых случаях в OpenAPI будет даже **две JSON схемы** для одной и той же Pydanticмодели: для входа и для выхода — в зависимости от наличия **значений по умолчанию**.
Посмотрим, как это работает, и как это изменить при необходимости.
@@ -34,7 +34,7 @@
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
…то, поскольку у `description` есть значение по умолчанию, если вы **ничего не вернёте** для этого поля, оно всё равно будет иметь это **значение по умолчанию**.
…то, поскольку у `description` есть значение по умолчанию, даже если вы **ничего не вернёте** для этого поля, оно всё равно будет иметь это **значение по умолчанию**.
### Модель для данных ответа { #model-for-output-response-data }
@@ -46,13 +46,13 @@
Это означает, что у него **всегда будет какое‑то значение**, просто иногда это значение может быть `None` (или `null` в JSON).
Это означает, что клиентам, использующим ваш API, не нужно проверять, существует ли это значение или нет: они могут **исходить из того, что поле всегда присутствует**, но в некоторых случаях оно будет иметь значение по умолчанию `None`.
Следовательно, клиентам, использующим ваш API, не нужно проверять наличие этого значения: они могут **исходить из того, что поле всегда присутствует**, а в некоторых случаях имеет значение по умолчанию `None`.
В OpenAPI это описывается тем, что поле помечается как **обязательное**, поскольку оно всегда присутствует.
Из‑за этого JSON Schema для модели может отличаться в зависимости от использования для **входа** или **выхода**:
* для **входа** `description` **не будет обязательным**
* для **входа** `description` не будет обязательным
* для **выхода** оно будет **обязательным** (и при этом может быть `None`, или, в терминах JSON, `null`)
### Выходная модель в документации { #model-for-output-in-docs }
@@ -81,9 +81,9 @@
Однако бывают случаи, когда вы хотите иметь **одну и ту же схему для входа и выхода**.
Главный сценарий — когда у вас уже есть сгенерированный клиентский код/SDK, и вы пока не хотите обновлять весь этот автогенерируемый клиентский код/SDK, вероятно, вы захотите сделать это в какой-то момент, но, возможно, не прямо сейчас.
Главный сценарий — когда у вас уже есть сгенерированный клиентский код/SDK, и вы пока не хотите обновлять весь этот автогенерируемый код/SDK (рано или поздно вы это сделаете, но не сейчас).
В таком случае вы можете отключить эту функциональность в **FastAPI** с помощью параметра `separate_input_output_schemas=False`.
В таком случае вы можете отключить эту функциональность в FastAPI с помощью параметра `separate_input_output_schemas=False`.
/// info | Информация
@@ -95,8 +95,10 @@
### Одна и та же схема для входной и выходной моделей в документации { #same-schema-for-input-and-output-models-in-docs }
И теперь для модели будет одна общая схема и для входа, и для выхода — только `Item`, и в ней `description` будет **не обязательным**:
Теперь для этой модели будет одна общая схема и для входа, и для выхода — только `Item`, и в ней `description` будет **не обязательным**:
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
</div>
Это то же поведение, что и в Pydantic v1. 🤓

View File

@@ -5,10 +5,10 @@
</style>
<p align="center">
<a href="https://fastapi.tiangolo.com/ru"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
</p>
<p align="center">
<em>Фреймворк FastAPI: высокая производительность, прост в изучении, позволяет быстро писать код, готов к продакшн</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">
@@ -40,7 +40,7 @@ FastAPI — это современный, быстрый (высокопрои
* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых доступных фреймворков Python](#performance).
* **Быстрота разработки**: Увеличьте скорость разработки фич примерно на 200300%. *
* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). *
* **Интуитивность**: Отличная поддержка редактора кода. <abbr title="также известное как: автодополнение, автозавершение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
* **Интуитивность**: Отличная поддержка редактора кода. <abbr title="также известное как: автодополнение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
* **Простота**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации.
* **Краткость**: Минимизируйте дублирование кода. Несколько возможностей из каждого объявления параметров. Меньше ошибок.
* **Надежность**: Получите код, готовый к продакшн. С автоматической интерактивной документацией.
@@ -117,12 +117,6 @@ FastAPI — это современный, быстрый (высокопрои
---
## Мини-документальный фильм о 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**, FastAPI для CLI { #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>
@@ -263,7 +257,7 @@ INFO: Application startup complete.
* Получает HTTP-запросы по _путям_ `/` и `/items/{item_id}`.
* Оба _пути_ используют `GET` <em>операции</em> (также известные как HTTP _методы_).
* _Путь_ `/items/{item_id}` имеет _path-параметр_ `item_id`, который должен быть `int`.
* _Путь_ `/items/{item_id}` имеет _параметр пути_ `item_id`, который должен быть `int`.
* _Путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`.
### Интерактивная документация API { #interactive-api-docs }
@@ -284,9 +278,9 @@ INFO: Application startup complete.
## Пример обновления { #example-upgrade }
Теперь измените файл `main.py`, чтобы принимать тело запроса из `PUT` HTTP-запроса.
Теперь измените файл `main.py`, чтобы принимать тело запроса из `PUT` запроса.
Объявите тело запроса, используя стандартные типы Python, спасибо Pydantic.
Объявите тело, используя стандартные типы Python, спасибо Pydantic.
```Python hl_lines="4 9-12 25-27"
from typing import Union
@@ -324,7 +318,7 @@ def update_item(item_id: int, item: Item):
Перейдите на <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
* Интерактивная документация API будет автоматически обновлена, включая новое тело запроса:
* Интерактивная документация API будет автоматически обновлена, включая новое тело:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
@@ -340,13 +334,13 @@ def update_item(item_id: int, item: Item):
Теперь откройте <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
* Альтернативная документация также отразит новый параметр запроса и тело запроса:
* Альтернативная документация также отразит новый параметр запроса и тело:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### Подведём итоги { #recap }
Итак, вы объявляете **один раз** типы параметров, тело запроса и т.д. как параметры функции.
Итак, вы объявляете **один раз** типы параметров, тела запроса и т.д. как параметры функции.
Вы делаете это с помощью стандартных современных типов Python.
@@ -396,13 +390,13 @@ item: Item
Возвращаясь к предыдущему примеру кода, **FastAPI** будет:
* Валидировать наличие `item_id` в пути для `GET` и `PUT` HTTP-запросов.
* Валидировать, что `item_id` имеет тип `int` для `GET` и `PUT` HTTP-запросов.
* Валидировать наличие `item_id` в пути для `GET` и `PUT` запросов.
* Валидировать, что `item_id` имеет тип `int` для `GET` и `PUT` запросов.
* Если это не так, клиент увидит полезную понятную ошибку.
* Проверять, есть ли необязательный параметр запроса с именем `q` (например, `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET` HTTP-запросов.
* Проверять, есть ли необязательный параметр запроса с именем `q` (например, `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET` запросов.
* Поскольку параметр `q` объявлен с `= None`, он необязателен.
* Без `None` он был бы обязательным (как тело запроса в случае с `PUT`).
* Для `PUT` HTTP-запросов к `/items/{item_id}` читать тело запроса как JSON:
* Для `PUT` запросов к `/items/{item_id}` читать тело запроса как JSON:
* Проверять, что есть обязательный атрибут `name`, который должен быть `str`.
* Проверять, что есть обязательный атрибут `price`, который должен быть `float`.
* Проверять, что есть необязательный атрибут `is_offer`, который должен быть `bool`, если он присутствует.
@@ -441,11 +435,11 @@ item: Item
Более полный пример с дополнительными возможностями см. в <a href="https://fastapi.tiangolo.com/ru/tutorial/">Учебник - Руководство пользователя</a>.
**Осторожно, спойлер**: учебник - руководство пользователя включает:
**Осторожно, спойлер**: учебник - руководство включает:
* Объявление **параметров** из других источников: **HTTP-заголовки**, **cookies**, **поля формы** и **файлы**.
* Как задать **ограничения валидации** вроде `maximum_length` или `regex`.
* Очень мощную и простую в использовании систему **<abbr title="также известна как: компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</abbr>**.
* Очень мощную и простую в использовании систему **<abbr title="также известная как: компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</abbr>**.
* Безопасность и аутентификацию, включая поддержку **OAuth2** с **JWT токенами** и **HTTP Basic** аутентификацию.
* Более продвинутые (но столь же простые) приёмы объявления **глубоко вложенных JSON-моделей** (спасибо Pydantic).
* Интеграцию **GraphQL** с <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> и другими библиотеками.
@@ -530,11 +524,11 @@ FastAPI зависит от Pydantic и 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="преобразование строки, полученной из HTTP-запроса, в данные Python">«парсинг»</abbr> форм через `request.form()`.
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> обязателен, если вы хотите поддерживать <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">«парсинг»</abbr> форм через `request.form()`.
Используется FastAPI:
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> — сервер, который загружает и «отдаёт» ваше приложение. Включает `uvicorn[standard]`, содержащий некоторые зависимости (например, `uvloop`), нужные для высокой производительности.
* <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>.

View File

@@ -1,4 +1,4 @@
# Большие приложения — несколько файлов { #bigger-applications-multiple-files }
# Большие приложения, в которых много файлов { #bigger-applications-multiple-files }
При построении приложения или веб-API нам редко удается поместить всё в один файл.
@@ -31,7 +31,7 @@
/// tip | Подсказка
Есть несколько файлов `__init__.py`: по одному в каждом каталоге или подкаталоге.
Обратите внимание, что в каждом каталоге и подкаталоге имеется файл `__init__.py`
Это как раз то, что позволяет импортировать код из одного файла в другой.
@@ -43,63 +43,61 @@ from app.routers import items
///
* Всё помещается в каталоге `app`. В нём также находится пустой файл `app/__init__.py`. Таким образом, `app` является "Python-пакетом" (коллекцией "Python-модулей"): `app`.
* Он содержит файл `app/main.py`. Данный файл является частью Python-пакета (т.е. находится внутри каталога, содержащего файл `__init__.py`), и, соответственно, он является модулем этого пакета: `app.main`.
* Всё помещается в каталоге `app`. В нём также находится пустой файл `app/__init__.py`. Таким образом, `app` является "Python-пакетом" (коллекцией модулей Python).
* Он содержит файл `app/main.py`. Данный файл является частью пакета (т.е. находится внутри каталога, содержащего файл `__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`.
* Здесь также находится подкаталог `app/routers/`, содержащий `__init__.py`. Он является суб-пакетом: `app.routers`.
* Файл `app/routers/items.py` находится внутри пакета `app/routers/`. Таким образом, он является суб-модулем: `app.routers.items`.
* Точно также `app/routers/users.py` является ещё одним суб-модулем: `app.routers.users`.
* Подкаталог `app/internal/`, содержащий файл `__init__.py`, является ещё одним суб-пакетом: `app.internal`.
* А файл `app/internal/admin.py` является ещё одним суб-модулем: `app.internal.admin`.
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
Та же самая файловая структура приложения, но с комментариями:
```bash
```
.
├── app # "app" пакет
│   ├── __init__.py # этот файл превращает "app" в "Python-пакет"
│   ├── main.py # модуль "main", напр.: import app.main
│   ├── dependencies.py # модуль "dependencies", напр.: import app.dependencies
│   └── routers # подпакет "routers"
│   │ ├── __init__.py # превращает "routers" в подпакет
│   │ ├── items.py # подмодуль "items", напр.: import app.routers.items
│   │ └── users.py # подмодуль "users", напр.: import app.routers.users
│   └── internal # подпакет "internal"
│   ├── __init__.py # превращает "internal" в подпакет
│   └── admin.py # подмодуль "admin", напр.: import app.internal.admin
│   └── routers # суб-пакет "routers"
│   │ ├── __init__.py # превращает "routers" в суб-пакет
│   │ ├── items.py # суб-модуль "items", напр.: import app.routers.items
│   │ └── users.py # суб-модуль "users", напр.: import app.routers.users
│   └── internal # суб-пакет "internal"
│   ├── __init__.py # превращает "internal" в суб-пакет
│   └── admin.py # суб-модуль "admin", напр.: import app.internal.admin
```
## `APIRouter` { #apirouter }
Давайте предположим, что для работы с пользователями используется отдельный файл (подмодуль) `/app/routers/users.py`.
Давайте предположим, что для работы с пользователями используется отдельный файл (суб-модуль) `/app/routers/users.py`.
Вы хотите отделить *операции пути*, связанные с пользователями, от остального кода, чтобы сохранить порядок.
Для лучшей организации приложения, вы хотите отделить операции пути, связанные с пользователями, от остального кода.
Но это всё равно часть того же приложения/веб-API на **FastAPI** (часть того же «Python-пакета»).
Но так, чтобы эти операции по-прежнему оставались частью **FastAPI** приложения/веб-API (частью одного пакета)
С помощью `APIRouter` вы можете создать *операции пути* для этого модуля.
С помощью `APIRouter` вы можете создать *операции пути* (*эндпоинты*) для данного модуля.
### Импорт `APIRouter` { #import-apirouter }
Точно так же, как и в случае с классом `FastAPI`, вам нужно импортировать и создать его «экземпляр»:
Точно также, как и в случае с классом `FastAPI`, вам нужно импортировать и создать объект класса `APIRouter`.
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
### *Операции пути* с `APIRouter` { #path-operations-with-apirouter }
### Создание *эндпоинтов* с помощью `APIRouter` { #path-operations-with-apirouter }
И затем вы используете его, чтобы объявить ваши *операции пути*.
Используйте его так же, как вы использовали бы класс `FastAPI`:
В дальнейшем используйте `APIRouter` для объявления *эндпоинтов*, точно также, как вы используете класс `FastAPI`:
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
Вы можете думать об `APIRouter` как об «мини-классе `FastAPI`».
Вы можете думать об `APIRouter` как об "уменьшенной версии" класса FastAPI`.
Поддерживаются все те же опции.
`APIRouter` поддерживает все те же самые опции.
Все те же `parameters`, `responses`, `dependencies`, `tags` и т.д.
`APIRouter` поддерживает все те же самые параметры, такие как `parameters`, `responses`, `dependencies`, `tags`, и т. д.
/// tip | Подсказка
@@ -107,21 +105,21 @@ from app.routers import items
///
Мы собираемся подключить данный `APIRouter` к нашему основному приложению на `FastAPI`, но сначала давайте проверим зависимости и ещё один `APIRouter`.
Мы собираемся подключить данный `APIRouter` к нашему основному приложению на `FastAPI`, но сначала давайте проверим зависимости и создадим ещё один модуль с `APIRouter`.
## Зависимости { #dependencies }
Мы видим, что нам понадобятся некоторые зависимости, которые будут использоваться в нескольких местах приложения.
Нам понадобятся некоторые зависимости, которые мы будем использовать в разных местах нашего приложения.
Поэтому мы поместим их в отдельный модуль `dependencies` (`app/dependencies.py`).
Мы поместим их в отдельный модуль `dependencies` (`app/dependencies.py`).
Теперь мы воспользуемся простой зависимостью, чтобы прочитать кастомный HTTP-заголовок `X-Token`:
Теперь мы воспользуемся простой зависимостью, чтобы прочитать кастомизированный `X-Token` из заголовка:
{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
/// tip | Подсказка
Для простоты мы воспользовались выдуманным заголовком.
Для простоты мы воспользовались неким воображаемым заголовоком.
В реальных случаях для получения наилучших результатов используйте интегрированные [утилиты безопасности](security/index.md){.internal-link target=_blank}.
@@ -129,29 +127,30 @@ from app.routers import items
## Ещё один модуль с `APIRouter` { #another-module-with-apirouter }
Давайте также предположим, что у вас есть эндпоинты, отвечающие за обработку «items» в вашем приложении, и они находятся в модуле `app/routers/items.py`.
Давайте также предположим, что у вас есть *эндпоинты*, отвечающие за обработку "items", и они находятся в модуле `app/routers/items.py`.
У вас определены *операции пути* для:
У вас определены следующие *операции пути* (*эндпоинты*):
* `/items/`
* `/items/{item_id}`
Тут всё та же структура, как и в случае с `app/routers/users.py`.
Тут всё точно также, как и в ситуации с `app/routers/users.py`.
Но мы хотим поступить умнее и слегка упростить код.
Но теперь мы хотим поступить немного умнее и слегка упростить код.
Мы знаем, что все *операции пути* этого модуля имеют одинаковые:
Мы знаем, что все *эндпоинты* данного модуля имеют некоторые общие свойства:
* `prefix` пути: `/items`.
* `tags`: (один единственный тег: `items`).
* Дополнительные `responses`.
* `dependencies`: всем им нужна та зависимость `X-Token`, которую мы создали.
* Префикс пути: `/items`.
* Теги: (один единственный тег: `items`).
* Дополнительные ответы (responses)
* Зависимости: использование созданной нами зависимости `X-token`
Таким образом, вместо того чтобы добавлять всё это в каждую *операцию пути*, мы можем добавить это в `APIRouter`.
Таким образом, вместо того чтобы добавлять все эти свойства в функцию каждого отдельного *эндпоинта*,
мы добавим их в `APIRouter`.
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
Так как путь каждой *операции пути* должен начинаться с `/`, как здесь:
Так как каждый *эндпоинт* начинается с символа `/`:
```Python hl_lines="1"
@router.get("/{item_id}")
@@ -163,74 +162,73 @@ async def read_item(item_id: str):
В нашем случае префиксом является `/items`.
Мы также можем добавить список `tags` и дополнительные `responses`, которые будут применяться ко всем *операциям пути*, включённым в этот маршрутизатор.
Мы также можем добавить в наш маршрутизатор (router) список `тегов` (`tags`) и дополнительных `ответов` (`responses`), которые являются общими для каждого *эндпоинта*.
И ещё мы можем добавить список `dependencies`, которые будут добавлены ко всем *операциям пути* в маршрутизаторе и будут выполняться/разрешаться для каждого HTTP-запроса к ним.
И ещё мы можем добавить в наш маршрутизатор список `зависимостей`, которые должны вызываться при каждом обращении к *эндпоинтам*.
/// tip | Подсказка
Обратите внимание, что так же, как и в случае с [зависимостями в декораторах *операций пути*](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, никакое значение не будет передано в вашу *функцию-обработчик пути*.
Обратите внимание, что также, как и в случае с зависимостями в декораторах *эндпоинтов* ([зависимости в декораторах операций пути](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), никакого значения в *функцию эндпоинта* передано не будет.
///
В результате пути для items теперь такие:
В результате мы получим следующие эндпоинты:
* `/items/`
* `/items/{item_id}`
...как мы и планировали.
* Они будут помечены списком тегов, содержащим одну строку `"items"`.
* Эти «теги» особенно полезны для систем автоматической интерактивной документации (с использованием OpenAPI).
* Все они будут включать предопределённые `responses`.
* Все эти *операции пути* будут иметь список `dependencies`, вычисляемых/выполняемых перед ними.
* Если вы также объявите зависимости в конкретной *операции пути*, **они тоже будут выполнены**.
* Сначала выполняются зависимости маршрутизатора, затем [`dependencies` в декораторе](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, и затем обычные параметрические зависимости.
* Вы также можете добавить [`Security`-зависимости с `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
* Они будут помечены тегами из заданного списка, в нашем случае это `"items"`.
* Эти теги особенно полезны для системы автоматической интерактивной документации (с использованием OpenAPI).
* Каждый из них будет включать предопределенные ответы `responses`.
* Каждый *эндпоинт* будет иметь список зависимостей (`dependencies`), исполняемых перед вызовом *эндпоинта*.
* Если вы определили зависимости в самой операции пути, **то она также будет выполнена**.
* Сначала выполняются зависимости маршрутизатора, затем вызываются [зависимости в декораторе](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, и, наконец, обычные параметрические зависимости.
* Вы также можете добавить [зависимости `Security` с `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
/// tip | Подсказка
Например, с помощью зависимостей в `APIRouter` мы можем потребовать аутентификации для доступа ко всей группе *операций пути*. Даже если зависимости не добавляются по отдельности к каждой из них.
Например, с помощью зависимостей в `APIRouter` мы можем потребовать аутентификации для доступа ко всей группе *эндпоинтов*, не указывая зависимости для каждой отдельной функции *эндпоинта*.
///
/// check | Заметка
Параметры `prefix`, `tags`, `responses` и `dependencies` — это (как и во многих других случаях) просто возможность **FastAPI**, помогающая избежать дублирования кода.
Параметры `prefix`, `tags`, `responses` и `dependencies` относятся к функционалу **FastAPI**, помогающему избежать дублирования кода.
///
### Импорт зависимостей { #import-the-dependencies }
Этот код находится в модуле `app.routers.items`, в файле `app/routers/items.py`.
Наш код находится в модуле `app.routers.items` (файл `app/routers/items.py`).
И нам нужно получить функцию зависимости из модуля `app.dependencies`, файла `app/dependencies.py`.
И нам нужно вызвать функцию зависимости из модуля `app.dependencies` (файл `app/dependencies.py`).
Поэтому мы используем относительный импорт с `..` для зависимостей:
Мы используем операцию относительного импорта `..` для импорта зависимости:
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *}
#### Как работает относительный импорт { #how-relative-imports-work }
#### Как работает относительный импорт? { #how-relative-imports-work }
/// tip | Подсказка
Если вы прекрасно знаете, как работает импорт, переходите к следующему разделу ниже.
Если вы прекрасно знаете, как работает импорт в Python, то переходите к следующему разделу.
///
Одна точка `.`, как здесь:
Одна точка `.`, как в данном примере:
```Python
from .dependencies import get_token_header
```
означает:
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
* найти модуль `dependencies` (воображаемый файл `app/routers/dependencies.py`)...
* и импортировать из него функцию `get_token_header`.
* Начните с пакета, в котором находится данный модуль (файл `app/routers/items.py` расположен в каталоге `app/routers/`)...
* ... найдите модуль `dependencies` (файл `app/routers/dependencies.py`)...
* ... и импортируйте из него функцию `get_token_header`.
Но такого файла не существует, наши зависимости находятся в файле `app/dependencies.py`.
К сожалению, такого файла не существует, и наши зависимости находятся в файле `app/dependencies.py`.
Вспомните, как выглядит файловая структура нашего приложения:
@@ -238,7 +236,7 @@ from .dependencies import get_token_header
---
Две точки `..`, как здесь:
Две точки `..`, как в данном примере:
```Python
from ..dependencies import get_token_header
@@ -246,12 +244,12 @@ from ..dependencies import get_token_header
означают:
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
* перейти в родительский пакет (каталог `app/`)...
* и там найти модуль `dependencies` (файл `app/dependencies.py`)...
* и импортировать из него функцию `get_token_header`.
* Начните с пакета, в котором находится данный модуль (файл `app/routers/items.py` находится в каталоге `app/routers/`)...
* ... перейдите в родительский пакет (каталог `app/`)...
* ... найдите в нём модуль `dependencies` (файл `app/dependencies.py`)...
* ... и импортируйте из него функцию `get_token_header`.
Это работает корректно! 🎉
Это работает верно! 🎉
---
@@ -263,29 +261,29 @@ from ...dependencies import get_token_header
то это бы означало:
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) расположен в (каталоге `app/routers/`)...
* перейти в родительский пакет (каталог `app/`)...
* затем перейти в родительский пакет этого пакета (родительского пакета нет, `app` верхний уровень 😱)...
* и там найти модуль `dependencies` (файл `app/dependencies.py`)...
* и импортировать из него функцию `get_token_header`.
* Начните с пакета, в котором находится данный модуль (файл `app/routers/items.py` находится в каталоге `app/routers/`)...
* ... перейдите в родительский пакет (каталог `app/`)...
* ... затем перейдите в родительский пакет текущего пакета (такого пакета не существует, `app` находится на самом верхнем уровне 😱)...
* ... найдите в нём модуль `dependencies` (файл `app/dependencies.py`)...
* ... и импортируйте из него функцию `get_token_header`.
Это ссылалось бы на какой-то пакет выше `app/`, со своим файлом `__init__.py` и т.п. Но у нас такого нет. Поэтому это вызвало бы ошибку в нашем примере. 🚨
Это будет относиться к некоторому пакету, находящемуся на один уровень выше чем `app/` и содержащему свой собственный файл `__init__.py`. Но ничего такого у нас нет. Поэтому это приведет к ошибке в нашем примере. 🚨
Но теперь вы знаете, как это работает, так что можете использовать относительные импорты в своих приложениях, независимо от того, насколько они сложные. 🤓
Теперь вы знаете, как работает импорт в Python, и сможете использовать относительное импортирование в своих собственных приложениях любого уровня сложности. 🤓
### Добавление пользовательских `tags`, `responses` и `dependencies` { #add-some-custom-tags-responses-and-dependencies }
### Добавление пользовательских тегов (`tags`), ответов (`responses`) и зависимостей (`dependencies`) { #add-some-custom-tags-responses-and-dependencies }
Мы не добавляем префикс `/items` и `tags=["items"]` к каждой *операции пути*, потому что мы добавили их в `APIRouter`.
Мы не будем добавлять префикс `/items` и список тегов `tags=["items"]` для каждого *эндпоинта*, т.к. мы уже их добавили с помощью `APIRouter`.
Но мы всё равно можем добавить _ещё_ `tags`, которые будут применяться к конкретной *операции пути*, а также дополнительные `responses`, специфичные для этой *операции пути*:
Но помимо этого мы можем добавить новые теги для каждого отдельного *эндпоинта*, а также некоторые дополнительные ответы (`responses`), характерные для данного *эндпоинта*:
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *}
/// tip | Подсказка
Эта последняя операция пути будет иметь комбинацию тегов: `["items", "custom"]`.
Последний *эндпоинт* будет иметь следующую комбинацию тегов: `["items", "custom"]`.
И в документации у неё будут оба ответа: один для `404` и один для `403`.
А также в его документации будут содержаться оба ответа: один для `404` и другой для `403`.
///
@@ -295,29 +293,29 @@ from ...dependencies import get_token_header
Именно сюда вы импортируете и именно здесь вы используете класс `FastAPI`.
Это основной файл вашего приложения, который связывает всё воедино.
Это основной файл вашего приложения, который объединяет всё в одно целое.
И так как большая часть вашей логики теперь будет находиться в отдельных специфичных модулях, основной файл будет довольно простым.
И теперь, когда большая часть логики приложения разделена на отдельные модули, основной файл `app/main.py` будет достаточно простым.
### Импорт `FastAPI` { #import-fastapi }
Вы импортируете и создаёте класс `FastAPI` как обычно.
Вы импортируете и создаете класс `FastAPI` как обычно.
И мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого `APIRouter`:
Мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого отдельного маршрутизатора:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *}
### Импорт `APIRouter` { #import-the-apirouter }
Теперь мы импортируем другие подмодули, содержащие `APIRouter`:
Теперь мы импортируем другие суб-модули, содержащие `APIRouter`:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *}
Так как файлы `app/routers/users.py` и `app/routers/items.py` являются подмодулями, входящими в один и тот же Python-пакет `app`, мы можем использовать одну точку `.` для импорта через «относительные импорты».
Так как файлы `app/routers/users.py` и `app/routers/items.py` являются суб-модулями одного и того же Python-пакета `app`, то мы сможем их импортировать, воспользовавшись операцией относительного импорта `.`.
### Как работает импорт { #how-the-importing-works }
### Как работает импорт? { #how-the-importing-works }
Этот фрагмент:
Данная строка кода:
```Python
from .routers import items, users
@@ -325,15 +323,15 @@ from .routers import items, users
означает:
* Начать в том же пакете, в котором находится этот модуль (файл `app/main.py`) расположен в (каталоге `app/`)...
* найти подпакет `routers` (каталог `app/routers/`)...
* и импортировать из него подмодули `items` (файл `app/routers/items.py`) и `users` (файл `app/routers/users.py`)...
* Начните с пакета, в котором содержится данный модуль (файл `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`.
В модуле `items` содержится переменная `router` (`items.router`), та самая, которую мы создали в файле `app/routers/items.py`, она является объектом класса `APIRouter`.
И затем мы делаем то же самое для модуля `users`.
И затем мы сделаем то же самое для модуля `users`.
Мы также могли бы импортировать их так:
Мы также могли бы импортировать и другим методом:
```Python
from app.routers import items, users
@@ -341,44 +339,44 @@ from app.routers import items, users
/// info | Примечание
Первая версия — это «относительный импорт»:
Первая версия является примером относительного импорта:
```Python
from .routers import items, users
```
Вторая версия — это «абсолютный импорт»:
Вторая версия является примером абсолютного импорта:
```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>.
Узнать больше о пакетах и модулях в Python вы можете из <a href="https://docs.python.org/3/tutorial/modules.html" class="external-link" target="_blank">официальной документации Python о модулях</a>
///
### Избегайте конфликтов имён { #avoid-name-collisions }
### Избегайте конфликтов имен { #avoid-name-collisions }
Мы импортируем подмодуль `items` напрямую, вместо того чтобы импортировать только его переменную `router`.
Вместо того чтобы импортировать только переменную `router`, мы импортируем непосредственно суб-модуль `items`.
Это потому, что у нас также есть другая переменная с именем `router` в подмодуле `users`.
Мы делаем это потому, что у нас есть ещё одна переменная `router` в суб-модуле `users`.
Если бы мы импортировали их одну за другой, как здесь:
Если бы мы импортировали их одну за другой, как показано в примере:
```Python
from .routers.items import router
from .routers.users import router
```
то `router` из `users` перезаписал бы `router` из `items`, и мы не смогли бы использовать их одновременно.
то переменная `router` из `users` переписал бы переменную `router` из `items`, и у нас не было бы возможности использовать их одновременно.
Поэтому, чтобы иметь возможность использовать обе в одном файле, мы импортируем подмодули напрямую:
Поэтому, для того чтобы использовать обе эти переменные в одном файле, мы импортировали соответствующие суб-модули:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
### Подключение `APIRouter` для `users` и `items` { #include-the-apirouters-for-users-and-items }
### Подключение маршрутизаторов (`APIRouter`) для `users` и для `items` { #include-the-apirouters-for-users-and-items }
Теперь давайте подключим `router` из подмодулей `users` и `items`:
Давайте подключим маршрутизаторы (`router`) из суб-модулей `users` и `items`:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *}
@@ -390,78 +388,79 @@ from .routers.users import router
///
С помощью `app.include_router()` мы можем добавить каждый `APIRouter` в основное приложение `FastAPI`.
С помощью `app.include_router()` мы можем добавить каждый из маршрутизаторов (`APIRouter`) в основное приложение `FastAPI`.
Он включит все маршруты этого маршрутизатора как часть приложения.
Он подключит все маршруты заданного маршрутизатора к нашему приложению.
/// note | Технические детали
Фактически, внутри он создаст *операцию пути* для каждой *операции пути*, объявленной в `APIRouter`.
Фактически, внутри он создаст все *операции пути* для каждой операции пути объявленной в `APIRouter`.
Так что под капотом всё будет работать так, как будто всё было одним приложением.
И под капотом всё будет работать так, как будто бы мы имеем дело с одним файлом приложения.
///
/// check | Заметка
При подключении маршрутизаторов не нужно беспокоиться о производительности.
При подключении маршрутизаторов не стоит беспокоиться о производительности.
Это займёт микросекунды и произойдёт только при старте.
Операция подключения займёт микросекунды и понадобится только при запуске приложения.
Так что это не повлияет на производительность. ⚡
Таким образом, это не повлияет на производительность. ⚡
///
### Подключение `APIRouter` с пользовательскими `prefix`, `tags`, `responses` и `dependencies` { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
### Подключение `APIRouter` с пользовательскими префиксом (`prefix`), тегами (`tags`), ответами (`responses`), и зависимостями (`dependencies`) { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
Теперь давайте представим, что ваша организация передала вам файл `app/internal/admin.py`.
Он содержит `APIRouter` с некоторыми административными *операциями пути*, которые ваша организация использует в нескольких проектах.
Он содержит `APIRouter` с некоторыми *эндпоитами* администрирования, которые ваша организация использует для нескольких проектов.
Для этого примера всё будет очень просто. Но допустим, что поскольку он используется совместно с другими проектами в организации, мы не можем модифицировать его и добавить `prefix`, `dependencies`, `tags` и т.д. непосредственно в `APIRouter`:
В данном примере это сделать очень просто. Но давайте предположим, что поскольку файл используется для нескольких проектов,
то мы не можем модифицировать его, добавляя префиксы (`prefix`), зависимости (`dependencies`), теги (`tags`), и т.д. непосредственно в `APIRouter`:
{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
Но мы всё равно хотим задать пользовательский `prefix` при подключении `APIRouter`, чтобы все его *операции пути* начинались с `/admin`, хотим защитить его с помощью `dependencies`, которые у нас уже есть для этого проекта, и хотим включить `tags` и `responses`.
Но, несмотря на это, мы хотим использовать кастомный префикс (`prefix`) для подключенного маршрутизатора (`APIRouter`), в результате чего, каждая *операция пути* будет начинаться с `/admin`. Также мы хотим защитить наш маршрутизатор с помощью зависимостей, созданных для нашего проекта. И ещё мы хотим включить теги (`tags`) и ответы (`responses`).
Мы можем объявить всё это, не изменяя исходный `APIRouter`, передав эти параметры в `app.include_router()`:
Мы можем применить все вышеперечисленные настройки, не изменяя начальный `APIRouter`. Нам всего лишь нужно передать нужные параметры в `app.include_router()`.
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *}
Таким образом исходный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации.
Таким образом, оригинальный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации.
В результате в нашем приложении каждая из *операций пути* из модуля `admin` будет иметь:
В результате, в нашем приложении каждый *эндпоинт* модуля `admin` будет иметь:
* Префикс `/admin`.
* Тег `admin`.
* Зависимость `get_token_header`.
* Ответ `418`. 🍵
Но это повлияет только на этот `APIRouter` в нашем приложении, а не на любой другой код, который его использует.
Это будет иметь место исключительно для `APIRouter` в нашем приложении, и не затронет любой другой код, использующий его.
Так что, например, другие проекты могут использовать тот же `APIRouter` с другим методом аутентификации.
Например, другие проекты, могут использовать тот же самый `APIRouter` с другими методами аутентификации.
### Подключение *операции пути* { #include-a-path-operation }
### Подключение отдельного *эндпоинта* { #include-a-path-operation }
Мы также можем добавлять *операции пути* напрямую в приложение `FastAPI`.
Мы также можем добавить *эндпоинт* непосредственно в основное приложение `FastAPI`.
Здесь мы делаем это... просто чтобы показать, что можем 🤷:
Здесь мы это делаем ... просто, чтобы показать, что это возможно 🤷:
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *}
и это будет работать корректно вместе со всеми другими *операциями пути*, добавленными через `app.include_router()`.
и это будет работать корректно вместе с другими *эндпоинтами*, добавленными с помощью `app.include_router()`.
/// info | Очень технические детали
/// info | Сложные технические детали
**Примечание**: это очень техническая деталь, которую, вероятно, можно **просто пропустить**.
**Примечание**: это сложная техническая деталь, которую, скорее всего, **вы можете пропустить**.
---
`APIRouter` не «монтируются», они не изолированы от остального приложения.
Маршрутизаторы (`APIRouter`) не "монтируются" по-отдельности и не изолируются от остального приложения.
Это потому, что мы хотим включить их *операции пути* в OpenAPI-схему и пользовательские интерфейсы.
Это происходит потому, что нужно включить их *эндпоинты* в OpenAPI схему и в интерфейс пользователя.
Так как мы не можем просто изолировать их и «смонтировать» независимо от остального, *операции пути* «клонируются» (пересоздаются), а не включаются напрямую.
В силу того, что мы не можем их изолировать и "примонтировать" независимо от остальных, *эндпоинты* клонируются (пересоздаются) и не подключаются напрямую.
///
@@ -481,24 +480,24 @@ $ fastapi dev app/main.py
Откройте документацию по адресу <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Вы увидите автоматическую документацию API, включая пути из всех подмодулей, с использованием корректных путей (и префиксов) и корректных тегов:
Вы увидите автоматическую API документацию. Она включает в себя маршруты из суб-модулей, используя верные маршруты, префиксы и теги:
<img src="/img/tutorial/bigger-applications/image01.png">
## Подключение одного и того же маршрутизатора несколько раз с разными `prefix` { #include-the-same-router-multiple-times-with-different-prefix }
## Подключение существующего маршрута через новый префикс (`prefix`) { #include-the-same-router-multiple-times-with-different-prefix }
Вы можете использовать `.include_router()` несколько раз с *одним и тем же* маршрутизатором, используя разные префиксы.
Вы можете использовать `.include_router()` несколько раз с одним и тем же маршрутом, применив различные префиксы.
Это может быть полезно, например, чтобы предоставить доступ к одному и тому же API с разными префиксами, например `/api/v1` и `/api/latest`.
Это может быть полезным, если нужно предоставить доступ к одному и тому же API через различные префиксы, например, `/api/v1` и `/api/latest`.
Это продвинутое использование, которое вам может и не понадобиться, но оно есть на случай, если понадобится.
Это продвинутый способ, который вам может и не пригодится. Мы приводим его на случай, если вдруг вам это понадобится.
## Подключение `APIRouter` в другой `APIRouter` { #include-an-apirouter-in-another }
## Включение одного маршрутизатора (`APIRouter`) в другой { #include-an-apirouter-in-another }
Точно так же, как вы можете подключить `APIRouter` к приложению `FastAPI`, вы можете подключить `APIRouter` к другому `APIRouter`, используя:
Точно так же, как вы включаете `APIRouter` в приложение `FastAPI`, вы можете включить `APIRouter` в другой `APIRouter`:
```Python
router.include_router(other_router)
```
Убедитесь, что вы сделали это до подключения `router` к приложению `FastAPI`, чтобы *операции пути* из `other_router` также были подключены.
Удостоверьтесь, что вы сделали это до того, как подключить маршрутизатор (`router`) к вашему `FastAPI` приложению, и *эндпоинты* маршрутизатора `other_router` были также подключены.

View File

@@ -2,13 +2,13 @@
## Обновление с заменой при помощи `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>.
Для полного обновления элемента можно воспользоваться операцией <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`.
{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
`PUT` используется для получения данных, которые должны заменить существующие данные.
`PUT` используется для получения данных, которые должны полностью заменить существующие данные.
### Предупреждение о замене { #warning-about-replacing }
@@ -24,11 +24,11 @@
поскольку оно не включает уже сохраненный атрибут `"tax": 20.2`, входная модель примет значение по умолчанию `"tax": 10.5`.
И данные будут сохранены с этим «новым» `tax`, равным `10.5`.
И данные будут сохранены с этим "новым" `tax`, равным `10,5`.
## Частичное обновление с помощью `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> для *частичного* обновления данных.
Также можно использовать <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> операцию для *частичного* обновления данных.
Это означает, что можно передавать только те данные, которые необходимо обновить, оставляя остальные нетронутыми.
@@ -46,13 +46,19 @@
### Использование параметра `exclude_unset` в Pydantic { #using-pydantics-exclude-unset-parameter }
Если вы хотите получать частичные обновления, очень полезно использовать параметр `exclude_unset` в `.model_dump()` модели Pydantic.
Если необходимо выполнить частичное обновление, то очень полезно использовать параметр `exclude_unset` в методе `.model_dump()` модели Pydantic.
Например, `item.model_dump(exclude_unset=True)`.
В результате будет сгенерирован `dict`, содержащий только те данные, которые были заданы при создании модели `item`, без учета значений по умолчанию.
/// info | Информация
Затем вы можете использовать это для создания `dict` только с теми данными, которые были установлены (отправлены в запросе), опуская значения по умолчанию:
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он помечен как устаревший (но все еще поддерживается) и переименован в `.model_dump()`.
Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, лучше используйте `.model_dump()`.
///
В результате будет сгенерирован словарь, содержащий только те данные, которые были заданы при создании модели `item`, без учета значений по умолчанию. Затем вы можете использовать это для создания словаря только с теми данными, которые были установлены (отправлены в запросе), опуская значения по умолчанию:
{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
@@ -60,6 +66,14 @@
Теперь можно создать копию существующей модели, используя `.model_copy()`, и передать параметр `update` с `dict`, содержащим данные для обновления.
/// info | Информация
В Pydantic v1 метод назывался `.copy()`, в Pydantic v2 он помечен как устаревший (но все еще поддерживается) и переименован в `.model_copy()`.
Примеры здесь используют `.copy()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, лучше используйте `.model_copy()`.
///
Например, `stored_item_model.model_copy(update=update_data)`:
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
@@ -70,9 +84,9 @@
* (Опционально) использовать `PATCH` вместо `PUT`.
* Извлечь сохранённые данные.
* Поместить эти данные в Pydantic-модель.
* Поместить эти данные в Pydantic модель.
* Сгенерировать `dict` без значений по умолчанию из входной модели (с использованием `exclude_unset`).
* Таким образом, можно обновлять только те значения, которые действительно установлены пользователем, вместо того чтобы переопределять уже сохраненные значения значениями по умолчанию из вашей модели.
* Таким образом, можно обновлять только те значения, которые действительно установлены пользователем, вместо того чтобы переопределять значения, уже сохраненные в модели по умолчанию.
* Создать копию хранимой модели, обновив ее атрибуты полученными частичными обновлениями (с помощью параметра `update`).
* Преобразовать скопированную модель в то, что может быть сохранено в вашей БД (например, с помощью `jsonable_encoder`).
* Это сравнимо с повторным использованием метода модели `.model_dump()`, но при этом происходит проверка (и преобразование) значений в типы данных, которые могут быть преобразованы в JSON, например, `datetime` в `str`.
@@ -83,7 +97,7 @@
/// tip | Подсказка
На самом деле эту же технику можно использовать и для операции HTTP `PUT`.
Эту же технику можно использовать и для операции HTTP `PUT`.
Но в приведенном примере используется `PATCH`, поскольку он был создан именно для таких случаев использования.

View File

@@ -32,10 +32,9 @@
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
Так же, как при объявлении параметров запроса: когда атрибут модели имеет значение по умолчанию, он не обязателен. Иначе он обязателен. Используйте `None`, чтобы сделать его просто необязательным.
Например, модель выше описывает такой JSON "`object`" (или Python `dict`):
Например, модель выше описывает такой JSON "объект" (или Python `dict`):
```JSON
{
@@ -46,7 +45,7 @@
}
```
...так как `description` и `tax` являются необязательными (со значением по умолчанию `None`), такой JSON "`object`" тоже будет корректным:
...так как `description` и `tax` являются необязательными (со значением по умолчанию `None`), такой JSON "объект" тоже будет корректным:
```JSON
{
@@ -74,7 +73,7 @@
* Передаст полученные данные в параметр `item`.
* Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т. п.) для всех атрибутов и их типов.
* Сгенерирует определения <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> для вашей модели; вы можете использовать их и в других местах, если это имеет смысл для вашего проекта.
* Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией <abbr title="User Interfaces - Пользовательские интерфейсы">UIs</abbr>.
* Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией <abbr title="User Interfaces Пользовательские интерфейсы">UIs</abbr>.
## Автоматическая документация { #automatic-docs }
@@ -128,6 +127,14 @@ JSON Schema ваших моделей будет частью сгенериро
{* ../../docs_src/body/tutorial002_py310.py *}
/// info | Информация
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, используйте `.model_dump()`.
///
## Тело запроса + параметры пути { #request-body-path-parameters }
Вы можете одновременно объявить параметры пути и тело запроса.
@@ -136,7 +143,6 @@ JSON Schema ваших моделей будет частью сгенериро
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
## Тело запроса + параметры пути + параметры запроса { #request-body-path-query-parameters }
Вы также можете одновременно объявить параметры **тела**, **пути** и **запроса**.
@@ -147,7 +153,7 @@ JSON Schema ваших моделей будет частью сгенериро
Параметры функции будут распознаны следующим образом:
* Если параметр также объявлен в **пути**, он будет использоваться как path-параметр.
* Если параметр также объявлен в **пути**, он будет использоваться как параметр пути.
* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т. п.), он будет интерпретирован как параметр **запроса**.
* Если параметр объявлен как тип **модели Pydantic**, он будет интерпретирован как **тело** запроса.
@@ -155,7 +161,7 @@ JSON Schema ваших моделей будет частью сгенериро
FastAPI понимает, что значение `q` не является обязательным из-за значения по умолчанию `= None`.
Аннотации типов `str | None` (Python 3.10+) или `Union` в `Union[str, None]` (Python 3.9+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
Аннотации типов `str | None` (Python 3.10+) или `Union[str, None]` (Python 3.9+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
Но добавление аннотаций типов позволит вашему редактору кода лучше вас поддерживать и обнаруживать ошибки.
@@ -163,4 +169,4 @@ FastAPI понимает, что значение `q` не является об
## Без Pydantic { #without-pydantic }
Если вы не хотите использовать модели Pydantic, вы также можете использовать параметры **Body**. См. раздел документации [Тело запроса - Несколько параметров: Единичные значения в теле](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
Если вы не хотите использовать модели Pydantic, вы также можете использовать параметры **Body**. См. раздел документации [Тело Несколько параметров: Единичные значения в теле](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.

View File

@@ -22,13 +22,21 @@
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
### Про `**user_in.model_dump()` { #about-user-in-model-dump }
/// info | Информация
#### `.model_dump()` из Pydantic { #pydantics-model-dump }
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
`user_in` — это Pydantic-модель класса `UserIn`.
В примерах здесь используется `.dict()` для совместимости с Pydantic v1, но если вы используете Pydantic v2, следует использовать `.model_dump()`.
У Pydantic-моделей есть метод `.model_dump()`, который возвращает `dict` с данными модели.
///
### Про `**user_in.dict()` { #about-user-in-dict }
#### `.dict()` из Pydantic { #pydantics-dict }
`user_in` - это Pydantic-модель класса `UserIn`.
У Pydantic-моделей есть метод `.dict()`, который возвращает `dict` с данными модели.
Поэтому, если мы создадим Pydantic-объект `user_in` таким способом:
@@ -39,10 +47,10 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
и затем вызовем:
```Python
user_dict = user_in.model_dump()
user_dict = user_in.dict()
```
то теперь у нас есть `dict` с данными в переменной `user_dict` (это `dict` вместо объекта Pydantic-модели).
то теперь у нас есть `dict` с данными модели в переменной `user_dict` (это `dict` вместо объекта Pydantic-модели).
И если мы вызовем:
@@ -50,7 +58,7 @@ user_dict = user_in.model_dump()
print(user_dict)
```
мы получим Python `dict` с:
мы можем получить `dict` с такими данными:
```Python
{
@@ -63,7 +71,7 @@ print(user_dict)
#### Распаковка `dict` { #unpacking-a-dict }
Если мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python его "распакует". Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
Если мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python распакует его. Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
Поэтому, продолжая описанный выше пример с `user_dict`, написание такого кода:
@@ -71,7 +79,7 @@ print(user_dict)
UserInDB(**user_dict)
```
будет эквивалентно:
Будет работать так же, как примерно такой код:
```Python
UserInDB(
@@ -82,7 +90,7 @@ UserInDB(
)
```
Или, более точно, если использовать `user_dict` напрямую, с любым содержимым, которое он может иметь в будущем:
Или, если для большей точности мы напрямую используем `user_dict` с любым потенциальным содержимым, то этот пример будет выглядеть так:
```Python
UserInDB(
@@ -93,22 +101,22 @@ UserInDB(
)
```
#### Pydantic-модель из содержимого другой { #a-pydantic-model-from-the-contents-of-another }
#### Pydantic-модель из содержимого другой модели { #a-pydantic-model-from-the-contents-of-another }
Как в примере выше мы получили `user_dict` из `user_in.model_dump()`, этот код:
Как в примере выше мы получили `user_dict` из `user_in.dict()`, этот код:
```Python
user_dict = user_in.model_dump()
user_dict = user_in.dict()
UserInDB(**user_dict)
```
будет равнозначен такому:
```Python
UserInDB(**user_in.model_dump())
UserInDB(**user_in.dict())
```
...потому что `user_in.model_dump()` это `dict`, и затем мы указываем, чтобы Python его "распаковал", когда передаём его в `UserInDB` с префиксом `**`.
...потому что `user_in.dict()` - это `dict`, и затем мы указываем, чтобы Python его "распаковал", когда передаём его в `UserInDB` и ставим перед ним `**`.
Таким образом мы получаем Pydantic-модель на основе данных из другой Pydantic-модели.
@@ -117,10 +125,10 @@ UserInDB(**user_in.model_dump())
И затем, если мы добавим дополнительный именованный аргумент `hashed_password=hashed_password` как здесь:
```Python
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
UserInDB(**user_in.dict(), hashed_password=hashed_password)
```
...то в итоге получится что-то подобное:
... то мы получим что-то подобное:
```Python
UserInDB(
@@ -134,13 +142,13 @@ UserInDB(
/// warning | Предупреждение
Вспомогательные дополнительные функции `fake_password_hasher` и `fake_save_user` используются только для демонстрации возможного потока данных и, конечно, не обеспечивают настоящую безопасность.
Вспомогательные функции `fake_password_hasher` и `fake_save_user` используются только для демонстрации возможного потока данных и, конечно, не обеспечивают настоящую безопасность.
///
## Сократите дублирование { #reduce-duplication }
Сокращение дублирования кода это одна из главных идей **FastAPI**.
Сокращение дублирования кода - это одна из главных идей **FastAPI**.
Поскольку дублирование кода повышает риск появления багов, проблем с безопасностью, проблем десинхронизации кода (когда вы обновляете код в одном месте, но не обновляете в другом), и т.д.
@@ -158,7 +166,7 @@ UserInDB(
## `Union` или `anyOf` { #union-or-anyof }
Вы можете объявить HTTP-ответ как `Union` из двух или более типов. Это означает, что HTTP-ответ может быть любым из них.
Вы можете определить ответ как `Union` из двух или более типов. Это означает, что ответ должен соответствовать одному из них.
Он будет определён в OpenAPI как `anyOf`.
@@ -166,7 +174,7 @@ UserInDB(
/// note | Примечание
При объявлении <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a> сначала указывайте наиболее специфичный тип, затем менее специфичный. В примере ниже более специфичный `PlaneItem` стоит перед `CarItem` в `Union[PlaneItem, CarItem]`.
При объявлении <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a>, сначала указывайте наиболее детальные типы, затем менее детальные. В примере ниже более детальный `PlaneItem` стоит перед `CarItem` в `Union[PlaneItem, CarItem]`.
///
@@ -184,19 +192,19 @@ UserInDB(
some_variable: PlaneItem | CarItem
```
Но если мы поместим это в присваивание `response_model=PlaneItem | CarItem`, мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
Но если мы помещаем его в `response_model=PlaneItem | CarItem` мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
## Список моделей { #list-of-models }
Таким же образом вы можете объявлять HTTP-ответы, возвращающие списки объектов.
Таким же образом вы можете определять ответы как списки объектов.
Для этого используйте стандартный `typing.List` в Python (или просто `list` в Python 3.9 и выше):
Для этого используйте `typing.List` из стандартной библиотеки Python (или просто `list` в Python 3.9 и выше):
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
## Ответ с произвольным `dict` { #response-with-arbitrary-dict }
Вы также можете объявить HTTP-ответ, используя обычный произвольный `dict`, объявив только тип ключей и значений, без использования Pydantic-модели.
Вы также можете определить ответ, используя произвольный одноуровневый `dict` и определяя только типы ключей и значений без использования Pydantic-моделей.
Это полезно, если вы заранее не знаете корректных названий полей/атрибутов (которые будут нужны при использовании Pydantic-модели).
@@ -206,6 +214,6 @@ some_variable: PlaneItem | CarItem
## Резюме { #recap }
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждого случая.
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждой из них.
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояние, включающее `password`, `password_hash` и отсутствие пароля.
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояния с полями `password`, `password_hash` и без пароля.

View File

@@ -8,7 +8,7 @@
Query-параметр `q` имеет тип `str | None`, это означает, что он имеет тип `str`, но также может быть `None`. Значение по умолчанию действительно `None`, поэтому FastAPI будет знать, что он не обязателен.
/// note | Примечание
/// note | Технические детали
FastAPI поймёт, что значение `q` не обязательно, из‑за значения по умолчанию `= None`.
@@ -177,7 +177,7 @@ q: str = Query(default="rick")
**Значение по умолчанию** у **параметра функции** — это **настоящее значение по умолчанию**, что более интуитивно для Python. 😌
Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
Если вы не используете `Annotated`, а применяете **(устаревший) стиль со значением по умолчанию**, то при вызове этой функции без FastAPI в **других местах** вам нужно **помнить** о том, что надо передать аргументы, чтобы всё работало корректно, иначе значения будут не такими, как вы ожидаете (например, вместо `str` будет `QueryInfo` или что-то подобное). И ни редактор, ни Python не будут ругаться при самом вызове функции — ошибка проявится лишь при операциях внутри.
@@ -191,7 +191,7 @@ q: str = Query(default="rick")
## Регулярные выражения { #add-regular-expressions }
Вы можете определить <abbr title="Регулярное выражение (regex, regexp) - это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
Вы можете определить <abbr title="Регулярное выражение (regex, regexp) это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
@@ -205,6 +205,20 @@ q: str = Query(default="rick")
Теперь вы знаете, что когда они понадобятся, вы сможете использовать их в **FastAPI**.
### `regex` из Pydantic v1 вместо `pattern` { #pydantic-v1-regex-instead-of-pattern }
До Pydantic версии 2 и до FastAPI 0.100.0 этот параметр назывался `regex`, а не `pattern`, но сейчас он устарел.
Вы всё ещё можете встретить такой код:
//// tab | Pydantic v1
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
////
Имейте в виду, что это устарело, и код следует обновить на использование нового параметра `pattern`. 🤓
## Значения по умолчанию { #default-values }
Конечно, можно использовать и другие значения по умолчанию, не только `None`.
@@ -265,7 +279,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
http://localhost:8000/items/?q=foo&q=bar
```
вы получите множественные значения *query-параметров* `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции-обработчика пути*, в *параметре функции* `q`.
вы получите множественные значения query-параметра `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
Таким образом, ответ на этот URL будет:
@@ -317,7 +331,7 @@ http://localhost:8000/items/
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
/// note | Примечание
/// note | Технические детали
Имейте в виду, что в этом случае FastAPI не будет проверять содержимое списка.
@@ -331,7 +345,7 @@ http://localhost:8000/items/
Эта информация будет включена в сгенерированную OpenAPI-схему и использована интерфейсами документации и внешними инструментами.
/// note | Примечание
/// note | Технические детали
Помните, что разные инструменты могут иметь разный уровень поддержки OpenAPI.
@@ -401,7 +415,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
///
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="ISBN означает International Standard Book Number - Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="IMDB (Internet Movie Database) - веб‑сайт с информацией о фильмах">IMDB</abbr>:
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="ISBN означает International Standard Book Number Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="IMDB (Internet Movie Database) веб‑сайт с информацией о фильмах">IMDB</abbr>:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
@@ -441,7 +455,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
Затем с `random.choice()` можно получить **случайное значение** из списка — то есть кортеж вида `(id, name)`. Это будет что‑то вроде `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
После этого мы **присваиваем эти два значения** кортежа переменным `id` и `name`.
После этого мы **распаковываем** эти два значения кортежа в переменные `id` и `name`.
Так что, если пользователь не передал ID элемента, он всё равно получит случайную рекомендацию.

View File

@@ -6,11 +6,11 @@
{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
FastAPI будет использовать этот возвращаемый тип, чтобы:
FastAPI будет использовать этот тип ответа для:
* **Валидировать** возвращаемые данные.
* Если данные невалидны (например, отсутствует поле), это означает, что код *вашего* приложения работает некорректно и возвращает не то, что должен. В таком случае будет возвращена ошибка сервера вместо неправильных данных. Так вы и ваши клиенты можете быть уверены, что получите ожидаемые данные и ожидаемую структуру данных.
* Добавить **JSON Schema** для ответа в OpenAPI *операции пути*.
* **Валидации** возвращаемых данных.
* Если данные невалидны (например, отсутствует поле), это означает, что код *вашего* приложения работает некорректно и возвращает не то, что должен. В таком случае будет возвращена ошибка сервера вместо неправильных данных. Так вы и ваши клиенты можете быть уверены, что получите ожидаемые данные и ожидаемую структуру.
* Добавления **JSON Schema** для ответа в OpenAPI *операции пути*.
* Это будет использовано **автоматической документацией**.
* Это также будет использовано инструментами автоматической генерации клиентского кода.
@@ -23,7 +23,7 @@ FastAPI будет использовать этот возвращаемый т
Бывают случаи, когда вам нужно или хочется возвращать данные, которые не в точности соответствуют объявленному типу.
Например, вы можете хотеть **возвращать словарь** или объект из базы данных, но **объявить его как Pydantic-модель**. Тогда Pydantic-модель выполнит документирование данных, валидацию и т.п. для объекта, который вы вернули (например, словаря или объекта из базы данных).
Например, вы можете хотеть **возвращать словарь (dict)** или объект из базы данных, но **объявить его как Pydantic-модель**. Тогда Pydantic-модель выполнит документирование данных, валидацию и т.п. для объекта, который вы вернули (например, словаря или объекта из базы данных).
Если вы добавите аннотацию возвращаемого типа, инструменты и редакторы кода начнут жаловаться (и будут правы), что функция возвращает тип (например, dict), отличный от объявленного (например, Pydantic-модель).
@@ -47,13 +47,13 @@ FastAPI будет использовать этот возвращаемый т
`response_model` принимает тот же тип, что вы бы объявили для поля Pydantic-модели, то есть это может быть одна Pydantic-модель, а может быть, например, `list` Pydantic-моделей, как `List[Item]`.
FastAPI будет использовать этот `response_model` для документирования, валидации данных и т.п., а также для **конвертации и фильтрации выходных данных** к объявленному типу.
FastAPI будет использовать `response_model` для документации, валидации и т. п., а также для **конвертации и фильтрации выходных данных** к объявленному типу.
/// tip | Совет
Если у вас в редакторе кода, mypy и т.п. включены строгие проверки типов, вы можете объявить возвращаемый тип функции как `Any`.
Если у вас в редакторе кода, mypy и т. п. включены строгие проверки типов, вы можете объявить возвращаемый тип функции как `Any`.
Так вы сообщите редактору, что намеренно возвращаете что угодно. Но FastAPI всё равно выполнит документирование, валидацию, фильтрацию данных и т.д. с помощью `response_model`.
Так вы сообщите редактору, что намеренно возвращаете что угодно. Но FastAPI всё равно выполнит документацию данных, валидацию, фильтрацию и т.д. с помощью `response_model`.
///
@@ -61,7 +61,7 @@ FastAPI будет использовать этот `response_model` для д
Если вы объявите и возвращаемый тип, и `response_model`, приоритет будет у `response_model`, именно его использует FastAPI.
Так вы можете добавить корректные аннотации типов к своим функциям, даже если фактически возвращаете тип, отличный от модели ответа, чтобы ими пользовались редактор кода и инструменты вроде mypy. И при этом FastAPI продолжит выполнять валидацию данных, документацию и т.д. с использованием `response_model`.
Так вы можете добавить корректные аннотации типов к своим функциям, даже если фактически возвращаете тип, отличный от модели ответа, чтобы ими пользовались редактор и инструменты вроде mypy. И при этом FastAPI продолжит выполнять валидацию данных, документацию и т.д. с использованием `response_model`.
Вы также можете указать `response_model=None`, чтобы отключить создание модели ответа для данной *операции пути*. Это может понадобиться, если вы добавляете аннотации типов для вещей, не являющихся валидными полями Pydantic. Пример вы увидите ниже.
@@ -75,7 +75,7 @@ FastAPI будет использовать этот `response_model` для д
Чтобы использовать `EmailStr`, сначала установите <a href="https://github.com/JoshData/python-email-validator" class="external-link" target="_blank">`email-validator`</a>.
Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установите пакет, например:
Создайте [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активируйте его и затем установите пакет, например:
```console
$ pip install email-validator
@@ -105,7 +105,7 @@ $ pip install "pydantic[email]"
///
## Добавить выходную модель { #add-an-output-model }
## Добавить модель для ответа { #add-an-output-model }
Вместо этого мы можем создать входную модель с паролем в открытом виде и выходную модель без него:
@@ -123,7 +123,7 @@ $ pip install "pydantic[email]"
### `response_model` или возвращаемый тип { #response-model-or-return-type }
В этом случае, поскольку две модели различаются, если бы мы аннотировали возвращаемый тип функции как `UserOut`, редактор кода и инструменты пожаловались бы, что мы возвращаем неверный тип, так как это разные классы.
В этом случае, поскольку две модели различаются, если бы мы аннотировали возвращаемый тип функции как `UserOut`, редактор и инструменты пожаловались бы, что мы возвращаем неверный тип, так как это разные классы.
Поэтому в этом примере мы должны объявить тип ответа в параметре `response_model`.
@@ -135,33 +135,33 @@ $ pip install "pydantic[email]"
Мы хотим, чтобы FastAPI продолжал **фильтровать** данные с помощью модели ответа. Так что, даже если функция возвращает больше данных, в ответ будут включены только поля, объявленные в модели ответа.
В предыдущем примере, поскольку классы были разными, нам пришлось использовать параметр `response_model`. Но это также означает, что мы теряем поддержку от редактора кода и инструментов, проверяющих возвращаемый тип функции.
В предыдущем примере, поскольку классы были разными, нам пришлось использовать параметр `response_model`. Но это также означает, что мы теряем поддержку от редактора и инструментов, проверяющих возвращаемый тип функции.
Однако в большинстве таких случаев нам нужно лишь **отфильтровать/убрать** некоторые данные, как в этом примере.
И в этих случаях мы можем использовать классы и наследование, чтобы воспользоваться **аннотациями типов** функций для лучшей поддержки в редакторе кода и инструментах и при этом получить **фильтрацию данных** от FastAPI.
И в этих случаях мы можем использовать классы и наследование, чтобы воспользоваться **аннотациями типов** функций для лучшей поддержки в редакторе и инструментах и при этом получить **фильтрацию данных** от FastAPI.
{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
Так мы получаем поддержку инструментов редакторов кода и mypy, так как этот код корректен с точки зрения типов — и одновременно получаем фильтрацию данных от FastAPI.
Так мы получаем поддержку инструментов (редакторы, mypy) — код корректен с точки зрения типов — и одновременно получаем фильтрацию данных от FastAPI.
Как это работает? Давайте разберёмся. 🤓
### Аннотации типов и инструменты { #type-annotations-and-tooling }
Сначала посмотрим, как это увидят редактор кода, mypy и другие инструменты.
Сначала посмотрим, как это увидят редакторы, mypy и другие инструменты.
`BaseUser` содержит базовые поля. Затем `UserIn` наследуется от `BaseUser` и добавляет поле `password`, то есть он будет включать все поля обеих моделей.
`BaseUser` содержит базовые поля. Затем `UserIn` наследуется от `BaseUser` и добавляет поле `password`, то есть он включает все поля обеих моделей.
Мы аннотируем возвращаемый тип функции как `BaseUser`, но фактически возвращаем экземпляр `UserIn`.
Редактор кода, mypy и другие инструменты не будут возражать, потому что с точки зрения типов `UserIn` — подкласс `BaseUser`, что означает, что это *валидный* тип везде, где ожидается что-то, являющееся `BaseUser`.
Редактор, mypy и другие инструменты не будут возражать, потому что с точки зрения типов `UserIn` — подкласс `BaseUser`, что означает, что это *валидный* тип везде, где ожидается что-то, являющееся `BaseUser`.
### Фильтрация данных FastAPI { #fastapi-data-filtering }
Теперь для FastAPI: он увидит возвращаемый тип и убедится, что то, что вы возвращаете, включает **только** поля, объявленные в этом типе.
Теперь, для FastAPI: он увидит возвращаемый тип и убедится, что то, что вы возвращаете, включает **только** поля, объявленные в этом типе.
FastAPI делает несколько вещей внутри вместе с Pydantic, чтобы гарантировать, что те же правила наследования классов не используются для фильтрации возвращаемых данных, иначе вы могли бы в итоге вернуть намного больше данных, чем ожидали.
FastAPI делает несколько вещей внутри вместе с Pydantic, чтобы гарантировать, что те же правила наследования классов не используются для фильтрации возвращаемых данных, иначе вы могли бы вернуть гораздо больше данных, чем ожидали.
Таким образом вы получаете лучшее из обоих миров: аннотации типов с **поддержкой инструментов** и **фильтрацию данных**.
@@ -171,17 +171,17 @@ FastAPI делает несколько вещей внутри вместе с
<img src="/img/tutorial/response-model/image01.png">
И обе модели будут использоваться в интерактивной документации API:
И обе модели используются в интерактивной документации API:
<img src="/img/tutorial/response-model/image02.png">
## Другие аннотации возвращаемых типов { #other-return-type-annotations }
Бывают случаи, когда вы возвращаете что-то, что не является валидным полем Pydantic, и аннотируете это в функции только ради поддержки инструментов (редактор кода, mypy и т.д.).
Бывают случаи, когда вы возвращаете что-то, что не является валидным полем Pydantic, и аннотируете это в функции только ради поддержки инструментов (редактор, mypy и т. д.).
### Возврат Response напрямую { #return-a-response-directly }
Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах документации для продвинутых](../advanced/response-directly.md){.internal-link target=_blank}.
Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах для продвинутых](../advanced/response-directly.md){.internal-link target=_blank}.
{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
@@ -195,7 +195,7 @@ FastAPI делает несколько вещей внутри вместе с
{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот простой случай.
Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот случай.
### Некорректные аннотации возвращаемых типов { #invalid-return-type-annotations }
@@ -209,15 +209,15 @@ FastAPI делает несколько вещей внутри вместе с
### Отключить модель ответа { #disable-response-model }
Продолжая пример выше, вы можете не хотеть использовать стандартные валидацию данных, документирование, фильтрацию и т.п., выполняемые FastAPI.
Продолжая пример выше, вы можете не хотеть использовать стандартную валидацию данных, документацию, фильтрацию и т.д., выполняемые FastAPI.
Но при этом вы можете хотеть сохранить аннотацию возвращаемого типа в функции, чтобы пользоваться поддержкой инструментов вроде редакторов кода и инструментов проверки типов (например, mypy).
Но при этом вы можете хотеть сохранить аннотацию возвращаемого типа в функции, чтобы пользоваться поддержкой инструментов (редакторы, проверки типов вроде mypy).
В этом случае вы можете отключить генерацию модели ответа, установив `response_model=None`:
{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
Так FastAPI пропустит генерацию модели ответа, и вы сможете использовать любые аннотации возвращаемых типов, которые вам нужны, без влияния на ваше приложение FastAPI. 🤓
Так FastAPI пропустит генерацию модели ответа, и вы сможете использовать любые аннотации возвращаемых типов, не влияя на ваше приложение FastAPI. 🤓
## Параметры кодирования модели ответа { #response-model-encoding-parameters }
@@ -252,6 +252,20 @@ FastAPI делает несколько вещей внутри вместе с
/// info | Информация
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы используете Pydantic v2, применяйте `.model_dump()`.
///
/// info | Информация
FastAPI использует метод `.dict()` у Pydantic-моделей с <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">параметром `exclude_unset`</a>, чтобы добиться такого поведения.
///
/// info | Информация
Вы также можете использовать:
* `response_model_exclude_defaults=True`
@@ -298,7 +312,7 @@ FastAPI достаточно умен (на самом деле, это Pydantic
Обратите внимание, что значения по умолчанию могут быть любыми, не только `None`.
Это может быть список (`[]`), число с плавающей точкой `10.5` и т.д.
Это может быть список (`[]`), число с плавающей точкой `10.5` и т. д.
///
@@ -332,7 +346,7 @@ FastAPI достаточно умен (на самом деле, это Pydantic
#### Использование `list` вместо `set` { #using-lists-instead-of-sets }
Если вы забыли использовать `set` и применили `list` или `tuple` вместо него, FastAPI всё равно преобразует это в `set`, и всё будет работать корректно:
Если вы забыли использовать `set` и применили `list` или `tuple`, FastAPI всё равно преобразует это в `set`, и всё будет работать корректно:
{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}

View File

@@ -8,14 +8,36 @@
Вы можете объявить `examples` для модели Pydantic, которые будут добавлены в сгенерированную JSON Schema.
//// tab | Pydantic v2
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
////
//// tab | Pydantic v1
{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
////
Эта дополнительная информация будет добавлена как есть в выходную **JSON Schema** этой модели и будет использоваться в документации API.
Вы можете использовать атрибут `model_config`, который принимает `dict`, как описано в <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Документации Pydantic: Конфигурация</a>.
//// tab | Pydantic v2
В Pydantic версии 2 вы будете использовать атрибут `model_config`, который принимает `dict`, как описано в <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Документации Pydantic: Конфигурация</a>.
Вы можете задать `"json_schema_extra"` с `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.
////
//// tab | Pydantic v1
В Pydantic версии 1 вы будете использовать внутренний класс `Config` и `schema_extra`, как описано в <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">Документации Pydantic: Настройка схемы</a>.
Вы можете задать `schema_extra` со `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.
////
/// tip | Подсказка
Вы можете использовать тот же приём, чтобы расширить JSON Schema и добавить свою собственную дополнительную информацию.
@@ -102,7 +124,7 @@ OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) доб
Ключи `dict` идентифицируют каждый пример, а каждое значение — это ещё один `dict`.
Каждый конкретный пример `dict` в `examples` может содержать:
Каждый конкретный пример`dict` в `examples` может содержать:
* `summary`: Краткое описание примера.
* `description`: Подробное описание, которое может содержать текст в Markdown.
@@ -113,7 +135,7 @@ OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) доб
{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}
### OpenAPI-примеры в UI документации { #openapi-examples-in-the-docs-ui }
### OpenAPI-примеры в UI документации { #openapi-examples-in-the-docs-ui }
С `openapi_examples`, добавленным в `Body()`, страница `/docs` будет выглядеть так:
@@ -191,7 +213,7 @@ OpenAPI также добавила поля `example` и `examples` в друг
### Swagger UI и специфичные для OpenAPI `examples` { #swagger-ui-and-openapi-specific-examples }
Теперь, поскольку Swagger UI не поддерживал несколько примеров JSON Schema (по состоянию на 2023-08-26), у пользователей не было способа показать несколько примеров в документации.
Раньше, поскольку Swagger UI не поддерживал несколько примеров JSON Schema (по состоянию на 2023-08-26), у пользователей не было способа показать несколько примеров в документации.
Чтобы решить это, FastAPI `0.103.0` **добавил поддержку** объявления того же старого, **специфичного для OpenAPI**, поля `examples` с новым параметром `openapi_examples`. 🤓

View File

@@ -90,12 +90,5 @@ For the following technical terms, use these specific translations to ensure con
* serve (meaning providing access to something): «отдавать» (or `предоставлять доступ к`)
* recap (noun): резюме
* utility function: вспомогательная функция
* fast to code: позволяет быстро писать код
* Tutorial - User Guide: Учебник - Руководство пользователя
* submodule: подмодуль
* subpackage: подпакет
* router: роутер
* building, deploying, accessing (when describing features of FastAPI Cloud): созданиe образа, развертывание и доступ
* type checker tool: инструмент проверки типов
Do not add whitespace in `т.д.`, `т.п.`.

View File

@@ -4,16 +4,10 @@ Translate to Turkish (Türkçe).
Language code: tr.
### Core principle
Don't translate word-by-word. Rewrite naturally in Turkish as if writing the doc from scratch. Preserve meaning, but prioritize fluency over literal accuracy.
### Grammar and tone
- Use instructional Turkish, consistent with existing Turkish docs.
- Use imperative/guide language (e.g. "açalım", "gidin", "kopyalayalım", "bir bakalım").
- Avoid filler words and overly long sentences.
- Ensure sentences make sense in Turkish context — adjust structure, conjunctions, and verb forms as needed for natural flow (e.g. use "Ancak" instead of "Ve" when connecting contrasting sentences, use "-maktadır/-mektedir" for formal statements).
- Use imperative/guide language when appropriate (e.g. açalım, gidin, kopyalayalım).
### Headings
@@ -21,23 +15,13 @@ Don't translate word-by-word. Rewrite naturally in Turkish as if writing the doc
### Quotes
- Keep quote style consistent with existing Turkish docs (typically ASCII quotes in text).
- Never modify quotes inside inline code, code blocks, URLs, or file paths.
- Alıntı stili mevcut Türkçe dokümanlarla tutarlı tutun (genellikle metin içinde ASCII tırnak işaretleri kullanılır).
- Satır içi kod, kod blokları, URL'ler veya dosya yolları içindeki tırnak işaretlerini asla değiştirmeyin.
### Ellipsis
- Keep ellipsis style (`...`) consistent with existing Turkish docs.
- Never modify `...` in code, URLs, or CLI examples.
### Consistency
- Use the same translation for the same term throughout the document.
- If you translate a concept one way, keep it consistent across all occurrences.
### Links and references
- Never modify link syntax like `{.internal-link target=_blank}`.
- Keep markdown link structure intact: `[text](url){.internal-link}`.
- Üç nokta (...) stili mevcut Türkçe dokümanlarla tutarlı tutun.
- Kod, URL veya CLI örneklerindeki `...` ifadesini asla değiştirmeyin.
### Preferred translations / glossary

View File

@@ -23,6 +23,7 @@ SUPPORTED_LANGS = {
"en",
"de",
"es",
"ja",
"ko",
"pt",
"ru",