FastAPIとPydanticで始めるリクエスト・レスポンス定義ガイド
📋 記事のポイント(サマリー)
- 誰向け?
PythonとFastAPIの基礎は理解しているけれど、データのバリデーションや型安全なAPI設計を学びたい中級者さん - 学べること
- Pydanticモデル(
BaseModel
)の基本構造 - リクエストボディでのバリデーション方法
- レスポンスモデルによる出力制御・ドキュメント生成
- フィールドのデフォルト値・エイリアス・検証ルール設定
- ネストしたモデルやリスト、カスタムバリデータの活用例
- Pydanticモデル(
- 得られる効果
- バリデーションエラーの自動生成で、堅牢かつ親切なAPIが実現できる
- ドキュメントUIにモデル定義が反映され、フロント開発者との連携がスムーズに
🎯 対象読者
- 学生エンジニアAさん(22歳)
FlaskやDjangoで簡単なAPIは作ったことがあるものの、型ヒントや自動バリデーションの便利さを体感したい方 - 社会人Bさん(30歳)
社内向けツールのAPI設計をFastAPIに移行し、入力チェックや出力フォーマットを厳格化したいエンジニア - サイドプロジェクトCさん(27歳)
趣味のToDoアプリで、安全にユーザー入力を受け取り、誰が見てもわかりやすいAPI仕様書を自動生成したい方
♿ アクセシビリティレベル
- 読みやすさ:漢字・ひらがな・カタカナのバランスを配慮し、重要語には簡易ルビを併記
- 構造化:見出し・サブ見出しと箇条書きで階層を明確化
- コード例:コメント付きのコードブロックを幅固定で表示し、視認性を高める
- ナビゲーション:各章末に「要点まとめ」を設け、スクリーンリーダーでも把握しやすい
1. Pydanticモデルの基本—BaseModel
とは?
FastAPIが標準で採用する Pydantic は、Pythonの型ヒントを活用しつつ、データ検証とシリアライズを自動化してくれるライブラリです。
中心となるのは BaseModel
クラスの継承で、各フィールドに型を指定するだけでバリデーションやデフォルト値の設定が可能になります。
from pydantic import BaseModel
class Item(BaseModel):
name: str # 必須の文字列
price: float # 必須の浮動小数点
is_offer: bool = False # オプション(デフォルト:False)
要点まとめ
BaseModel
を継承してクラス定義- 型ヒントだけで検証・シリアライズが実行される
- デフォルト値を指定すると「オプション」扱いに
2. リクエストボディでのモデル適用
2.1 FastAPIの引数にPydanticモデルを指定
POST
や PUT
のように、クライアントから JSON ボディを受け取る場合、エンドポイント関数の引数にPydanticモデルを型注釈するだけでOKです。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: bool = False
@app.post("/items/")
async def create_item(item: Item):
# itemはItemインスタンスとして受け取れる
return {"item_name": item.name, "item_price": item.price}
- クライアントが不正なJSONや型の値を送ると、自動的に 422 Unprocessable Entity エラーが返却されます。
- レスポンスボディには、どのフィールドがどう間違っているかが詳細に含まれます。
要点まとめ
- 関数引数にモデルを型注釈するだけでバリデーションが有効化
- 不正入力時は自動的にエラーレスポンスを生成
3. レスポンスモデルでレスポンス制御
3.1 response_model
パラメータの活用
エンドポイントの戻り値から、特定のフィールドのみを公開したい場合、response_model
にモデルを指定します。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class ItemIn(BaseModel):
name: str
price: float
class ItemOut(BaseModel):
name: str
price_with_tax: float
@app.post("/items/", response_model=ItemOut)
async def create_item(item: ItemIn):
price_with_tax = item.price * 1.1
# 入力モデルから変換した出力モデルを返す
return ItemOut(name=item.name, price_with_tax=price_with_tax)
- レスポンスに含めたくない内部フィールドは除外でき、安全性が向上します。
- 自動生成ドキュメントにも
ItemOut
の構造が反映され、API仕様が明確に。
要点まとめ
response_model
で戻り値をモデル化- 不要なフィールドを自動でフィルタリング
4. フィールド設定の応用テクニック
4.1 Field
で詳細設定
Pydanticの Field
関数を使うと、さらに細かな制約やメタデータを付与できます。
from pydantic import BaseModel, Field
class User(BaseModel):
id: int = Field(..., ge=1, description="ユーザーID(1以上の整数)")
name: str = Field(..., min_length=1, max_length=50)
email: str = Field(..., regex=r'^\S+@\S+\.\S+$', description="有効なメールアドレス")
...
は 必須 を意味します。デフォルト値なしなら必ずクライアント提供が必要です。ge
,le
,min_length
,max_length
,regex
など、多彩なバリデーションが用意されています。description
はOpenAPIドキュメントに注釈として反映されます。
4.2 エイリアスと入力整形
外部APIやクライアント仕様でキー名がスネークケース以外の場合、alias
オプションで対応可能です。
class Product(BaseModel):
product_id: int = Field(..., alias="id")
productName: str = Field(..., alias="name")
# クライアントは {"id":1,"name":"Book"} を送信
# 内部では product_id, productName プロパティでアクセスできる
要点まとめ
Field
で制約とドキュメント注釈を追加alias
でJSONキー名とプロパティ名を切り分け
5. ネストモデル・リスト・カスタムバリデータ
5.1 ネストしたモデル
複雑なデータ構造でも、Pydanticモデルをネストして定義できます。
class Address(BaseModel):
street: str
city: str
class UserProfile(BaseModel):
name: str
address: Address # ネストモデル
@app.post("/profiles/")
async def create_profile(profile: UserProfile):
return profile
5.2 リスト型フィールド
複数要素を受け取る場合はリストで型指定します。
class Tag(BaseModel):
name: str
class Article(BaseModel):
title: str
tags: list[Tag] # Tagモデルのリスト
5.3 カスタムバリデータ
独自のチェックが必要な場合、@validator
デコレータでメソッドを定義できます。
from pydantic import validator
class Order(BaseModel):
quantity: int
@validator("quantity")
def must_be_positive(cls, v):
if v <= 0:
raise ValueError("quantity must be positive")
return v
要点まとめ
- ネストやリストで複雑な構造を簡潔に表現
@validator
で自由なバリデーションが可能
6. まとめと次のステップ
本記事では、Pydanticモデルによるリクエスト・レスポンス定義の核心部分をカバーしました。
BaseModel
を継承してモデルを作成- リクエスト引数や
response_model
で適用するだけのシンプルさ Field
、alias
、validator
で柔軟かつ厳密な制約設定- ネストモデルやリストで実用的なデータ構造を実現
これらをマスターすると、FastAPIの自動ドキュメントや型安全性を最大限に活かした堅牢なAPI設計が可能になります。
次のステップとしては、データベース連携や認証機能と組み合わせて、さらに実践的なサービス構築に挑戦してみてくださいね♡