カスタムレスポンス - HTML、ストリーム、ファイル、その他のレスポンス¶
デフォルトでは、FastAPI は JSONResponse
を使ってレスポンスを返します。
レスポンスを直接返すで見たように、 Response
を直接返すことでこの挙動をオーバーライドできます。
しかし、Response
を直接返すと、データは自動的に変換されず、ドキュメントも自動生成されません (例えば、生成されるOpenAPIの一部としてHTTPヘッダー Content-Type
に特定の「メディアタイプ」を含めるなど) 。
しかし、path operationデコレータ に、使いたい Response
を宣言することもできます。
path operation関数 から返されるコンテンツは、その Response
に含まれます。
そしてもし、Response
が、JSONResponse
や UJSONResponse
の場合のようにJSONメディアタイプ (application/json
) ならば、データは path operationデコレータ に宣言したPydantic response_model
により自動的に変換 (もしくはフィルタ) されます。
備考
メディアタイプを指定せずにレスポンスクラスを利用すると、FastAPIは何もコンテンツがないことを期待します。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットが記載されません。
ORJSONResponse
を使う¶
例えば、パフォーマンスを出したい場合は、orjson
をインストールし、ORJSONResponse
をレスポンスとしてセットすることができます。
使いたい Response
クラス (サブクラス) をインポートし、 path operationデコレータ に宣言します。
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
app = FastAPI()
@app.get("/items/", response_class=ORJSONResponse)
async def read_items():
return ORJSONResponse([{"item_id": "Foo"}])
情報
パラメータ response_class
は、レスポンスの「メディアタイプ」を定義するために利用することもできます。
この場合、HTTPヘッダー Content-Type
には application/json
がセットされます。
そして、OpenAPIにはそのようにドキュメントされます。
豆知識
ORJSONResponse
は、現在はFastAPIのみで利用可能で、Starletteでは利用できません。
HTMLレスポンス¶
FastAPI からHTMLを直接返す場合は、HTMLResponse
を使います。
HTMLResponse
をインポートする。- path operation のパラメータ
content_type
にHTMLResponse
を渡す。
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/items/", response_class=HTMLResponse)
async def read_items():
return """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
情報
パラメータ response_class
は、レスポンスの「メディアタイプ」を定義するために利用されます。
この場合、HTTPヘッダー Content-Type
には text/html
がセットされます。
そして、OpenAPIにはそのようにドキュメント化されます。
Response
を返す¶
レスポンスを直接返すで見たように、レスポンスを直接返すことで、path operation の中でレスポンスをオーバーライドできます。
上記と同じ例において、 HTMLResponse
を返すと、このようになります:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/items/")
async def read_items():
html_content = """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)
注意
path operation関数 から直接返される Response
は、OpenAPIにドキュメントされず (例えば、 Content-Type
がドキュメントされない) 、自動的な対話的ドキュメントからも閲覧できません。
情報
もちろん、実際の Content-Type
ヘッダーやステータスコードなどは、返された Response
オブジェクトに由来しています。
OpenAPIドキュメントと Response
のオーバーライド¶
関数の中でレスポンスをオーバーライドしつつも、OpenAPI に「メディアタイプ」をドキュメント化したいなら、 response_class
パラメータを使い、 Response
オブジェクトを返します。
response_class
はOpenAPIの path operation ドキュメントにのみ使用されますが、 Response
はそのまま使用されます。
HTMLResponse
を直接返す¶
例えば、このようになります:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
def generate_html_response():
html_content = """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)
@app.get("/items/", response_class=HTMLResponse)
async def read_items():
return generate_html_response()
この例では、関数 generate_html_response()
は、str
のHTMLを返すのではなく Response
を生成して返しています。
generate_html_response()
を呼び出した結果を返すことにより、FastAPI の振る舞いを上書きする Response
が既に返されています。
しかし、一方では response_class
に HTMLResponse
を渡しているため、 FastAPI はOpenAPIや対話的ドキュメントでHTMLとして text/html
でドキュメント化する方法を知っています。
利用可能なレスポンス¶
以下が利用可能なレスポンスの一部です。
Response
を使って他の何かを返せますし、カスタムのサブクラスも作れることを覚えておいてください。
技術詳細
from starlette.responses import HTMLResponse
も利用できます。
FastAPI は開発者の利便性のために fastapi.responses
として starlette.responses
と同じものを提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。
Response
¶
メインの Response
クラスで、他の全てのレスポンスはこれを継承しています。
直接返すことができます。
以下のパラメータを受け付けます。
content
-str
かbytes
。status_code
-int
のHTTPステータスコード。headers
- 文字列のdict
。media_type
- メディアタイプを示すstr
。例えば"text/html"
。
FastAPI (実際にはStarlette) は自動的にContent-Lengthヘッダーを含みます。また、media_typeに基づいたContent-Typeヘッダーを含み、テキストタイプのためにcharsetを追加します。
from fastapi import FastAPI, Response
app = FastAPI()
@app.get("/legacy/")
def get_legacy_data():
data = """<?xml version="1.0"?>
<shampoo>
<Header>
Apply shampoo here.
</Header>
<Body>
You'll have to use soap here.
</Body>
</shampoo>
"""
return Response(content=data, media_type="application/xml")
HTMLResponse
¶
上で読んだように、テキストやバイトを受け取り、HTMLレスポンスを返します。
PlainTextResponse
¶
テキストやバイトを受け取り、プレーンテキストのレスポンスを返します。
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse
app = FastAPI()
@app.get("/", response_class=PlainTextResponse)
async def main():
return "Hello World"
JSONResponse
¶
データを受け取り、 application/json
としてエンコードされたレスポンスを返します。
上で読んだように、FastAPI のデフォルトのレスポンスとして利用されます。
ORJSONResponse
¶
上で読んだように、orjson
を使った、高速な代替のJSONレスポンスです。
UJSONResponse
¶
ujson
を使った、代替のJSONレスポンスです。
注意
ujson
は、いくつかのエッジケースの取り扱いについて、Pythonにビルトインされた実装よりも作りこまれていません。
from fastapi import FastAPI
from fastapi.responses import UJSONResponse
app = FastAPI()
@app.get("/items/", response_class=UJSONResponse)
async def read_items():
return [{"item_id": "Foo"}]
豆知識
ORJSONResponse
のほうが高速な代替かもしれません。
RedirectResponse
¶
HTTPリダイレクトを返します。デフォルトでは307ステータスコード (Temporary Redirect) となります。
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get("/typer")
async def redirect_typer():
return RedirectResponse("https://typer.tiangolo.com")
StreamingResponse
¶
非同期なジェネレータか通常のジェネレータ・イテレータを受け取り、レスポンスボディをストリームします。
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
async def fake_video_streamer():
for i in range(10):
yield b"some fake video bytes"
@app.get("/")
async def main():
return StreamingResponse(fake_video_streamer())
StreamingResponse
をファイルライクなオブジェクトとともに使う¶
ファイルライクなオブジェクト (例えば、 open()
で返されたオブジェクト) がある場合、 StreamingResponse
に含めて返すことができます。
これにはクラウドストレージとの連携や映像処理など、多くのライブラリが含まれています。
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
some_file_path = "large-video-file.mp4"
app = FastAPI()
@app.get("/")
def main():
def iterfile(): # (1)
with open(some_file_path, mode="rb") as file_like: # (2)
yield from file_like # (3)
return StreamingResponse(iterfile(), media_type="video/mp4")
豆知識
ここでは async
や await
をサポートしていない標準の open()
を使っているので、通常の def
でpath operationを宣言していることに注意してください。
FileResponse
¶
レスポンスとしてファイルを非同期的にストリームします。
他のレスポンスタイプとは異なる引数のセットを受け取りインスタンス化します。
path
- ストリームするファイルのファイルパス。headers
- 含めたい任意のカスタムヘッダーの辞書。media_type
- メディアタイプを示す文字列。セットされなかった場合は、ファイル名やパスからメディアタイプが推察されます。filename
- セットされた場合、レスポンスのContent-Disposition
に含まれます。
ファイルレスポンスには、適切な Content-Length
、 Last-Modified
、 ETag
ヘッダーが含まれます。
from fastapi import FastAPI
from fastapi.responses import FileResponse
some_file_path = "large-video-file.mp4"
app = FastAPI()
@app.get("/")
async def main():
return FileResponse(some_file_path)
デフォルトレスポンスクラス¶
FastAPI クラスのインスタンスか APIRouter
を生成するときに、デフォルトのレスポンスクラスを指定できます。
定義するためのパラメータは、 default_response_class
です。
以下の例では、 FastAPI は、全ての path operation で JSONResponse
の代わりに ORJSONResponse
をデフォルトとして利用します。
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
app = FastAPI(default_response_class=ORJSONResponse)
@app.get("/items/")
async def read_items():
return [{"item_id": "Foo"}]
豆知識
前に見たように、 path operation の中で response_class
をオーバーライドできます。
その他のドキュメント¶
また、OpenAPIでは responses
を使ってメディアタイプやその他の詳細を宣言することもできます: Additional Responses in OpenAPI