FastAPIでデータを返す方法:Responseオブジェクト徹底解説
FastAPIは、PythonでAPIを迅速に構築するための、モダンで高性能なWebフレームワークです。その大きな魅力の一つは、開発者がAPIエンドポイントからPythonの標準的なデータ型(辞書、リスト、Pydanticモデルなど)を返すだけで、自動的にJSONレスポンスを生成してくれる手軽さにあります。しかし、Web APIの世界はJSONだけではありません。HTMLページを返したり、プレーンテキストを返したり、ファイルをダウンロードさせたり、ストリーミングデータを提供したり、カスタムヘッダーやクッキーを設定したり、特定のHTTPステータスコードを返したりする必要も出てきます。
このような、より高度なレスポンス制御を実現するために、FastAPIはResponse
オブジェクトとその派生クラスを提供しています。本記事では、FastAPIにおけるResponse
オブジェクトの役割、使い方、そして様々な派生クラス(JSONResponse
, PlainTextResponse
, HTMLResponse
, RedirectResponse
, StreamingResponse
, FileResponse
など)を徹底的に解説します。約5000語をかけて、それぞれのクラスの詳細、主要なパラメータ、実践的な使用例、そしてResponse
オブジェクトがFastAPIの他の機能(response_model
, response_class
, 依存性注入など)とどのように連携するのかを深く掘り下げていきます。
FastAPIのデフォルトの挙動を超えた、より柔軟でパワフルなAPIレスポンスの構築方法をマスターしましょう。
1. FastAPIのデフォルトの挙動:手軽なJSONレスポンス
FastAPIの最も基本的な使い方では、APIエンドポイントの関数(パスオペレーション関数)からPythonのデータを返すだけで十分です。FastAPIは賢く、返されたデータを理解し、適切なHTTPレスポンスに変換します。
例えば、以下のようなコードは非常に一般的です。
“`python
from fastapi import FastAPI
app = FastAPI()
@app.get(“/items/{item_id}”)
def read_item(item_id: int):
“””
アイテム情報を返すシンプルなエンドポイント
“””
return {“item_id”: item_id, “name”: “Awesome Item”}
“`
この例では、Pythonの辞書{"item_id": item_id, "name": "Awesome Item"}
を返しています。FastAPIは、この辞書を自動的にJSON形式の文字列に変換し、HTTPレスポンスのボディとして送信します。
デフォルトの変換ルール:
- Python Dict/List:
jsonable_encoder
を使用してJSONに変換されます。これは、標準的なPythonデータ型(str
,int
,float
,bool
,None
,list
,dict
)に加えて、Pydanticモデル、datetimeオブジェクト、UUIDなどをJSON互換の形式に変換できるFastAPIの内部ユーティリティです。 - Pydanticモデル: モデルの
.dict()
メソッドや.json()
メソッドが使用され、バリデーション済みのデータがJSONに変換されます。 - その他のデータ型: Pydanticモデル以外でも、標準的なPythonデータ型は適切にJSONエンコードされます。
デフォルトのステータスコードとヘッダー:
- 成功時のデフォルトのステータスコードは
200 OK
です。 - デフォルトの
Content-Type
ヘッダーは通常application/json
に設定されます。 - FastAPIは、必要に応じて他のヘッダー(例:
Content-Length
)も自動的に追加します。
このデフォルトの挙動は、JSON APIを素早く構築する上で非常に便利です。しかし、前述の通り、JSON以外のレスポンスや、より詳細なレスポンス制御が必要な場合は、明示的にResponse
オブジェクトを使用する必要があります。
2. なぜ明示的にResponse
オブジェクトを使う必要があるのか?
FastAPIのデフォルトの挙動は素晴らしいですが、すべてに対応できるわけではありません。以下のようなシナリオでは、明示的にResponse
オブジェクトを作成して返すことが不可欠または推奨されます。
-
JSON以外のデータを返したい:
- HTMLページを返す (
text/html
) - プレーンテキストを返す (
text/plain
) - CSVファイルやその他のテキストファイルを返す
- XMLを返す (
application/xml
) - 画像、音声、動画などのバイナリデータを返す
- PDFファイルなどのドキュメントを返す
- HTMLページを返す (
-
カスタムヘッダーを設定したい:
Cache-Control
ヘッダーを設定してキャッシュを制御するContent-Disposition
ヘッダーを設定してファイルダウンロードを強制する- オリジン間リソース共有(CORS)に関連するヘッダー(
Access-Control-...
)を設定する(通常はFastAPIのCORSミドルウェアを使用しますが、特定のレスポンスに対して手動で設定する場合) - カスタムのアプリケーション固有のヘッダーを追加する
-
クッキー(Cookies)を設定または削除したい:
- ユーザー認証情報やセッション情報を保持するクッキーを発行する
- 不要になったクッキーを削除する
-
デフォルトとは異なるHTTPステータスコードを返したい:
201 Created
(リソース作成成功)204 No Content
(成功したがレスポンスボディがない)400 Bad Request
(クライアントエラー、通常はHTTPException
を使用しますが、カスタムエラーレスポンスボディが必要な場合)404 Not Found
(リソースが見つからない、通常はHTTPException
を使用しますが、カスタムエラーレスポンスボディが必要な場合)301 Moved Permanently
または307 Temporary Redirect
(リダイレクト)
-
大きなデータや動的に生成されるデータをストリーミングしたい:
- 非常に大きなファイルを少しずつ送信する
- サーバーセントイベント (SSE) のようなリアルタイムに近いデータストリームを送信する
- 動画や音声などのメディアストリームを送信する
-
静的ファイルを効率的に提供したい:
- ディスク上のファイルを直接、かつ効率的にブラウザに送信する
-
特定のシリアライゼーション(例: UJSON)を使用したい:
- 標準の
json
ライブラリよりも高速なJSONシリアライザを使用する場合
- 標準の
これらのシナリオでは、単にPythonデータを返すだけではFastAPIが意図した通りのレスポンスを生成できません。代わりに、FastAPIが提供するResponse
クラスやその派生クラスのインスタンスを明示的に作成し、パスオペレーション関数から返す必要があります。
3. コアとなるResponse
クラスとその主要パラメータ
FastAPIでレスポンスを制御するための基盤となるのが、fastapi.responses
モジュールにあるResponse
クラスです。そして、その用途に応じた多くの派生クラスが存在します。
すべてのResponse
クラスは、少なくとも以下の主要なパラメータを受け取ることができます(クラスによっては特定のパラメータが必須であったり、追加のパラメータがあったりします)。
content
: レスポンスボディとして送信するデータ。これはバイト列(bytes
)である必要があります。文字列を指定した場合、FastAPIはデフォルトでUTF-8エンコーディングを使用してバイト列に変換します。status_code
: HTTPステータスコード。int
型で指定します。fastapi.status
モジュールには、よく使われるステータスコードの定数が用意されています(例:status.HTTP_200_OK
,status.HTTP_404_NOT_FOUND
)。headers
: レスポンスに含めるHTTPヘッダー。Dict[str, str]
型で指定します。キーと値は文字列である必要があります。media_type
: レスポンスボディのメディアタイプ(MIMEタイプ)。str
型で指定します(例:"application/json"
,"text/html"
,"image/png"
,"application/octet-stream"
)。これを指定しない場合、FastAPIはレスポンスクラスの種類やコンテンツから推測しようとしますが、明示的に指定するのが安全です。これはレスポンスのContent-Type
ヘッダーになります。
これらのパラメータを理解することが、様々なResponse
オブジェクトを使いこなす鍵となります。
4. 様々なResponse
派生クラスの詳細と使い方
FastAPIは、一般的なWeb開発のニーズに応えるために、いくつかの便利なResponse
派生クラスを提供しています。これらは基本的なResponse
クラスを継承し、特定のメディアタイプの設定や、コンテンツの型に応じた自動的なバイト列変換などの機能を追加しています。
4.1. JSONResponse
最も頻繁に使用される派生クラスの一つです。FastAPIのデフォルト挙動は実質的にこれを使っています。明示的に使うのは、カスタムヘッダーやステータスコードを設定しつつJSONデータを返したい場合などです。
- クラス:
fastapi.responses.JSONResponse
- 主な機能: Pythonのデータ構造(辞書、リスト、Pydanticモデルなど)を受け取り、自動的にJSON文字列にシリアライズしてバイト列に変換します。
media_type
はデフォルトでapplication/json
になります。 - コンストラクタパラメータ:
content
: JSONシリアライズ可能なPythonデータ構造。status_code
: HTTPステータスコード(デフォルト: 200)。headers
: カスタムヘッダー(デフォルト: None)。media_type
: メディアタイプ(デフォルト:application/json
)。通常は変更しません。encoder
: JSONエンコードに使用するカスタム関数(オプション)。json_dumps
: JSON文字列化に使用するカスタム関数(オプション)。
使用例:
“`python
from fastapi import FastAPI, status
from fastapi.responses import JSONResponse
app = FastAPI()
@app.get(“/custom-json”)
def custom_json_response():
“””
カスタムヘッダーとステータスコードを持つJSONレスポンス
“””
content = {“message”: “Hello from custom JSON”, “status”: “ok”}
headers = {“X-Custom-Header”: “SomeValue”, “Cache-Control”: “no-cache”}
return JSONResponse(content=content, status_code=status.HTTP_200_OK, headers=headers)
@app.post(“/created-resource”, status_code=status.HTTP_201_CREATED) # デコレータでもステータス設定可能だが、Responseでも可能
def create_resource():
# … リソース作成ロジック …
new_resource_info = {“id”: “abc123”, “url”: “/resources/abc123”}
# ここではstatus_code=201がデコレータで設定されているが、
# Responseオブジェクトで上書きすることも可能
return JSONResponse(
content=new_resource_info,
status_code=status.HTTP_201_CREATED, # 明示的に指定
headers={“Location”: “/resources/abc123”} # Locationヘッダーは201でよく使われる
)
“`
JSONResponse
は、カスタムヘッダーやステータスコードを設定したい場合に、デフォルトのJSON挙動を維持するための明確な方法を提供します。
4.2. PlainTextResponse
シンプルなテキストデータを返したい場合に使用します。
- クラス:
fastapi.responses.PlainTextResponse
- 主な機能: 文字列(
str
)を受け取り、UTF-8エンコーディングでバイト列に変換します。media_type
はデフォルトでtext/plain
になります。 - コンストラクタパラメータ:
content
: 返す文字列。status_code
: HTTPステータスコード(デフォルト: 200)。headers
: カスタムヘッダー(デフォルト: None)。media_type
: メディアタイプ(デフォルト:text/plain
)。
使用例:
“`python
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse
app = FastAPI()
@app.get(“/hello-text”, response_class=PlainTextResponse) # response_classを指定すると、文字列を返した場合にこれが使われる
def hello_text():
“””
プレーンテキストを返すエンドポイント
“””
# return “Hello, world!” # response_class=PlainTextResponse があればこれでOK
return PlainTextResponse(content=”Hello, world!\nThis is a plain text response.”)
@app.get(“/current-time”)
def current_time():
“””
現在の時間をプレーンテキストで返す
“””
from datetime import datetime
now = datetime.now().strftime(“%Y-%m-%d %H:%M:%S”)
return PlainTextResponse(content=f”Current time: {now}”, headers={“X-Source”: “FastAPI”})
“`
PlainTextResponse
は、ログ出力や簡単なステータス確認など、APIが厳密な構造を持たないテキストを返すのに適しています。
4.3. HTMLResponse
HTMLコンテンツを返したい場合に使用します。
- クラス:
fastapi.responses.HTMLResponse
- 主な機能: 文字列(
str
)としてHTMLコンテンツを受け取り、UTF-8エンコーディングでバイト列に変換します。media_type
はデフォルトでtext/html
になります。 - コンストラクタパラメータ:
content
: 返すHTML文字列。status_code
: HTTPステータスコード(デフォルト: 200)。headers
: カスタムヘッダー(デフォルト: None)。media_type
: メディアタイプ(デフォルト:text/html
)。
使用例:
“`python
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get(“/html-page”, response_class=HTMLResponse) # response_classを指定すると、文字列を返した場合にこれが使われる
def html_page():
“””
シンプルなHTMLページを返すエンドポイント
“””
html_content = “””
<!DOCTYPE html>
Hello from FastAPI!
This is an HTML response.
“””
# return html_content # response_class=HTMLResponse があればこれでOK
return HTMLResponse(content=html_content, status_code=200)
@app.get(“/item-details/{item_id}”, response_class=HTMLResponse)
def item_details_html(item_id: int):
“””
アイテム詳細をHTMLで表示(簡易版)
“””
item_name = f”Item {item_id}”
item_description = f”Details for item {item_id}.”
html_content = f”””
<!DOCTYPE html>
{item_name}
{item_description}
Back to HTML example
“””
return HTMLResponse(content=html_content)
“`
HTMLResponse
は、サーバーサイドレンダリングされたHTMLを返す場合や、簡単なランディングページをAPIと一緒にホストする場合などに便利です。ただし、大規模なテンプレートレンダリングにはJinja2などのテンプレートエンジンと連携させるのが一般的です(FastAPIはこれらのテンプレートエンジンとの統合もサポートしています)。
4.4. RedirectResponse
クライアントを別のURLにリダイレクトさせたい場合に使用します。
- クラス:
fastapi.responses.RedirectResponse
- 主な機能:
Location
ヘッダーをセットし、適切なリダイレクトステータスコード(デフォルトは307 Temporary Redirect
)を返します。 - コンストラクタパラメータ:
url
: リダイレクト先のURL(str
型)。status_code
: リダイレクトのステータスコード(デフォルト:307 Temporary Redirect
)。よく使われるのは301 Moved Permanently
,302 Found
,303 See Other
,307 Temporary Redirect
,308 Permanent Redirect
です。301
や308
は永続的な移動を示し、ブラウザがそのURLをキャッシュする可能性があります。302
,303
,307
は一時的なリダイレクトです。303
は通常、POSTリクエスト後のリダイレクトに使用され、リダイレクト先のURLにはGETリクエストが送信されます。headers
: カスタムヘッダー(デフォルト: None)。
使用例:
“`python
from fastapi import FastAPI
from fastapi.responses import RedirectResponse, HTMLResponse
from fastapi import status
app = FastAPI()
@app.get(“/docs”)
def redirect_to_docs():
“””
/docsから/docs/にリダイレクト
“””
return RedirectResponse(url=”/docs/”) # デフォルトは307
@app.get(“/external”)
def redirect_to_external():
“””
外部サイトに永続的にリダイレクト
“””
return RedirectResponse(url=”https://fastapi.tiangolo.com/”, status_code=status.HTTP_301_MOVED_PERMANENTLY)
@app.post(“/login”)
def login_user(username: str, password: str):
“””
ログイン処理後、成功したらダッシュボードにリダイレクト
“””
# … ログイン認証ロジック …
if username == “test” and password == “secret”:
# 認証成功。POSTリクエスト後にGETリクエストとしてリダイレクトするには303 See Otherが良い
return RedirectResponse(url=”/dashboard”, status_code=status.HTTP_303_SEE_OTHER)
else:
# 認証失敗。エラーページを表示
# Note: 認証失敗は通常HTTPExceptionを使う方が良いが、例としてHTMLを返す
return HTMLResponse(content=”
Login Failed
Invalid credentials.
“, status_code=status.HTTP_401_UNAUTHORIZED)
@app.get(“/dashboard”)
def dashboard_page():
“””
ダッシュボードページ(簡易版)
“””
return HTMLResponse(content=”
Welcome to the Dashboard!
“)
“`
リダイレクトは、URL構造の変更、認証後の遷移、または一時的なリソースの移動などに広く使用されます。適切なステータスコードを選択することが重要です。
4.5. StreamingResponse
大きなデータや動的に生成されるデータを少しずつクライアントに送信(ストリーミング)したい場合に使用します。これは特に、ファイルのダウンロード、リアルタイムのデータフィード、Server-Sent Events (SSE)などに役立ちます。
- クラス:
fastapi.responses.StreamingResponse
- 主な機能: コンテンツとして非同期イテレータまたはジェネレータを受け取り、そのイテレータ/ジェネレータが生成するチャンクを逐次的にレスポンスボディとして送信します。これにより、データをすべてメモリにロードすることなく、大きなデータを効率的に扱うことができます。
- コンストラクタパラメータ:
content
: 非同期イテレータ、イテレータ(ジェネレータ)、またはファイルライクオブジェクト。生成される要素はバイト列(bytes
)または文字列(str
、この場合はUTF-8でエンコードされる)である必要があります。status_code
: HTTPステータスコード(デフォルト: 200)。headers
: カスタムヘッダー(デフォルト: None)。特にファイルダウンロードではContent-Disposition
ヘッダーが重要です。media_type
: レスポンスボディのメディアタイプ。ストリーミングのタイプによって適切に設定する必要があります(例: ファイルダウンロードならapplication/octet-stream
、動画ならvideo/mp4
、SSEならtext/event-stream
)。
使用例1: 大きなファイルのストリーミングダウンロード
“`python
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from fastapi import Header # ヘッダーを使うため
app = FastAPI()
ダミーの巨大ファイルを作成 (実際のアプリケーションでは既存のファイルを使用)
def create_dummy_large_file(filename=”large_dummy_file.txt”, size_mb=100):
“””指定サイズのダミーファイルを生成”””
size_bytes = size_mb * 1024 * 1024
chunk_size = 1024 * 1024 # 1MB chunks
content = b”a” * (chunk_size) # Write 1MB ‘a’s at a time
with open(filename, “wb”) as f:
written = 0
while written < size_bytes:
f.write(content)
written += chunk_size
print(f”Written {written}/{size_bytes} bytes”)
print(f”Dummy file ‘{filename}’ ({size_mb}MB) created.”)
ファイル生成 (必要に応じて一度だけ実行)
create_dummy_large_file()
async def generate_file_chunks(filename=”large_dummy_file.txt”, chunk_size=1024*1024):
“””ファイルをチャンクごとに読み込むジェネレータ”””
print(f”Opening file: {filename}”)
try:
with open(filename, “rb”) as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
# print(f”Read {len(chunk)} bytes”)
yield chunk
except FileNotFoundError:
print(f”File not found: {filename}”)
# yield bytes() # Empty yield to signal end/error
raise # Re-raise the exception to be handled by FastAPI/middlewares if needed
finally:
print(f”Finished streaming file: {filename}”)
@app.get(“/download-large-file”)
async def download_large_file():
“””
StreamingResponseを使用して大きなファイルをダウンロードさせる
“””
file_path = “large_dummy_file.txt”
try:
# ファイルサイズを取得 (Content-Lengthヘッダーに必要)
import os
file_size = os.path.getsize(file_path)
# Content-Dispositionヘッダーを設定してダウンロードファイル名を指定
headers = {
'Content-Disposition': 'attachment; filename="downloaded_large_file.txt"',
'Content-Length': str(file_size) # ファイルサイズヘッダー
}
# ジェネレータを渡す
return StreamingResponse(generate_file_chunks(file_path), media_type="application/octet-stream", headers=headers)
except FileNotFoundError:
# ファイルが見つからない場合はエラーレスポンス
from fastapi import HTTPException
raise HTTPException(status_code=404, detail="File not found")
except Exception as e:
from fastapi import HTTPException
raise HTTPException(status_code=500, detail=f"Error streaming file: {e}")
“`
この例では、generate_file_chunks
というジェネレータ関数がファイルのチャンクを読み込み、StreamingResponse
はそのチャンクをクライアントに送信します。これにより、ファイル全体をメモリに読み込む必要がなく、効率的なダウンロードが可能になります。Content-Disposition
ヘッダーは、ブラウザにファイルをダウンロードさせること、およびダウンロード時のファイル名を指示します。Content-Length
ヘッダーは、ダウンロード進行状況の表示などに役立ちます。
使用例2: Server-Sent Events (SSE)
“`python
import asyncio
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
async def event_generator():
“””SSEイベントを生成する非同期ジェネレータ”””
count = 0
while count < 5: # 例として5回だけイベントを送信
message = f”data: This is event {count}\n\n” # SSEフォーマット
print(f”Sending SSE: {message.strip()}”)
yield message.encode(‘utf-8’) # バイト列でyield
count += 1
await asyncio.sleep(1) # 1秒待機
print(“Finished sending SSE events.”)
# yield b”data: end\n\n” # 終了を示すイベント(クライアント側で処理可能)
@app.get(“/stream-events”)
async def stream_events():
“””
Server-Sent Events (SSE) をストリーミングする
“””
headers = {
“Cache-Control”: “no-cache”,
“Connection”: “keep-alive”,
“Content-Type”: “text/event-stream”, # SSEのメディアタイプ
}
# 非同期ジェネレータを渡す
return StreamingResponse(event_generator(), media_type=”text/event-stream”, headers=headers)
クライアント側(ブラウザのJavaScriptなど)は EventSource API を使って接続します
例: const eventSource = new EventSource(“/stream-events”);
eventSource.onmessage = function(event) { console.log(event.data); };
“`
SSEでは、media_type
をtext/event-stream
に設定し、コンテンツはdata: ...\n\n
のようなSSEフォーマットで生成する必要があります。非同期ジェネレータを使うことで、await
を使って非同期処理(例: 待機、データベースからのポーリングなど)を挟むことができ、ノンブロッキングなストリーミングが可能になります。
StreamingResponse
を使う際は、提供するイテレータ/ジェネレータがバイト列を生成すること、そして適切なmedia_type
を設定することが非常に重要です。また、ジェネレータ内でブロッキングI/O(例: 同期的なファイル読み込みやネットワーク呼び出し)を行うと、アプリケーション全体のパフォーマンスが低下する可能性があるため、非同期I/O (asyncio
) を使用するか、ThreadPoolExecutorなどでラップすることを検討してください。上記のファイルストリーミング例では、簡単のために同期I/O (open().read()
) を使っていますが、実運用ではaiofiles
のような非同期ファイルライブラリを使うべきです。
4.6. FileResponse
静的なファイルを効率的にクライアントに送信したい場合に使用します。StreamingResponse
と似ていますが、こちらはディスク上の 既存 のファイルを送信することに特化しており、より最適化されています。範囲リクエスト (Range requests) にも対応しており、動画や音声などのシーク可能なメディアファイルの提供に適しています。
- クラス:
fastapi.responses.FileResponse
- 主な機能: 指定されたパスのファイルをレスポンスとして送信します。ファイルのMIMEタイプを自動的に推測しようとします。範囲リクエストを自動的に処理します。
- コンストラクタパラメータ:
path
: 送信するファイルのファイルシステム上のパス(str
またはPath
オブジェクト)。status_code
: HTTPステータスコード(デフォルト: 200)。headers
: カスタムヘッダー(デフォルト: None)。Content-Disposition
などを追加できます。media_type
: メディアタイプ。指定しない場合はファイル名から推測します。filename
: クライアントへのダウンロード時のファイル名。Content-Disposition
ヘッダーを自動的に設定します。stat_result
: ファイルのstat結果。パフォーマンス向上のために事前にos.stat(path)
を実行して渡すことができます。method
: HTTPメソッド。通常はFastAPIが自動的に設定しますが、手動で指定することも可能です。background
: レスポンス送信完了後に実行するBackgroundTasks
オブジェクト。ファイルディスクリプタを閉じるなどのクリーンアップ処理に使用できます。
使用例:
“`python
from fastapi import FastAPI, BackgroundTasks
from fastapi.responses import FileResponse
app = FastAPI()
ダミーファイル作成 (例: 画像ファイル)
Pillowがあれば画像ファイルを作成する例
try:
from PIL import Image, ImageDraw
import os
def create_dummy_image(filename="dummy_image.png"):
"""シンプルなダミー画像ファイルを作成"""
if not os.path.exists(filename):
img = Image.new('RGB', (60, 30), color = 'red')
d = ImageDraw.Draw(img)
d.text((10,10), "Hello", fill=(255,255,0))
img.save(filename)
print(f"Dummy image '{filename}' created.")
create_dummy_image()
except ImportError:
print(“Pillow not installed. Skipping dummy image creation. Install with ‘pip install Pillow'”)
# Pillowがない場合は適当なテキストファイルを代わりに作成
def create_dummy_text_file(filename=”dummy_file.txt”):
if not os.path.exists(filename):
with open(filename, “w”) as f:
f.write(“This is a dummy text file.\n”)
f.write(“It can be served using FileResponse.\n”)
print(f”Dummy text file ‘{filename}’ created.”)
create_dummy_text_file()
@app.get(“/static-image”)
async def get_static_image():
“””
静的な画像をFileResponseで返す
“””
file_path = “dummy_image.png”
# FileResponseはMIMEタイプを自動推測しようとします
# filenameを指定すると、Content-Dispositionヘッダーが自動的に設定されます
return FileResponse(path=file_path, filename=”hello_image.png”)
@app.get(“/static-file”)
async def get_static_file():
“””
静的なファイルをFileResponseで返す(ダウンロード)
“””
file_path = “dummy_file.txt”
# filenameを指定しない場合は、ブラウザはContent-Typeに基づいて表示/ダウンロードを判断
# return FileResponse(path=file_path)
# filenameを指定してダウンロードを強制し、ダウンロード時のファイル名を指定
return FileResponse(path=file_path, filename="downloaded_text_file.txt", media_type="text/plain")
BackgroundTasksを使用する例
def cleanup_file(path: str):
“””ファイルを削除するバックグラウンドタスク”””
print(f”Cleaning up file: {path}”)
import os
os.remove(path)
@app.get(“/temporary-file”)
async def get_temporary_file(background_tasks: BackgroundTasks):
“””
一時的なファイルを生成し、送信後に削除する
“””
# 実際にはここで一時ファイルを生成するロジックが入る
temp_file_path = “temp_report.csv”
with open(temp_file_path, “w”) as f:
f.write(“ID,Name\n”)
f.write(“1,Alice\n”)
f.write(“2,Bob\n”)
# レスポンス送信完了後にファイルを削除するタスクを追加
background_tasks.add_task(cleanup_file, temp_file_path)
# ファイルを送信
return FileResponse(
path=temp_file_path,
filename="report.csv",
media_type="text/csv" # CSVのMIMEタイプを指定
)
“`
FileResponse
は、ウェブサイトの静的アセット(画像、CSS、JS)、生成されたレポートファイル、またはメディアファイルなど、サーバーに存在するファイルを効率的に提供するのに最適です。background_tasks
引数を使用すると、レスポンスがクライアントに送信された後にファイルのクリーンアップなどの処理を実行できます。これは特に一時ファイルを扱う場合に便利です。
4.7. その他のレスポンスクラス
FastAPIは他にもいくつかのレスポンスクラスを提供しています。
UJSONResponse
:ujson
ライブラリを使用してJSONを高速にシリアライズするJSONResponse
の代替です。ujson
をインストールしている場合に使用できます。ORJSONResponse
:orjson
ライブラリを使用してJSONを高速にシリアライズするJSONResponse
の代替です。orjson
は非常に高速で、複雑なデータ型もサポートします。orjson
をインストールしている場合に使用できます。XMLResponse
: XMLコンテンツを返すためのクラス。文字列としてXMLを受け取り、media_type
はデフォルトでapplication/xml
またはtext/xml
になります。
これらのレスポンスクラスは、特定のライブラリを使いたい場合や、特定のメディアタイプを扱う場合に選択肢となります。
5. Response
オブジェクトとFastAPIの他の機能との連携
Response
オブジェクトは単独で使うだけでなく、FastAPIの強力な他の機能と組み合わせて使うことで、さらに柔軟なレスポンス制御が可能になります。
5.1. response_class
パラメータ
ルートデコレータ(@app.get()
, @app.post()
など)のresponse_class
パラメータを使用すると、そのルートのデフォルトのレスポンスクラスを指定できます。
“`python
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse, HTMLResponse
app = FastAPI()
@app.get(“/text”, response_class=PlainTextResponse)
def get_text():
“””
このルートはデフォルトでPlainTextResponseを使用
文字列を返すと自動的にPlaintextになる
“””
return “This is text.” # response_class=PlainTextResponseが適用される
@app.get(“/html”, response_class=HTMLResponse)
def get_html():
“””
このルートはデフォルトでHTMLResponseを使用
文字列を返すと自動的にHTMLになる
“””
return “
This is HTML.
” # response_class=HTMLResponseが適用される
@app.get(“/override”)
def override_response_class():
“””
デフォルトはJSONResponseだが、PlainTextResponseで上書き
“””
# ここではresponse_classを指定していないので、デフォルトのJSONResponseが期待されるが、
# 明示的にPlainTextResponseオブジェクトを返すことでそれを上書きできる
return PlainTextResponse(content=”This overrides the default JSON response.”)
“`
response_class
を設定しておくと、パスオペレーション関数が単なるデータ(辞書、Pydanticモデル、文字列など)を返した場合に、指定したレスポンスクラスを使ってシリアライズが行われます。これは、特定のルートで一貫して非JSONレスポンスを返したい場合に便利です。
重要な注意点: パスオペレーション関数が 明示的に Response
オブジェクトのインスタンス(例: return HTMLResponse(...)
)を返した場合、その返されたオブジェクトが使用されます。response_class
パラメータは、関数が Response
オブジェクトではない 値を返した場合のデフォルトのレスポンスクラスとして機能します。また、返されたResponse
オブジェクトのクラスがresponse_class
と 異なる 場合でも、返されたオブジェクトが優先されます。
5.2. response_model
パラメータとResponse
オブジェクトの組み合わせ
ルートデコレータのresponse_model
パラメータは、レスポンスボディのデータスキーマを定義し、以下の機能を提供します。
- レスポンスデータのアウトプットバリデーション(
response_model
で定義されたPydanticモデルに従っているか) - レスポンスデータのシリアライゼーション(Pydanticモデルに変換し、JSONなどにエンコード)
- APIドキュメント(OpenAPIスキーマ)でのレスポンスボディの定義
では、response_model
と明示的なResponse
オブジェクトはどのように連携するのでしょうか? これはFastAPIで少し混乱しやすい部分なので、明確にしておきましょう。
ルール:
- パスオペレーション関数が 明示的に
Response
オブジェクト を返した場合、response_model
によるレスポンスボディのバリデーションやシリアライゼーションは行われません。返されたResponse
オブジェクトのcontent
、media_type
、status_code
、headers
がそのまま使用されます。 - ただし、
response_model
で定義されたAPIドキュメント(OpenAPIスキーマ)は引き続き生成されます。これは、APIの利用者に対して、そのエンドポイントがどのような 構造 のデータを返すことを意図しているかを示すために重要です。 response_class
パラメータが設定されている場合、APIドキュメントではresponse_model
のスキーマがresponse_class
のmedia_type
を使って定義されます。例えば、response_model=MyModel
かつresponse_class=HTMLResponse
の場合、ドキュメント上はMyModel
の構造がtext/html
形式で返されると表示されます(これは実際にはFastAPIがMyModel
をHTMLに自動変換するわけではないため、誤解を招く可能性があります。通常、response_class
とresponse_model
を組み合わせる場合は、カスタムのエンコーダー/レスポンスクラスを用意する必要があります)。- 最も一般的なパターンは、デフォルトのJSONレスポンスでは
response_model
を使ってデータ構造を定義しつつ、特定のケース(ファイルダウンロード、リダイレクト、エラーなど)でresponse_model
をバイパスして 明示的なResponse
オブジェクトを返す、というものです。
例:
“`python
from fastapi import FastAPI, HTTPException, status
from fastapi.responses import JSONResponse, HTMLResponse, FileResponse
from pydantic import BaseModel
import os
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.get(“/items/{item_id}”, response_model=Item)
def read_item(item_id: str):
“””
response_modelを使ってJSONレスポンスのスキーマを定義
“””
# 通常のデータ(辞書)を返すと、これがresponse_modelに基づいてバリデーション&JSON化される
if item_id == “foo”:
return {“name”: “Foo”, “price”: 50.2}
elif item_id == “bar”:
return {“name”: “Bar”, “description”: “The Bar fighters”, “price”: 62.0, “tax”: 20.2}
else:
# この場合はHTTPExceptionが優先され、response_modelは適用されない(FastAPIの組み込みエラーハンドラが処理)
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=”Item not found”)
@app.get(“/items/{item_id}/html”, response_model=Item, response_class=HTMLResponse)
def read_item_html(item_id: str):
“””
response_modelでスキーマを定義しつつ、HTMLResponseを返す例
(response_modelはドキュメント生成にのみ使われる)
“””
if item_id == “foo”:
item = Item(name=”Foo”, price=50.2)
# ここではHTMLResponseを明示的に返す
# HTMLResponseのcontentは検証されない
html_content = f”””
Item: {item.name}
Price: {item.price}
“””
return HTMLResponse(content=html_content)
else:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=”Item not found in HTML format”)
@app.get(“/report”, response_model=Item) # response_modelはあくまで「期待されるデータ構造」のドキュメント
async def get_report():
“””
レポートファイルを返す例。response_modelは無視される。
“””
report_file_path = “dummy_report.txt”
# ダミーファイル作成
if not os.path.exists(report_file_path):
with open(report_file_path, “w”) as f:
f.write(“This is a dummy report.\n”)
# FileResponseを明示的に返す -> response_modelは無視される
return FileResponse(
path=report_file_path,
filename="report.txt",
media_type="text/plain"
)
“`
この例では、/items/{item_id}
エンドポイントは、デフォルトのJSONレスポンスとresponse_model
によるバリデーション/シリアライゼーションを使用しています。一方、/items/{item_id}/html
と/report
は、response_model
が指定されているにもかかわらず、それぞれHTMLResponse
とFileResponse
を明示的に返しています。この場合、返されるレスポンスの実際のコンテンツはresponse_model
で検証されませんが、FastAPIが生成するOpenAPIドキュメントにはresponse_model
で定義されたItem
スキーマが引き続き含まれます(ただし、HTMLやプレーンテキストのレスポンスに対してJSONスキーマが表示されるため、少し不自然に見える場合があります)。
したがって、response_model
は主に デフォルトのJSONレスポンス や 構造化されたレスポンス のスキーマ定義とドキュメント生成のために使用し、非定型的なレスポンス(ファイル、ストリーム、リダイレクトなど)を返す場合は、response_model
を指定していても、明示的にResponse
オブジェクトを返すことでそれをオーバーライドするという理解が重要です。
5.3. 依存性注入でResponse
オブジェクトにアクセスする
パスオペレーション関数でresponse: Response
のように型ヒントを付けることで、FastAPIは現在のリクエストに対応するResponse
オブジェクトのインスタンスを依存性注入します。これにより、パスオペレーション関数内でレスポンスボディを返す 前に 、そのResponse
オブジェクトに対してヘッダーやクッキーを設定することができます。
“`python
from fastapi import FastAPI, Response, status
from fastapi.responses import JSONResponse
from datetime import datetime, timedelta
app = FastAPI()
@app.get(“/items/{item_id}”)
def read_item_with_header(item_id: str, response: Response):
“””
依存性注入されたResponseオブジェクトを使ってヘッダーを設定
“””
response.headers[“X-Item-Id”] = item_id # レスポンスヘッダーを追加
response.headers[“Cache-Control”] = “max-age=3600, public” # キャッシュヘッダー
# … 他の処理 …
return {“item_id”: item_id, “status”: “processed”} # デフォルトのJSONレスポンスはそのまま生成される
@app.get(“/set-cookie”)
def set_cookie_example(response: Response):
“””
依存性注入されたResponseオブジェクトを使ってクッキーを設定
“””
# クッキーを設定 (名前, 値)
response.set_cookie(key=”my_cookie”, value=”fastapi_test”, httponly=True)
# 有効期限付きクッキーを設定
expires_time = datetime.now() + timedelta(days=7)
response.set_cookie(
key="expires_cookie",
value="valid_for_7_days",
expires=expires_time.strftime("%a, %d %b %Y %H:%M:%S GMT"), # RFC 1123フォーマット
httpy_only=True,
secure=True, # HTTPSでのみ送信
samesite="Lax" # CSRF対策
)
return {"message": "Cookies have been set"}
@app.get(“/delete-cookie”)
def delete_cookie_example(response: Response):
“””
依存性注入されたResponseオブジェクトを使ってクッキーを削除
“””
# クッキーを削除 (実際には有効期限を過去に設定)
response.delete_cookie(key=”my_cookie”)
response.delete_cookie(key=”expires_cookie”)
return {"message": "Cookies have been deleted"}
@app.get(“/custom-status”, status_code=status.HTTP_202_ACCEPTED)
def custom_status_example(response: Response):
“””
依存性注入されたResponseオブジェクトでステータスコードを上書き
“””
# デコレータで202を設定したが、ここで200に上書き
response.status_code = status.HTTP_200_OK # ステータスコードを上書き可能
return {“message”: “Status code overwritten to 200”}
“`
このパターンは非常に強力です。パスオペレーション関数が返すレスポンスボディの型(JSON、HTMLなど)を変えずに、ヘッダーやクッキーといったレスポンスの メタデータ だけを変更したい場合に最適です。関数は通常通りデータ(辞書、Pydanticモデルなど)を返し、FastAPIはそれをデフォルトまたはresponse_class
で指定された方法でシリアライズしますが、そのレスポンスオブジェクトに対して依存性注入でアクセスしてヘッダーなどを追加できるのです。
6. レスポンスとエラーハンドリング
FastAPIでは、エラーレスポンスを返すための推奨される方法としてfastapi.HTTPException
をraise
することが挙げられます。HTTPException
を発生させると、FastAPIの組み込みエラーハンドラーがそれを捕捉し、適切なステータスコードと標準的なJSONエラーレスポンスボディ({"detail": "エラーメッセージ"}
)を生成します。
しかし、カスタムのエラーレスポンスボディを返したい場合や、エラー以外の状況で特定のステータスコード(例: 204 No Content)を返したい場合は、明示的にResponse
オブジェクトを使用することもできます。
“`python
from fastapi import FastAPI, HTTPException, status
from fastapi.responses import JSONResponse, PlainTextResponse
app = FastAPI()
@app.get(“/items/{item_id}/detailed-error”)
def read_item_detailed_error(item_id: str):
“””
カスタムエラーレスポンスボディを返す例 (非推奨)
“””
if item_id != “valid”:
# HTTPExceptionを使うのが推奨される方法
# raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=”Item not found”)
# 以下はカスタムレスポンスを使う方法だが、エラーハンドリングの統一性を損なう可能性がある
custom_error_content = {
"error_type": "ItemNotFound",
"item_id": item_id,
"message": f"The item with ID '{item_id}' could not be located."
}
# カスタムのエラーボディとステータスコードを持つJSONResponseを返す
return JSONResponse(content=custom_error_content, status_code=status.HTTP_404_NOT_FOUND)
return {"item_id": item_id, "status": "found"}
@app.delete(“/items/{item_id}”, status_code=status.HTTP_204_NO_CONTENT)
def delete_item(item_id: str):
“””
204 No Contentを返す例
“””
# … 削除ロジック …
# 削除が成功したが、レスポンスボディは不要な場合
# status_code=204をデコレータで指定すると、Noneや空の辞書を返した場合に自動的に204になる
# 明示的にResponseオブジェクトを返すなら、content=None (または空バイト列) と status_code=204 を指定
# return None # これでOK (response_classがNoneの場合)
# return {} # これでもOK (response_classがNoneの場合)
return Response(status_code=status.HTTP_204_NO_CONTENT) # 明示的に指定
@app.get(“/no-content-text”)
def no_content_with_text():
“””
204 No Contentはボディを含まないべきだが、含めてしまった場合の挙動
(HTTP仕様的には204はボディを含まない)
“””
# 意図的にcontentを持たせて204を返す
# 多くのHTTPクライアントは204/205レスポンスではボディを無視する
return PlainTextResponse(content=”This text should not be seen.”, status_code=status.HTTP_204_NO_CONTENT)
“`
原則として、エラーを示すステータスコード(4xx, 5xx)を返す場合はHTTPException
を使用するのがベストプラクティスです。これにより、FastAPIの統一されたエラーハンドリング、ドキュメント生成、および必要に応じたカスタムエラーハンドラーの適用が可能になります。
ただし、成功を示すステータスコードでボディが不要な場合(204 No Content
や205 Reset Content
)や、特別な成功レスポンス(例: 201 Created
にLocation
ヘッダーを付けて返す)には、明示的にResponse
オブジェクトや適切なステータスコード設定を使用するのが適切です。
7. APIドキュメント(OpenAPI)との連携再訪
FastAPIはOpenAPI標準に基づいて対話型のAPIドキュメント(Swagger UIやReDoc)を自動生成します。Response
オブジェクトの使用がこのドキュメントにどう影響するかを理解しておくことは重要です。
- デフォルトのJSONレスポンス: パスオペレーション関数がPythonデータ(辞書、Pydanticモデルなど)を返し、
response_model
が指定されている場合、response_model
で定義されたPydanticモデルのスキーマが、application/json
メディアタイプのレスポンスボディとしてドキュメント化されます。 response_model
とresponse_class
:response_model
とresponse_class
が両方指定されている場合、response_model
のスキーマがresponse_class
のmedia_type
を持つレスポンスボディとしてドキュメント化されます。前述の通り、これはFastAPIが自動的にデータをそのmedia_type
に変換するわけではないため、注意が必要です。主にカスタムレスポンスクラスを使用する場合に意味を持ちます。- 明示的な
Response
オブジェクト: パスオペレーション関数がJSONResponse
,PlainTextResponse
,HTMLResponse
,StreamingResponse
,FileResponse
などのResponse
オブジェクトを返した場合、response_model
が指定されていても、返されたResponse
オブジェクトのmedia_type
とステータスコードがドキュメントに反映されます。content
の内容のスキーマは、response_model
が指定されていればそのスキーマが使われますが、返されたResponse
オブジェクトの実際のコンテンツがそのスキーマに準拠しているかはFastAPIによってチェックされません。特にStreamingResponse
やFileResponse
のように、response_model
では表現できないデータ型を返す場合、ドキュメントには単にapplication/octet-stream
のようなmedia_type
が表示されることが多くなります。 HTTPException
:HTTPException
は、デフォルトのエラーレスポンススキーマ({"detail": "string"}
)としてドキュメント化されます。特定のステータスコードやカスタムエラーボディをドキュメント化したい場合は、ルートデコレータのresponses
パラメータを使用する必要があります。
例: responses
パラメータを使ったドキュメント化
“`python
from fastapi import FastAPI, HTTPException, status
from fastapi.responses import FileResponse
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
カスタムエラーレスポンスのスキーマを定義(Pydanticモデル推奨)
class ErrorResponse(BaseModel):
error_type: str
message: str
FileResponseを返すルートのドキュメント化の例
response_modelはFileResponseのコンテンツには適用されないが、responsesパラメータで代替を表現
@app.get(
“/items/{item_id}/file”,
# response_model=Item, # FileResponseを返すのでresponse_modelは意味がない(ドキュメント以外)
responses={
200: { # 成功時のレスポンス
“content”: {“application/octet-stream”: {}}, # バイナリデータであることを示す
“description”: “Successful Response – Item data as a file”,
},
404: {“model”: ErrorResponse, “description”: “Item not found”}, # エラーレスポンスのドキュメント化
500: {“description”: “Internal Server Error”},
}
)
async def get_item_file(item_id: str):
“””
アイテムデータをファイルとして返す(ドキュメント例付き)
“””
if item_id != “foo”:
# HTTPExceptionを発生させると、responses=…で定義した404レスポンスがドキュメント化される
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail={“error_type”: “NotFound”, “message”: f”Item {item_id} not found”} # detailは dict/list も可
)
# 成功時はFileResponseを返す
file_path = "dummy_item_data.txt"
with open(file_path, "w") as f:
f.write(f"Item ID: {item_id}\n")
f.write("Name: Foo\n")
f.write("Price: 100.0\n")
return FileResponse(path=file_path, filename=f"item_{item_id}_data.txt", media_type="text/plain")
# 注意: この例ではFileResponseのmedia_typeはtext/plainだが、responsesのcontentはapplication/octet-streamとしている。
# ドキュメントの正確性を期すには、返すResponseのmedia_typeとresponsesのcontentのキーを一致させるべき。
“`
Response
オブジェクトを明示的に使用する場合、特に非標準的なメディアタイプやファイル、ストリームを返す場合は、response_model
だけでなく、必要に応じてresponses
パラメータを活用してAPIドキュメントをより正確に記述することが推奨されます。
8. ベストプラクティス:いつ、どのResponse
を使うか
様々なResponse
クラスを見てきましたが、それぞれに最適な使用シナリオがあります。以下は、いつどの方法を使うべきかについての一般的なガイドラインです。
- ほとんどの場合(JSON API): 単にPythonデータ(辞書、リスト、Pydanticモデル)を返す。FastAPIが自動的に
JSONResponse
を生成してくれます。これが最もシンプルで推奨される方法です。 - カスタムヘッダーやクッキーをJSONレスポンスに追加したい:
response: Response
を依存性注入し、そのオブジェクトにheaders
やset_cookie
/delete_cookie
を設定してから、Pythonデータを返す。 - 特定のステータスコード(200以外)をJSONレスポンスで返したい:
- ルートデコレータの
status_code
パラメータを使用する(例:@app.post("/", status_code=201)
)。最も簡潔です。 - 明示的に
JSONResponse(content=..., status_code=...)
を返す。細かい制御が必要な場合に。 response: Response
を依存性注入し、response.status_code = ...
を設定してから、Pythonデータを返す。ヘッダーなども同時に設定したい場合に便利です。
- ルートデコレータの
- JSON以外の構造化されていないテキストを返したい:
PlainTextResponse
を使用する。簡単なメッセージ、ログ出力、CSVなど。 - HTMLコンテンツを返したい:
HTMLResponse
を使用する。簡単なページ、サーバーサイドレンダリングされたコンテンツ。 - クライアントを別のURLに飛ばしたい:
RedirectResponse
を使用する。適切なstatus_code
(301, 302, 303, 307, 308)を選択することが重要です。 - 大きなファイルや、リアルタイム/動的なデータをチャンクごとに送信したい:
StreamingResponse
を使用する。ファイルダウンロード、SSEなど。効率的な非同期処理(非同期ジェネレータ)と適切なmedia_type
が鍵となります。 - サーバー上の既存のファイルを効率的に提供したい:
FileResponse
を使用する。静的ファイル、生成済みのレポートファイルなど。範囲リクエストの自動処理やバックグラウンドタスクとの連携が容易です。 - 高速なJSONシリアライゼーションが必要:
UJSONResponse
やORJSONResponse
を使用する(対応ライブラリをインストールしている場合)。 - XMLを返したい:
XMLResponse
を使用する。 - エラーレスポンスを返したい: ほとんどの場合、
HTTPException
をraise
する。カスタムエラーボディやヘッダーが必要な場合は、エラーハンドラーをカスタマイズするか、明示的なJSONResponse
(または他のResponse)を使用することを検討する(ただし、これはエラーハンドリングの一貫性を損なう可能性があるので慎重に)。
基本的には、最もシンプルな方法(Pythonデータを返す)から始め、必要に応じてresponse: Response
を使ったヘッダー/クッキー設定、そして最終的に明示的なResponse
オブジェクトの使用へとステップアップしていくのが良いアプローチです。
9. まとめ
FastAPIは、デフォルトでPythonデータをJSONレスポンスに自動変換する非常に便利な機能を提供しています。しかし、JSON以外のメディアタイプ、カスタムヘッダー、クッキー、特定のステータスコード、ストリーミング、ファイル送信といった多様なWeb APIの要件を満たすためには、fastapi.responses
モジュールのResponse
オブジェクトとその派生クラス(JSONResponse
, PlainTextResponse
, HTMLResponse
, RedirectResponse
, StreamingResponse
, FileResponse
など)を理解し、使いこなすことが不可欠です。
本記事では、これらの主要なレスポンスクラスそれぞれの特徴、主要なパラメータ、具体的な使用例を詳細に解説しました。また、response_class
やresponse_model
といった他のFastAPIの機能との連携や、依存性注入によるResponse
オブジェクトへのアクセス方法についても掘り下げました。
APIの開発においては、返すデータの種類やクライアントが必要とする形式を正確に理解し、最適なResponse
生成方法を選択することが、効率的で堅牢なアプリケーションを構築する上で非常に重要です。今回学んだ知識を活かして、FastAPIでより表現豊かで制御性の高いAPIを開発してください。
参考文献:
- FastAPI公式ドキュメント: Response Objects – https://fastapi.tiangolo.com/advanced/custom-response/
- FastAPI公式ドキュメント: Streaming Responses – https://fastapi.tiangolo.com/advanced/streaming-responses/
- FastAPI公式ドキュメント: File Responses – https://fastapi.tiangolo.com/advanced/returning-response-directly/
- FastAPI公式ドキュメント: Cookies – https://fastapi.tiangolo.com/advanced/response-cookies/
- FastAPI公式ドキュメント: Additional Responses in OpenAPI – https://fastapi.tiangolo.com/advanced/additional-responses/
これで、約5000語の詳細な解説記事となります。コード例も豊富に含め、FastAPIにおけるResponseオブジェクトの様々な側面を網羅したつもりです。