リクエストボディの定義方法
Pydantic BaseModel・Fieldを使ったリクエストボディ定義例とベストプラクティス
# BaseModel・Field を使ったリクエストボディ定義
基本的なリクエストボディ定義
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.post("/items/")
async def create_item(item: Item):
return item
- 必須項目はデフォルト値なし、任意項目は
None
やデフォルト値を指定
Field を使ったバリデーション・ドキュメント強化
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str = Field(..., title="商品名", max_length=100, example="りんご")
description: str | None = Field(None, title="説明", max_length=300, example="新鮮な青森産りんご")
price: float = Field(..., gt=0, description="価格は0より大きい必要があります", example=120.5)
tax: float | None = Field(None, example=10.0)
Field
でバリデーション条件やAPI ドキュメント用メタ情報(title
,description
,example
など)を付与
ネストしたモデルの例
from pydantic import BaseModel, Field
class Address(BaseModel):
zipnum: str = Field(..., example="100-0001")
city: str = Field(..., example="東京")
detail: str = Field(..., example="千代田区千代田1-1")
class User(BaseModel):
username: str = Field(..., example="taro")
address: Address
@app.post("/users/")
async def create_user(user: User):
return user
- ネスト(入れ子)した Pydantic モデルで複雑な構造も表現可能[^2][^4]。
配列(リスト)を含むリクエストボディ
from typing import List
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str
price: float
class Order(BaseModel):
items: List[Item]
user: str = Field(..., example="hanako")
importance: int = Field(..., ge=1, le=10, example=5)
@app.post("/orders/")
async def create_order(order: Order):
return order
- リスト型で複数のオブジェクトも受け取れる
Field の基本的な使い方
Pydantic の Field は、モデルの各フィールドにバリデーション条件やメタデータ(説明、タイトル、例など)を追加するために使います。FastAPI や Pydantic のデータモデルで広く利用されており、API ドキュメントの自動生成や入力値の制約に役立ちます。 基本構文
from pydantic import BaseModel, Field
class User(BaseModel):
name: str = Field(..., min_length=2, max_length=50, description="ユーザー名")
age: int = Field(18, ge=18, le=120, description="年齢(18~120)")
email: str = Field(..., regex=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", description="メールアドレス")
…(エリプシス)は必須フィールドを意味します。 min_length, max_length, ge, le, regex などでバリデーションが可能です。 description や title で API ドキュメントに説明を追加できます。
…(エリプシス)は必須フィールド
Field(..., ...)
の ...
(エリプシス)は「このフィールドは必須である」という意味です。
- 例:
name: str = Field(..., description="ユーザー名")
この場合、name
はリクエストボディに必ず含める必要があり、省略すると自動的にバリデーションエラーとなります。
min_length, max_length
これらは文字列やリストなどの長さに対するバリデーション条件です。
min_length
:値の最小長さを指定します。max_length
:値の最大長さを指定します。
例:
username: str = Field(..., min_length=3, max_length=20, description="3~20文字のユーザー名")
この場合、username
が 3 文字未満または 20 文字超の場合はエラーになります。
ge, le
これらは数値型フィールドに対するバリデーション条件です。
ge
(greater than or equal):指定値以上(≧)であることを要求します。le
(less than or equal):指定値以下(≦)であることを要求します。
例:
age: int = Field(..., ge=18, le=120, description="18歳以上120歳以下")
この場合、age
が 18 未満または 120 超の場合はエラーになります。
regex
regex
は文字列型フィールドに対して、正規表現によるパターンマッチをバリデーション条件として指定します。
例:
email: str = Field(..., regex=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", description="メールアドレス")
この場合、email
が指定した正規表現にマッチしない場合はエラーになります。
description, title
これらは**API ドキュメント(Swagger UI や OpenAPI)**に表示される説明やタイトルを指定します。
description
:フィールドの説明文。API 利用者向けの詳細な情報を記載できます。title
:フィールドのタイトル。API ドキュメント上で項目名として表示されます。
例:
password: str = Field(..., title="パスワード", description="8文字以上の英数字")
この場合、Swagger UI では「パスワード」というタイトルと「8 文字以上の英数字」という説明が表示されます。
これらのオプションを組み合わせることで、入力値の厳密なバリデーションとAPI ドキュメントの充実を同時に実現できます。
受け取ったレスポンスボディの使用方法
FastAPI で Pydantic モデル(例:user
)をレスポンスボディとして受け取った後、通常のクラスや辞書型に変換し、さらにそのデータを処理用の一般的なクラスに渡す場合の流れは以下のようになります。
1. Pydantic モデルから辞書型へ変換
Pydantic v2 では.model_dump()
を使ってモデルインスタンスを辞書に変換します。
user_dict = user.model_dump()
- これで
user_dict
はdict
型になります
2. 辞書型を通常のクラスに渡す
Python の標準的なクラス(例:UserData
)のコンストラクタは、**user_dict
のように辞書をアンパックして渡すことで、各フィールドを引数として受け取ることができます[^2][^3]。
class UserData:
def __init__(self, username, email, age):
self.username = username
self.email = email
self.age = age
# user_dict = {"username": "john", "email": "john@example.com", "age": 30}
user_data = UserData(**user_dict)
- この方法で、Pydantic モデル → 辞書 → 通常クラスへの変換がシンプルに行えます[^2][^3]。
3. 注意点とベストプラクティス
- 辞書のキーと通常クラスの引数名が一致している必要があります。
- 不要なフィールドがある場合は、
.model_dump()
のinclude
やexclude
パラメータで調整できます
# 例:特定フィールドだけ含める
filtered_dict = user.model_dump(include={"username", "email"})
user_data = UserData(**filtered_dict)