第2章 FastAPI による Web API の基本設計
FastAPI は、現代的な Python の型ヒントを最大限に活用した、直感的で書きやすい Web フレームワークです。
本章では、FastAPI アプリケーションの基本的な作り方、URL ルーティング、Pydantic モデルを用いた入力検証、ステータスコードの制御、および自動生成されるドキュメント機能について学びます。
2.1 FastAPI アプリケーションの起動とルーティング
FastAPI の最小構成は、FastAPI クラスのインスタンスを作成し、デコレータを用いて関数にパス(URL)と HTTP メソッドを紐付けることです。
以下のコードは、ルートパス / に GET リクエストが届いた際に JSON を返す最小限のアプリケーション例です。
from fastapi import FastAPI
app = FastAPI(title="Sample API", version="1.0.0")
@app.get("/")
def read_root() -> dict[str, str]:
return {"message": "Hello, FastAPI"}
このファイルを main.py として保存した場合、ターミナルから uvicorn main:app --reload を実行するとサーバーが起動し、http://127.0.0.1:8000/ でアクセスできるようになります。
2.2 パスパラメータとクエリパラメータ
API では、URL の一部に変数を埋め込む「パスパラメータ」と、末尾に ?key=value の形式で付与する「クエリパラメータ」を使い分けます。
FastAPI では、関数の引数に型アノテーションを記述するだけで、自動的に文字列から数値への変換と妥当性チェックが行われます。
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None) -> dict[str, int | str | None]:
return {"item_id": item_id, "query": q}
パス内に記述された {item_id} はパスパラメータとして int 型に変換されます。パスに含まれない引数 q は自動的にクエリパラメータとして扱われます。もし item_id に文字(例: /items/abc)を指定すると、FastAPI は自動的にエラー(422 Unprocessable Entity)を返します。
2.3 Pydantic によるリクエストボディの検証
POST や PUT メソッドで JSON データを受け取る場合は、Pydantic の BaseModel を継承したクラスを定義します。
Pydantic モデルを使うことで、期待するフィールドの名前、型、デフォルト値、必須チェックを宣言的に定義できます。
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class ItemCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=50, description="商品名")
price: int = Field(..., gt=0, description="単価(1円以上)")
tax_rate: float = Field(default=0.1, ge=0.0, le=1.0, description="消費税率")
@app.post("/items")
def create_item(item: ItemCreate) -> dict[str, str | int | float]:
total_price = int(item.price * (1 + item.tax_rate))
return {
"name": item.name,
"price": item.price,
"total_price": total_price,
}
クライアントから送られた JSON は自動的に解析され、型と制約条件(文字数や数値範囲)が検証されます。ルール違反がある場合、どのフィールドにどんな不備があったのかを詳細な JSON エラーとして返却してくれます。
2.4 レスポンスモデルと HTTP ステータスコード
API の設計では、クライアントへ返すデータの構造を明確にし、適切な HTTP ステータスコード(成功時は 200 または 201、エラー時は 400 や 404 など)を設定することが不可欠です。
response_model 引数をデコレータに指定すると、余計な内部データの漏洩を防ぎ、出力データの型を保証できます。
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
app = FastAPI()
class UserOut(BaseModel):
id: int
username: str
email: str
users_db: dict[int, dict[str, str | int]] = {
1: {"id": 1, "username": "alice", "email": "alice@example.com", "hashed_password": "secret"},
}
@app.get("/users/{user_id}", response_model=UserOut, status_code=status.HTTP_200_OK)
def get_user(user_id: int):
user = users_db.get(user_id)
if user is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"User with id {user_id} was not found",
)
return user
上記コードでは、データベース内に hashed_password が存在していても、response_model=UserOut で定義されたフィールドのみが JSON としてクライアントに返されるため、意図しない機密情報の漏洩を防ぐことができます。
2.5 自動生成される対話型 API ドキュメント
FastAPI を起動すると、ブラウザからアクセスできる対話型ドキュメントが追加の設定なしで自動生成されます。
- Swagger UI:
http://127.0.0.1:8000/docsにアクセスすると利用できます。ブラウザ上で各エンドポイントの仕様を確認し、実際にリクエストを送信して動作をテストできます。 - ReDoc:
http://127.0.0.1:8000/redocにアクセスすると利用できます。読みやすく整形された API ドキュメントを閲覧できます。
コード中に書いた型ヒント、Pydantic モデル、および説明文(description や関数の docstring)がそのまま仕様書に反映されるため、コードとドキュメントの乖離が発生しません。