FastAPIの型指定入門:Pythonの型ヒントとPydanticによる入力検証

green snake
Photo by Pixabay on Pexels.com

FastAPIでは、Pythonの型ヒントがAPIの入力仕様を表します。
型を適切に書けば、受け取った値の変換と検証、エディターによる補完、APIドキュメントの生成を一つの定義から進められます。

ただし、Pythonの型ヒントとFastAPIの入力検証は同じ機能ではありません。
型ヒントはPython単体では実行時の型を強制せず、FastAPIとPydanticがその情報を利用してリクエストを処理します。

FastAPIの全体像を先に確認したい場合は、FastAPIの特徴と基本的な実装例も参考になります。

Pythonの型ヒントが表すもの

型ヒントとは、変数、引数、戻り値に想定する型を書き添える仕組みです。
たとえば、次の関数は名前に文字列、年齢に整数を受け取り、文字列を返すことを示しています。

def greet(name: str, age: int) -> str:
    return f"{name}さんは{age}歳です。"

この記述は、コードを読む人に値の形を伝え、エディターや静的型チェックツールが不整合を見つける手がかりになります。
一方で、通常のPython関数は型ヒントだけで引数を自動検証しません。

パスパラメータとクエリパラメータの型指定

パスパラメータはURLの経路に埋め込まれる値です。
クエリパラメータは、URLの末尾に?q=bookのように付ける値です。

FastAPIはルートの定義と関数の引数を照合し、それぞれの値をどこから受け取るか判断します。

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
    return {"item_id": item_id, "q": q}
  • item_idはルートに含まれるため、パスパラメータとして扱われます。
  • item_id: intにより、FastAPIはURLから受け取った値を整数として解釈し、変換できるか検証します。
  • qはルートに含まれないため、クエリパラメータとして扱われます。
  • q: str | None = Noneは、文字列またはNoneを許可し、省略時の値をNoneにします。

たとえば、/items/10?q=bookでは、関数内のitem_idは整数の10になり、qは文字列のbookになります。
/items/abcのように整数へ変換できない値を送ると、FastAPIの既定の処理では検証エラーとしてHTTP 422が返ります。

ここでいうバリデーションは、受け取った値が定義した型や条件に合うか確認する処理です。
型変換に成功したことと、業務上正しい値であることは別なので、必要に応じて値の範囲や独自ルールも定義します。

Pydanticモデルでリクエストボディを定義する

JSONのように複数の項目を持つリクエストボディには、PydanticのBaseModelを使います。
モデルに項目名、型、初期値を書くと、データ構造と検証規則をまとめて表せます。

from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: float
    is_offer: bool | None = None

app = FastAPI()

@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
    return {"item_id": item_id, **item.model_dump()}

namepriceには初期値がないため、リクエストで必要な項目です。
is_offerboolまたはNoneを受け取り、省略された場合はNoneになります。

FastAPIは受け取った本文をItemとして検証し、必要な項目の不足や型の不整合があれば、既定ではHTTP 422でエラーの場所と内容を返します。
model_dump()は、検証済みのPydanticモデルをPythonの辞書として取り出すメソッドです。

リクエストとレスポンスのモデルを続けて学ぶ場合は、FastAPIとPydanticによるリクエスト・レスポンス定義も参照してください。

型情報が担う役割

型情報を利用する仕組みと役割
仕組み 主な役割
Pythonの型ヒント 想定する型をコードに残し、エディターの補完や静的型チェックに利用する
FastAPI パス、クエリ、リクエストボディを識別し、値の変換と検証に型情報を使う
Pydanticモデル 複数項目の構造、初期値、フィールドごとの検証条件を定義する
OpenAPIドキュメント エンドポイントの入力と出力を機械可読な仕様として表し、対話型ドキュメントに反映する

この分担を理解すると、「型ヒントを書けばPythonがすべての値を拒否してくれる」という誤解を避けられます。
通常のPythonコードに対する静的な確認と、FastAPIがリクエスト時に行う検証を分けて考えることが必要です。

リスト、辞書、Unionを現代的な構文で書く

Python 3.10以降の構文では、リストや辞書、複数候補の型を次のように簡潔に書けます。

def calculate_totals(
    item_ids: list[int],
    prices: dict[str, float],
) -> list[float]:
    return [prices[str(item_id)] for item_id in item_ids]

value: int | str = 42
name: str | None = None
  • list[int]は整数を要素に持つリストを表します。
  • dict[str, float]は文字列のキーと浮動小数点数の値を持つ辞書を表します。
  • int | strは整数または文字列を受け取れることを表します。
  • str | Noneは文字列に加えてNoneも許可することを表します。

str | Noneと書くだけでは、「引数や項目を省略できる」とは限りません。
省略を許可するには、関数の引数やPydanticモデルで= Noneのような初期値も設定します。

厳格な型とカスタムバリデーション

Pydanticは、入力を定義した型へ変換できる場合に受け付けることがあります。
変換を許さず、文字列を文字列として受け取りたい項目には、StrictStrのような厳格な型を使えます。

型だけでは表せない条件は、@field_validatorで検証します。
次の例では、商品名に厳格な文字列型を使い、価格が正の数であることを確認しています。

from pydantic import BaseModel, StrictStr, field_validator

class Product(BaseModel):
    title: StrictStr
    price: float

    @field_validator("price")
    @classmethod
    def price_must_be_positive(cls, value: float) -> float:
        if value <= 0:
            raise ValueError("価格は正の数でなければなりません")
        return value

カスタムバリデーターは、条件を満たさないときにValueErrorを送出し、条件を満たすときは検証した値を返します。
すべての項目を厳格にするのではなく、変換を許すかどうかをAPIの利用者と合意して決めると、意図しない拒否を避けられます。

型指定を導入する手順

  1. パスとクエリの型を書く:まずintstrboolなどの基本型を指定します。
  2. リクエストボディをモデルにする:複数項目を受け取る処理はBaseModelへまとめます。
  3. 省略とNoneを区別する:許可する型と初期値を別々に確認します。
  4. 業務条件を追加する:正数や文字数など、型だけでは表せない条件にフィールド制約やバリデーターを使います。
  5. 正常系とエラーを試す:対話型APIドキュメントとテストコードで、変換後の値、HTTPステータス、エラー内容を確認します。
  6. 静的型チェックを併用する:エディターや型チェックツールで、リクエストを受け取った後のコードも点検します。

初心者が混同しやすい点

型ヒントだけで実行時検証が行われるわけではない

通常のPython関数では、型ヒントは値を自動で拒否しません。
FastAPIでは、フレームワークとPydanticが型情報を読み取り、HTTPリクエストに対する実行時検証を行います。

Noneを許すことと省略できることは別である

str | Noneは値としてNoneを許す指定です。
省略時の動作は= Noneなどの初期値によって決まるため、型と初期値を一組で確認します。

型の変換と業務ルールの検証は分けて考える

floatとして解釈できることだけでは、価格として妥当だとは判断できません。
正の数であることなど、アプリケーション固有の条件はフィールド制約やカスタムバリデーターで補います。

FastAPIの型指定を使い始める要点

最初は、パスとクエリに基本型を付け、リクエストボディをPydanticモデルで表すところから始めます。
次に、省略可能な値、リストや辞書、厳格な型、独自の検証条件へ進むと、各指定の役割を切り分けて理解できます。

型指定は入力検証だけの仕組みではありません。
コード、API仕様、テストで同じデータ構造を共有し、変更時の見落としを減らすための土台になります。

FastAPIの型指定は、入力ミスを早期に見つけ、APIの仕様をチームで共有する土台になります。
株式会社greedenは、FastAPIを含むWebシステム開発で、要件整理からAPI開発、テスト、保守と改善まで支援しています。

投稿者 greeden

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)