👻

ResponseValidationErrorが出たときは【FastAPI】

2024/09/22に公開

私がFastAPIで開発していて、デバッグする際にResponseValidationErrorというのがエラーの中ではよく出たので、このエラーの原因と解決策について自分の備忘録としてまとめてみました。

エラー文のイメージ

前提

  • 言語: Python 3.12.2
  • フレームワーク: FastAPI 0.110.0
  • 仮想環境: Dockerを用いた環境構築
  • データベース: MySQL
  • ORMツール: SQLAlchemy 2.0.28
  • データベースマイグレーションツール: Alembic 1.13.1

ResponseValidationError とは

このエラーは、APIからのレスポンスが期待されるデータ型と一致していない場合に発生する。FastAPIはPydanticを使用して、エンドポイントからのレスポンスが指定されたモデルに従っているかを検証する。もしレスポンスがモデルと一致しなければ、このエラーが発生してしまう。

FastAPIで実装する際、レスポンスを求めるようなAPI(特にGETメソッド)の場合、以下のようにレスポンスモデルを定義するかと思う。下記の例の場合はユーザー情報を取得しようとしている。

class UserResponse(BaseResponse):
    id: int
    name: str
    user_id: str
    email: str

この場合、「id」「name」「user_id」「email」の4つの要素があり、idはint型、それ以外はstr型で、それらを辞書型にして取得することを要求するようにしている。

# ヘッダーなどは省略
{
"id": 101,
"name": "John Doe",
"user_id": "johndoe123",
"email": "johndoe@example.com"
}

このような形で戻ってくれば良いのだが、1つでもこれに反するデータが取得された場合に、このエラーを返してくる。

エラーが発生するケース

# ヘッダーなどは省略
# 以下は誤ったデータのイメージ
{
"id": 101,
"name": "John Doe",
"user_id": 123101,
"email": "johndoe@example.com"
}

上記の場合、user_idはstr型を要求していたにも関わらず、数値を返そうとしている。この場合にエラーが発生する。原因は、データベースから取得するデータの選択が誤っているか、そもそもレスポンスモデルの指定の間違い(intで書くべきところをコピペミスなどでstrにしていた)などが考えられる。

# ヘッダーなどは省略
# 以下は誤ったデータのイメージ
{
"id": 101,
"name": "John Doe",
"address": "Japan",
"user_id": "johndoe123",
"email": "johndoe@example.com"
}

上記の場合、レスポンスモデルにない”address” という要素が一緒に返ってきている。この場合もエラーが発生する。これもデータベースからデータを取得する際に、必要なデータの選択が正しくできていない可能性がある。

# ヘッダーなどは省略
# 以下は誤ったデータのイメージ
{
"id": 101,
"name": null,
"user_id": "johndoe123",
"email": "johndoe@example.com"
}

上記の場合、”name” が見つからずにnullとなっている。データベースに”name”というカラムが存在しないか、データが空白になっているなどの原因が考えられる。この場合、もしデータが空である状態が存在しうる(例えば名前は後から入力できる設定にしているなど)ならば、レスポンスモデルにNoneを許可するように記載して回避することもできる。

name: Optional[str]
# もしくは
name: str | None

解決策

  1. レスポンスモデルの確認:
    • APIのエンドポイントで指定されたレスポンスモデルを確認し、それが正しく指定されているか確認する。intであるべきところがstrになっている、”name”という属性も必要なのに書き忘れていた、Listで返してくる想定なのにそれを記載していなかったなど、ミスがあるかもしれないので、それをよく確認するようにしよう。
  2. データソースの検証:
    • データソース(データベースや外部APIなど)から正しいデータが取得できているかを確認する。上の例なら、必要な4つの要素についてクエリを正しく指定しているか、余分なクエリが混じっていないか、逆にデータに不足はないかなど、よく確認する。特に区分系のカラムの場合、外部キーとしてidをint型で格納していて、外部テーブルから対応する文字列を探してこないといけないが、それを忘れていたケースもよくあるので、それにも注意するようにしよう。
  3. エラーハンドリングの強化:
    • APIが空のリストや予期しないデータタイプを返す可能性がある場合、適切なエラーコードやメッセージを返すようにエラーハンドリングを実装することも考えよう。

まとめ

ResponseValidationErrorは、APIが予期せぬ形式のデータを返してしまったことを示す重要な警告である。このためこのエラーが発生したときは、レスポンスモデルに合致したデータをDBから取得できているか、しっかり確認することが大事である。

株式会社Xronotech

Discussion