@ -1,150 +1,134 @@
# カスタムレスポンス - HTML、ストリーム、ファイル、その他のレスポンス { #custom -response-html-stream-file-others }
# カスタムレスポンス - HTML、ストリーム、ファイル、その他 { #custom -response-html-stream-file-others }
デフォルトでは、**FastAPI** は ` JSONResponse` を使って レスポンスを返します。
デフォルトでは、**FastAPI** はJSONレスポンスを返します。
[レスポンスを直接返す ](response-directly.md ){.internal-link target=_blank}で見たように、 `Response` を直接返すことでこの挙動をオーバーライド できます。
[レスポンスを直接返す ](response-directly.md )で見たように、`Response` を直接返してこの挙動を上書き できます。
しかし、`Response` を直接返すと (または `JSONResponse` のような任意のサブクラスを返すと)、データは自動的に変換されず(`response_model` を宣言していても) 、ドキュメントも自動生成されません(例えば、生成されるOpenAPIの一部としてHTTPヘッダー `Content-Type` に特定の「メディアタイプ」を含めるなど)。
しかし、`Response`(または `JSONResponse` のような任意のサブクラス)を直接返す場合、(`response_model` を宣言していても)データは自動的に変換されず 、ドキュメントも自動生成されません(例えば、生成されるOpenAPIの一部としてHTTPヘッダー `Content-Type` に特定の「メディアタイプ」を含めるなど)。
`response_class` パラメータを使用して、*path operation デコレータ* で 使用したい `Response` (任意の `Response` サブクラス)を宣言することもできます。
一方で、*path operation デコレータ* の `response_class` パラメータを使って、 使用したい `Response` (`Response` の任意の サブクラス)を宣言することもできます。
*path operation 関数* から返されるコンテンツは、その `Response` に含まれます。
*path operation 関数* から返したコンテンツは、その `Response` に格納されます。
そしてその `Response` が、`JSONResponse` や `UJSONResponse` の場合のようにJSONメディアタイプ(`application/json`)なら、関数の返り値は *path operationデコレータ* に宣言した任意のPydantic `response_model` により自動的に変換(およびフィルタ)されます。
/// note | 備考
/// note | 備考
メディアタイプを指定せずにレスポンスクラスを利用すると、FastAPIはレスポンスにコンテンツがないことを期待 します。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットが 記載されません。
メディアタイプを持たないレスポンスクラスを使用すると、FastAPIはレスポンスにコンテンツがないものと見な します。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットは 記載されません。
///
///
## `ORJSONResponse` を使う { #use -orjsonresponse }
## JSONレスポンス { #json -responses }
例えば、パフォーマンスを絞り出したい場合は、< a href = "https://github.com/ijl/orjson" class = "external-link" target = "_blank" > `orjson`</ a > をインストールし、レスポンスとして `ORJSONResponse` をセットできます。
使いたい `Response` クラス(サブクラス)をインポートし、*path operationデコレータ* に宣言します。
大きなレスポンスの場合、`Response` を直接返すほうが、辞書を返すよりもはるかに高速で す。
FastAPI はデフォルトでJSONレスポンスを返します。
これは、デフォルトではFastAPIがチュートリアルで説明した同じ[JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}を使って、内部の各アイテムを検査し、JSONとしてシリアライズ可能であることを確認するためです。これにより、例えばデータベースモデルのような**任意のオブジェクト**を返せ ます。
[レスポンスモデル ](../tutorial/response-model.md ) を宣言すると、FastAPI は Pydantic を使ってデータをJSONにシリアライズします。
しかし、返そうとしているコンテンツが **JSONでシリアライズ可能**であることが確実なら、それを直接レスポンスクラスに渡して、FastAPIがレスポンスクラスへ渡す前に返却コンテンツを `jsonable_encoder` に通すことで発生する追加のオーバーヘッドを回避できます。
レスポンスモデルを宣言しない場合、FastAPI は [JSON Compatible Encoder ](../tutorial/encoder.md ) で説明した `jsonable_encoder` を使い、その結果を `JSONResponse` に入れます。
{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *}
/// info | 情報
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するためにも利用 されます。
`JSONResponse` のようにJSONメディアタイプ(`application/json`)を持つ `response_class` を宣言した場合、*path operation デコレータ* に宣言した任意のPydanticの `response_model` に従って、返すデータは自動的に変換(およびフィルタ)されます。ただし、そのデータは Pydantic でJSONのバイト列にシリアライズされるわけではなく、まず `jsonable_encoder` で変換された後に `JSONResponse` クラスへ渡され、Pythonの標準JSONライブラリでバイト列にシリアライズされます。
この場合、HTTPヘッダー `Content-Type` には `application/json` がセットされます。
### JSONのパフォーマンス { #json -performance }
そして、OpenAPIにはそのようにドキュメントされます。
///
/// tip | 豆知識
`ORJSONResponse` はFastAPIでのみ利用可能で、Starletteでは利用できません 。
結論として、最大のパフォーマンスを得たい場合は、[レスポンスモデル](../tutorial/response-model.md) を使い、*path operation デコレータ* で `response_class` は宣言しないでください。
///
{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}
## HTMLレスポンス { #html -response }
## HTMLレスポンス { #html -response }
**FastAPI** からHTMLを直接返す場合 は、`HTMLResponse` を使います。
**FastAPI** からHTMLを直接返すに は、`HTMLResponse` を使います。
* `HTMLResponse` をインポートする。
* `HTMLResponse` をインポートする
* *path operation デコレータ* のパラメータ `response_class` に `HTMLResponse` を渡す。
* *path operation デコレータ* のパラメータ `response_class` に `HTMLResponse` を渡す
{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
/// info | 情報
/// info | 情報
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するためにも利 用されます。
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するためにも使 用されます。
この場合、HTTPヘッダー `Content-Type` には `text/html` がセット されます。
この場合、HTTPヘッダー `Content-Type` には `text/html` が設定 されます。
そして、OpenAPIにはそのようにドキュメント されます。
そして、OpenAPIにもそのようにドキュメント化 されます。
///
///
### `Response` を返す { #return -a-response }
### `Response` を返す { #return -a-response }
[レスポンスを直接返す ](response-directly.md ){.internal-link target=_blank} で見たように、レスポンスを返すことで 、*path operation* の中でレスポンスを直接オーバーライド することもできます。
[レスポンスを直接返す ](response-directly.md )で見たように、*path operation* の中でレスポンスを直接返して上書き することもできます。
上記と同じ例において、 `HTMLResponse` を返すと、こ のようになります:
上記と同じ例で、`HTMLResponse` を返すと次 のようになります:
{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}
/// warning | 注意
/// warning | 注意
*path operation関数* から直接返される `Response` は、OpenAPIにドキュメントされず(例えば、`Content-Type` がドキュメントされない)、自動的な対話的ドキュメントで も表示されません。
*path operation 関数* から直接返される `Response` は、OpenAPIにドキュメント化されず(例えば `Content-Type` がドキュメント化されない)、自動生成の対話的ドキュメントに も表示されません。
///
///
/// info | 情報
/// info | 情報
もちろん、実際の `Content-Type` ヘッダーやステータスコードなどは、返され た `Response` オブジェクトに由来します。
もちろん、実際の `Content-Type` ヘッダーやステータスコードなどは、返し た `Response` オブジェクトに由来します。
///
///
### OpenAPIドキュメントと `Response` のオーバーライド { #document -in-openapi-and-override-response }
### OpenAPIにドキュメント化しつつ `Response` を上書き { #document -in-openapi-and-override-response }
関数の中でレスポンスをオーバーライドしつつも、OpenAPI に「メディアタイプ」をドキュメント化したいなら 、`response_class` パラメータを使用し、かつ `Response` オブジェクトを返します。
関数の中からレスポンスを上書きしつつ、同時にOpenAPIで「メディアタイプ」をドキュメント化したい場合は 、`response_class` パラメータを使用し、かつ `Response` オブジェクトを返します。
`response_class` はOpenAPIの*path operation*のドキュメント化のためにのみ使用され、`Response` は そのまま使用されます。
この場合、`response_class` はOpenAPIの *path operation* をドキュメント化するためだけに使われ、実際には返した `Response` が そのまま使用されます。
#### `HTMLResponse` を直接返す { #return -an-htmlresponse-directly }
#### `HTMLResponse` を直接返す { #return -an-htmlresponse-directly }
例えば、こ のようになります:
例えば、次 のようになります:
{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}
この例では、関数 `generate_html_response()` は、`str` のHTMLを返すのではなく、`Response` を生成して返しています。
この例では、関数 `generate_html_response()` はHTMLの `str` を返すのではなく、すでに `Response` を生成して返しています。
`generate_html_response()` を呼び出した結果を返すことにより、デフォルトの **FastAPI** の挙動をオーバーライド する `Response` をすでに返しています。
`generate_html_response()` の呼び出し結果を返すことで、デフォルトの **FastAPI** の挙動を上書き する `Response` をすでに返しています。
しかし、`response_class` にも `HTMLResponse` を渡しているため、**FastAPI** はOpenAPIと対話的ドキュメントで、`text/html` のHTMLとしてどのようにドキュメント化すればよいかを理解 できます:
しかし、`response_class` にも `HTMLResponse` を渡しているため、**FastAPI** はOpenAPIおよび対話的ドキュメントで、それが `text/html` のHTMLであると正しくドキュメント化 できます:
< img src = "/img/tutorial/custom-response/image01.png" >
< img src = "/img/tutorial/custom-response/image01.png" >
## 利用可能なレスポンス { #available -responses }
## 利用可能なレスポンス { #available -responses }
以下が 利用可能なレスポンスの一部です。
以下は 利用可能なレスポンスの一部です。
`Response` を使って他の何かを返せますし、カスタムのサブクラスも作れることを覚えておいてください 。
`Response` を使って他のものを返したり、カスタムサブクラスを作成することもできます 。
/// note | 技術詳細
/// note | 技術詳細
`from starlette.responses import HTMLResponse` も利用 できます。
`from starlette.responses import HTMLResponse` を使うこと もできます。
**FastAPI** は開発者の利便性のために、`starlette.responses` と同じものを `fastapi.responses` として提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供され ます。
**FastAPI** は開発者の利便性のために、`starlette.responses` と同じものを `fastapi.responses` として提供しています。ただし、利用可能なレスポンスの多くはStarletteから直接提供されてい ます。
///
///
### `Response` { #response }
### `Response` { #response }
メインの `Response` クラスで、他の全 てのレスポンスはこれを継承しています。
メインの `Response` クラスで、他のすべ てのレスポンスはこれを継承しています。
直接返すことができます。
直接返すことができます。
以下のパラメータを受け付けます。
以下のパラメータを受け付けます。
* `content` - `str` か `bytes` 。
* `content` - `str` または `bytes`
* `status_code` - `int` のHTTPステータスコード。
* `status_code` - `int` のHTTPステータスコード
* `headers` - 文字列の `dict` 。
* `headers` - 文字列の `dict`
* `media_type` - メディアタイプを示す `str` 。例えば `"text/html"` 。
* `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_py310.py hl[1,18] *}
{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}
### `HTMLResponse` { #htmlresponse }
### `HTMLResponse` { #htmlresponse }
上で読んだように、テキストやバイトを受け取り、HTMLレスポンスを返します。
上で読んだように、テキストやバイト列 を受け取り、HTMLレスポンスを返します。
### `PlainTextResponse` { #plaintextresponse }
### `PlainTextResponse` { #plaintextresponse }
テキストやバイトを受け取り、プレーンテキストのレスポンスを返します。
テキストやバイト列 を受け取り、プレーンテキストのレスポンスを返します。
{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}
@ -152,45 +136,19 @@ FastAPI(実際にはStarlette)は自動的にContent-Lengthヘッダーを
データを受け取り、`application/json` としてエンコードされたレスポンスを返します。
データを受け取り、`application/json` としてエンコードされたレスポンスを返します。
上で読んだように、**FastAPI** のデフォルトのレスポンスとして利用されます。
これは、上で述べたように **FastAPI** のデフォルトのレスポンスです。
### `ORJSONResponse` { #orjsonresponse }
上で読んだように、< a href = "https://github.com/ijl/orjson" class = "external-link" target = "_blank" > `orjson`< / a > を使った、高速な代替のJSONレスポンスです。
/// info | 情報
これは、例えば `pip install orjson` で `orjson` をインストールする必要があります。
///
/// note | 技術詳細
### `UJSONResponse` { #ujsonresponse }
< a href = "https://github.com/ultrajson/ultrajson" class = "external-link" target = "_blank" > `ujson`< / a > を使った、代替のJSONレスポンスです。
/// info | 情報
これは、例えば `pip install ujson` で `ujson` をインストールする必要があります。
///
/// warning | 注意
`ujson` は、いくつかのエッジケースの取り扱いについて、Pythonにビルトインされた実装ほど注意深くありません。
///
{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *}
/// tip | 豆知識
ただし、レスポンスモデルや返却型を宣言した場合は、それが直接データのJSONシリアライズに使われ、適切なJSONのメディアタイプを持つレスポンスが `JSONResponse` クラスを使わずに直接返されます。
`ORJSONResponse` のほうが高速な代替かもしれません 。
これが最適なパフォーマンスを得る理想的な方法です。
///
///
### `RedirectResponse` { #redirectresponse }
### `RedirectResponse` { #redirectresponse }
HTTPリダイレクトを返します。デフォルトでは307ステータスコード(Temporary Redirect)となり ます。
HTTPリダイレクトを返します。デフォルトでは307ステータスコード(Temporary Redirect)を使用します。
`RedirectResponse` を直接返せます:
`RedirectResponse` を直接返せます:
@ -202,56 +160,50 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}
その場合、*path operation*関数からURLを直接返せます。
その場合、*path operation* 関数からURLを直接返せます。
この場合に使用される `status_code` は `RedirectResponse` のデフォルトである `307` になります。
この場合に使用される `status_code` は、`RedirectResponse` のデフォルトである `307` になります。
---
---
また 、`status_code` パラメータを `response_class` パラメータと組み合わせて使うこともできます:
さらに 、`status_code` パラメータを `response_class` パラメータと組み合わせて使うこともできます:
{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}
### `StreamingResponse` { #streamingresponse }
### `StreamingResponse` { #streamingresponse }
非同期ジェネレータ、または通常のジェネレータ/イテレータを受け取り、レスポンスボディをストリームします。
非同期ジェネレータ、または通常のジェネレータ/イテレータ(`yield` を持つ関数) を受け取り、レスポンスボディをストリームします。
{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14 ] *}
{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16 ] *}
#### ファイルライクオブジェクトで `StreamingResponse` を使う { #using -streamingresponse-with-file-like-objects }
/// note | 技術詳細
< a href = "https://docs.python.org/3/glossary.html#term-file-like-object" class = "external-link" target = "_blank" > file-like</ a > オブジェクト(例: `open()` で返されるオブジェクト)がある場合、そのfile-likeオブジェクトを反復処理するジェネレータ関数を作れます。
そうすれば、最初にすべてをメモリへ読み込む必要はなく、そのジェネレータ関数を `StreamingResponse` に渡して返せます。
これにはクラウドストレージとの連携、映像処理など、多くのライブラリが含まれます。
{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *}
`async` タスクは `await` に到達したときにのみキャンセルできます。`await` がない場合、ジェネレータ(`yield` を持つ関数)は適切にキャンセルできず、キャンセル要求後も実行が続く可能性があります。
1. これはジェネレータ関数です。内部に `yield` 文を含むため「ジェネレータ関数」です。
この小さな例では `await` が不要なため、イベントループにキャンセルを処理する機会を与えるために `await anyio.sleep(0)` を追加しています。
2. `with` ブロックを使うことで、ジェネレータ関数が終わった後(つまりレスポンスの送信が完了した後)にfile-likeオブジェクトが確実にクローズされるようにします。
3. この `yield from` は、`file_like` という名前のものを反復処理するように関数へ指示します。そして反復された各パートについて、そのパートをこのジェネレータ関数(`iterfile`)から来たものとして `yield` します。
つまり、内部的に「生成」の作業を別のものへ移譲するジェネレータ関数で す。
これは大きなストリームや無限ストリームではさらに重要になります。
このようにすることで `with` ブロックに入れられ、完了後にfile-likeオブジェクトが確実にクローズされます。
///
/// tip | 豆知識
/// tip | 豆知識
ここでは `async` と `await` をサポートしていない標準の `open()` を使っているため、通常の `def` でpath operationを宣言している点に注意してください。
`StreamingResponse` を直接返す代わりに、[データをストリームする](./stream-data.md) スタイルに従うことをおすすめします。こちらのほうがはるかに便利で、裏側でキャンセル処理も行ってくれます。
JSON Lines をストリームする場合は、[JSON Lines をストリームする](../tutorial/stream-json-lines.md) チュートリアルを参照してください。
///
///
### `FileResponse` { #fileresponse }
### `FileResponse` { #fileresponse }
レスポンスとしてファイルを 非同期的 にストリームします。
ファイルを レスポンスとして非同期にストリームします。
他のレスポンスタイプとは異なる引数のセットを受け取りインスタンス化します。
他のレスポンスタイプとは異なる引数セットでインスタンス化します:
* `path` - ストリームするファイルのファイルパス。
* `path` - ストリームするファイルのファイルパス
* `headers` - 含めたい任意のカスタムヘッダーの辞書。
* `headers` - 含めたい任意のカスタムヘッダー(辞書)
* `media_type` - メディアタイプを示す文字列。未設定の場合、ファイル名やパスからメディアタイプが 推測されます。
* `media_type` - メディアタイプを示す文字列。未設定の場合、ファイル名やパスから推測されます
* `filename` - 設定した場合、レスポンスの `Content-Disposition` に含まれます。
* `filename` - 設定した場合、レスポンスの `Content-Disposition` に含まれます
ファイルレスポンスには、適切な `Content-Length` 、`Last-Modified`、`ETag` ヘッダーが含まれます。
ファイルレスポンスには、適切な `Content-Length` 、`Last-Modified`、`ETag` ヘッダーが含まれます。
@ -261,17 +213,17 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}
この場合、*path operation*関数からファイルパスを直接返せます。
この場合、*path operation* 関数からファイルパスを直接返せます。
## カスタムレスポンスクラス { #custom -response-class }
## カスタムレスポンスクラス { #custom -response-class }
`Response` を継承した独自のカスタムレスポンスクラスを作成して利 用できます。
`Response` を継承して、独自のカスタムレスポンスクラスを作成し、使 用できます。
例えば、< a href = "https://github.com/ijl/orjson" class = "external-link" target = "_blank" > `orjson`</ a > を使いたいが、同梱の `ORJSONResponse` クラスで使われていないカスタム設定も 使いたいとします。
例えば、[`orjson`](https://github.com/ijl/orjson) を特定の設定で 使いたいとします。
例えば、インデントされ整形されたJSONを返したいので、orjson オプション `orjson.OPT_INDENT_2` を使いたいとします。
インデントされた整形済みJSONを返したいので、orjson の オプション `orjson.OPT_INDENT_2` を使いたいとします。
`CustomORJSONResponse` を作れます。主に必要なのは、コンテンツを `bytes` として 返す `Response.render(content)` メソッドを作ることです:
`CustomORJSONResponse` を作成できます。主に必要なのは、`bytes` を 返す `Response.render(content)` メソッドを作ることです:
{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}
@ -289,24 +241,32 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
}
}
```
```
もちろん、JSONの整形よりも、これを活用するもっと良い方法が見つかるはずです。 😉
もちろん、JSONの整形以外にも、これを活用するもっと良い方法が見つかるはずです。 😉
### `orjson` か レスポンスモデルか { #orjson -or-response-model }
もし求めているのがパフォーマンスであれば、`orjson` レスポンスを使うより、[レスポンスモデル](../tutorial/response-model.md) を使うほうが良い場合が多いです。
レスポンスモデルがあると、FastAPI は中間ステップ(他の場合に行われる `jsonable_encoder` による変換など)を介さずに、Pydantic を使ってデータをJSONにシリアライズします。
内部的には、Pydantic はJSONシリアライズに `orjson` と同じRust由来の仕組みを用いているため、レスポンスモデルを使うだけで最良のパフォーマンスが得られます。
## デフォルトレスポンスクラス { #default -response-class }
## デフォルトレスポンスクラス { #default -response-class }
**FastAPI** クラスのインスタンス、または `APIRouter` を作成する際に、デフォルトで使用するレスポンスクラスを指定できます。
**FastAPI** クラスのインスタンスや `APIRouter` を作成する際に、デフォルトで使用するレスポンスクラスを指定できます。
これを定義するパラメータは `default_response_class` です。
これを定義するパラメータは `default_response_class` です。
以下の例では、**FastAPI** はすべての*path operation*で、`JSONResponse` の代わりに `ORJSONResponse` をデフォルトとして使います。
以下の例では、**FastAPI** はすべての *path operation* で、JSONの代わりにデフォルトで `HTMLResponse` を使用し ます。
{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}
/// tip | 豆知識
/// tip | 豆知識
これまでと同様に、*path operation*で `response_class` をオーバーライドできます。
これまでと同様に、*path operation* ごとに `response_class` をオーバーライドできます。
///
///
## その他のドキュメント { #additional -documentation }
## その他のドキュメント { #additional -documentation }
OpenAPIでは `responses` を使ってメディアタイプやその他の詳細を宣言することもできます: [Additional Responses in OpenAPI ](additional-responses.md ){.internal-link target=_blank} 。
OpenAPIでは `responses` を使ってメディアタイプやその他の詳細を宣言することもできます: [OpenAPI の追加レスポンス ](additional-responses.md )。