ホーム

リクエストボディの定義方法

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_dictdict型になります

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()includeexcludeパラメータで調整できます
# 例:特定フィールドだけ含める
filtered_dict = user.model_dump(include={"username", "email"})
user_data = UserData(**filtered_dict)