|
| 1 | +# カスタムレスポンス - HTML、ストリーム、ファイル、その他のレスポンス |
| 2 | + |
| 3 | +デフォルトでは、**FastAPI** は `JSONResponse` を使ってレスポンスを返します。 |
| 4 | + |
| 5 | +[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、 `Response` を直接返すことでこの挙動をオーバーライドできます。 |
| 6 | + |
| 7 | +しかし、`Response` を直接返すと、データは自動的に変換されず、ドキュメントも自動生成されません (例えば、生成されるOpenAPIの一部としてHTTPヘッダー `Content-Type` に特定の「メディアタイプ」を含めるなど) 。 |
| 8 | + |
| 9 | +しかし、*path operationデコレータ* に、使いたい `Response` を宣言することもできます。 |
| 10 | + |
| 11 | +*path operation関数* から返されるコンテンツは、その `Response` に含まれます。 |
| 12 | + |
| 13 | +そしてもし、`Response` が、`JSONResponse` や `UJSONResponse` の場合のようにJSONメディアタイプ (`application/json`) ならば、データは *path operationデコレータ* に宣言したPydantic `response_model` により自動的に変換 (もしくはフィルタ) されます。 |
| 14 | + |
| 15 | +!!! note "備考" |
| 16 | + メディアタイプを指定せずにレスポンスクラスを利用すると、FastAPIは何もコンテンツがないことを期待します。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットが記載されません。 |
| 17 | + |
| 18 | +## `ORJSONResponse` を使う |
| 19 | + |
| 20 | +例えば、パフォーマンスを出したい場合は、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>をインストールし、`ORJSONResponse`をレスポンスとしてセットすることができます。 |
| 21 | + |
| 22 | +使いたい `Response` クラス (サブクラス) をインポートし、 *path operationデコレータ* に宣言します。 |
| 23 | + |
| 24 | +```Python hl_lines="2 7" |
| 25 | +{!../../../docs_src/custom_response/tutorial001b.py!} |
| 26 | +``` |
| 27 | + |
| 28 | +!!! info "情報" |
| 29 | + パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するために利用することもできます。 |
| 30 | + |
| 31 | + この場合、HTTPヘッダー `Content-Type` には `application/json` がセットされます。 |
| 32 | + |
| 33 | + そして、OpenAPIにはそのようにドキュメントされます。 |
| 34 | + |
| 35 | +!!! tip "豆知識" |
| 36 | + `ORJSONResponse` は、現在はFastAPIのみで利用可能で、Starletteでは利用できません。 |
| 37 | + |
| 38 | +## HTMLレスポンス |
| 39 | + |
| 40 | +**FastAPI** からHTMLを直接返す場合は、`HTMLResponse` を使います。 |
| 41 | + |
| 42 | +* `HTMLResponse` をインポートする。 |
| 43 | +* *path operation* のパラメータ `content_type` に `HTMLResponse` を渡す。 |
| 44 | + |
| 45 | +```Python hl_lines="2 7" |
| 46 | +{!../../../docs_src/custom_response/tutorial002.py!} |
| 47 | +``` |
| 48 | + |
| 49 | +!!! info "情報" |
| 50 | + パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するために利用されます。 |
| 51 | + |
| 52 | + この場合、HTTPヘッダー `Content-Type` には `text/html` がセットされます。 |
| 53 | + |
| 54 | + そして、OpenAPIにはそのようにドキュメント化されます。 |
| 55 | + |
| 56 | +### `Response` を返す |
| 57 | + |
| 58 | +[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、レスポンスを直接返すことで、*path operation* の中でレスポンスをオーバーライドできます。 |
| 59 | + |
| 60 | +上記と同じ例において、 `HTMLResponse` を返すと、このようになります: |
| 61 | + |
| 62 | +```Python hl_lines="2 7 19" |
| 63 | +{!../../../docs_src/custom_response/tutorial003.py!} |
| 64 | +``` |
| 65 | + |
| 66 | +!!! warning "注意" |
| 67 | + *path operation関数* から直接返される `Response` は、OpenAPIにドキュメントされず (例えば、 `Content-Type` がドキュメントされない) 、自動的な対話的ドキュメントからも閲覧できません。 |
| 68 | + |
| 69 | +!!! info "情報" |
| 70 | + もちろん、実際の `Content-Type` ヘッダーやステータスコードなどは、返された `Response` オブジェクトに由来しています。 |
| 71 | + |
| 72 | +### OpenAPIドキュメントと `Response` のオーバーライド |
| 73 | + |
| 74 | +関数の中でレスポンスをオーバーライドしつつも、OpenAPI に「メディアタイプ」をドキュメント化したいなら、 `response_class` パラメータを使い、 `Response` オブジェクトを返します。 |
| 75 | + |
| 76 | +`response_class` はOpenAPIの *path operation* ドキュメントにのみ使用されますが、 `Response` はそのまま使用されます。 |
| 77 | + |
| 78 | +#### `HTMLResponse` を直接返す |
| 79 | + |
| 80 | +例えば、このようになります: |
| 81 | + |
| 82 | +```Python hl_lines="7 21 23" |
| 83 | +{!../../../docs_src/custom_response/tutorial004.py!} |
| 84 | +``` |
| 85 | + |
| 86 | +この例では、関数 `generate_html_response()` は、`str` のHTMLを返すのではなく `Response` を生成して返しています。 |
| 87 | + |
| 88 | +`generate_html_response()` を呼び出した結果を返すことにより、**FastAPI** の振る舞いを上書きする `Response` が既に返されています。 |
| 89 | + |
| 90 | +しかし、一方では `response_class` に `HTMLResponse` を渡しているため、 **FastAPI** はOpenAPIや対話的ドキュメントでHTMLとして `text/html` でドキュメント化する方法を知っています。 |
| 91 | + |
| 92 | +<img src="/img/tutorial/custom-response/image01.png"> |
| 93 | + |
| 94 | +## 利用可能なレスポンス |
| 95 | + |
| 96 | +以下が利用可能なレスポンスの一部です。 |
| 97 | + |
| 98 | +`Response` を使って他の何かを返せますし、カスタムのサブクラスも作れることを覚えておいてください。 |
| 99 | + |
| 100 | +!!! note "技術詳細" |
| 101 | + `from starlette.responses import HTMLResponse` も利用できます。 |
| 102 | + |
| 103 | + **FastAPI** は開発者の利便性のために `fastapi.responses` として `starlette.responses` と同じものを提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。 |
| 104 | + |
| 105 | +### `Response` |
| 106 | + |
| 107 | +メインの `Response` クラスで、他の全てのレスポンスはこれを継承しています。 |
| 108 | + |
| 109 | +直接返すことができます。 |
| 110 | + |
| 111 | +以下のパラメータを受け付けます。 |
| 112 | + |
| 113 | +* `content` - `str` か `bytes`。 |
| 114 | +* `status_code` - `int` のHTTPステータスコード。 |
| 115 | +* `headers` - 文字列の `dict` 。 |
| 116 | +* `media_type` - メディアタイプを示す `str` 。例えば `"text/html"` 。 |
| 117 | + |
| 118 | +FastAPI (実際にはStarlette) は自動的にContent-Lengthヘッダーを含みます。また、media_typeに基づいたContent-Typeヘッダーを含み、テキストタイプのためにcharsetを追加します。 |
| 119 | + |
| 120 | +```Python hl_lines="1 18" |
| 121 | +{!../../../docs_src/response_directly/tutorial002.py!} |
| 122 | +``` |
| 123 | + |
| 124 | +### `HTMLResponse` |
| 125 | + |
| 126 | +上で読んだように、テキストやバイトを受け取り、HTMLレスポンスを返します。 |
| 127 | + |
| 128 | +### `PlainTextResponse` |
| 129 | + |
| 130 | +テキストやバイトを受け取り、プレーンテキストのレスポンスを返します。 |
| 131 | + |
| 132 | +```Python hl_lines="2 7 9" |
| 133 | +{!../../../docs_src/custom_response/tutorial005.py!} |
| 134 | +``` |
| 135 | + |
| 136 | +### `JSONResponse` |
| 137 | + |
| 138 | +データを受け取り、 `application/json` としてエンコードされたレスポンスを返します。 |
| 139 | + |
| 140 | +上で読んだように、**FastAPI** のデフォルトのレスポンスとして利用されます。 |
| 141 | + |
| 142 | +### `ORJSONResponse` |
| 143 | + |
| 144 | +上で読んだように、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>を使った、高速な代替のJSONレスポンスです。 |
| 145 | + |
| 146 | +### `UJSONResponse` |
| 147 | + |
| 148 | +<a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>を使った、代替のJSONレスポンスです。 |
| 149 | + |
| 150 | +!!! warning "注意" |
| 151 | + `ujson` は、いくつかのエッジケースの取り扱いについて、Pythonにビルトインされた実装よりも作りこまれていません。 |
| 152 | + |
| 153 | +```Python hl_lines="2 7" |
| 154 | +{!../../../docs_src/custom_response/tutorial001.py!} |
| 155 | +``` |
| 156 | + |
| 157 | +!!! tip "豆知識" |
| 158 | + `ORJSONResponse` のほうが高速な代替かもしれません。 |
| 159 | + |
| 160 | +### `RedirectResponse` |
| 161 | + |
| 162 | +HTTPリダイレクトを返します。デフォルトでは307ステータスコード (Temporary Redirect) となります。 |
| 163 | + |
| 164 | +```Python hl_lines="2 9" |
| 165 | +{!../../../docs_src/custom_response/tutorial006.py!} |
| 166 | +``` |
| 167 | + |
| 168 | +### `StreamingResponse` |
| 169 | + |
| 170 | +非同期なジェネレータか通常のジェネレータ・イテレータを受け取り、レスポンスボディをストリームします。 |
| 171 | + |
| 172 | +```Python hl_lines="2 14" |
| 173 | +{!../../../docs_src/custom_response/tutorial007.py!} |
| 174 | +``` |
| 175 | + |
| 176 | +#### `StreamingResponse` をファイルライクなオブジェクトとともに使う |
| 177 | + |
| 178 | +ファイルライクなオブジェクト (例えば、 `open()` で返されたオブジェクト) がある場合、 `StreamingResponse` に含めて返すことができます。 |
| 179 | + |
| 180 | +これにはクラウドストレージとの連携や映像処理など、多くのライブラリが含まれています。 |
| 181 | + |
| 182 | +```Python hl_lines="2 10-11" |
| 183 | +{!../../../docs_src/custom_response/tutorial008.py!} |
| 184 | +``` |
| 185 | + |
| 186 | +!!! tip "豆知識" |
| 187 | + ここでは `async` や `await` をサポートしていない標準の `open()` を使っているので、通常の `def` でpath operationを宣言していることに注意してください。 |
| 188 | + |
| 189 | +### `FileResponse` |
| 190 | + |
| 191 | +レスポンスとしてファイルを非同期的にストリームします。 |
| 192 | + |
| 193 | +他のレスポンスタイプとは異なる引数のセットを受け取りインスタンス化します。 |
| 194 | + |
| 195 | +* `path` - ストリームするファイルのファイルパス。 |
| 196 | +* `headers` - 含めたい任意のカスタムヘッダーの辞書。 |
| 197 | +* `media_type` - メディアタイプを示す文字列。セットされなかった場合は、ファイル名やパスからメディアタイプが推察されます。 |
| 198 | +* `filename` - セットされた場合、レスポンスの `Content-Disposition` に含まれます。 |
| 199 | + |
| 200 | +ファイルレスポンスには、適切な `Content-Length` 、 `Last-Modified` 、 `ETag` ヘッダーが含まれます。 |
| 201 | + |
| 202 | +```Python hl_lines="2 10" |
| 203 | +{!../../../docs_src/custom_response/tutorial009.py!} |
| 204 | +``` |
| 205 | + |
| 206 | +## デフォルトレスポンスクラス |
| 207 | + |
| 208 | +**FastAPI** クラスのインスタンスか `APIRouter` を生成するときに、デフォルトのレスポンスクラスを指定できます。 |
| 209 | + |
| 210 | +定義するためのパラメータは、 `default_response_class` です。 |
| 211 | + |
| 212 | +以下の例では、 **FastAPI** は、全ての *path operation* で `JSONResponse` の代わりに `ORJSONResponse` をデフォルトとして利用します。 |
| 213 | + |
| 214 | +```Python hl_lines="2 4" |
| 215 | +{!../../../docs_src/custom_response/tutorial010.py!} |
| 216 | +``` |
| 217 | + |
| 218 | +!!! tip "豆知識" |
| 219 | + 前に見たように、 *path operation* の中で `response_class` をオーバーライドできます。 |
| 220 | + |
| 221 | +## その他のドキュメント |
| 222 | + |
| 223 | +また、OpenAPIでは `responses` を使ってメディアタイプやその他の詳細を宣言することもできます: [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank} |
0 commit comments