情報処理技術者試験解説チャンネル

応用情報技術者試験をはじめとする情報処理技術者試験の午後問題では、「過去10年分を確実に理解しているか」が合格ラインを左右するといわれています。当チャンネルでは、その10年分の午後問題を要点だけに絞り、約10分のコンパクトな解説としてまとめました。限られた時間でも効率よく学習を進められる構成です。

FastAPIで発生する型エラーを解決しよう

こんにちは、みなさん!PythonでWebアプリケーションを開発していると、突然エラーが発生して、頭を抱えてしまうことってありますよね。特に、「型エラー」なんてものに遭遇すると、「あれ?何がいけなかったんだろう?」と混乱することもあるのではないでしょうか。でも、そんな時こそ冷静に!今回は、FastAPIというWebフレームワークを使っている中でよく出くわす「型エラー」について、具体的にどう対処すればいいのかを、一緒に学んでいきましょう。

「え、型エラー?難しそう...」と思ったあなたも安心してください。丁寧にわかりやすく説明しますし、実際にどんなコードでエラーが発生し、どうやって修正すればいいのかをしっかりお見せします。それでは、気持ちを楽にして、楽しくエラーを乗り越えていきましょう!

型エラーとは?

まず、型エラーとは何かを簡単におさらいしておきましょう。型エラーは、プログラムで変数に割り当てられたデータの「型」が期待されたものと違う場合に発生します。たとえば、数値を期待していたところに文字列が渡されたり、リストが渡されるべきところに整数が来てしまった場合などです。

FastAPIでは、リクエストに含まれるデータの型が間違っていると、自動的に型チェックが行われてエラーが発生します。これをどうやって修正するのか、一緒に見ていきましょう。

サンプルシナリオ:ユーザー情報の登録

次に、実際にFastAPIを使って、ユーザー情報を登録するAPIを作ってみます。ここで、意図的に型エラーを発生させてみましょう。まずは、シンプルなFastAPIのエンドポイントから始めます。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# ユーザーの情報を格納するモデル
class User(BaseModel):
    name: str
    age: int

@app.post("/create_user/")
async def create_user(user: User):
    return {"message": f"ユーザー {user.name} が登録されました!年齢は {user.age} です。"}

このAPIでは、ユーザーの名前と年齢を受け取って、ユーザーを登録するという簡単なものです。それでは、このAPIに対して間違ったデータを送ってみましょう。たとえば、年齢は数値であるべきですが、文字列を渡してみます。

curl -X 'POST' \
  'http://127.0.0.1:8000/create_user/' \
  -H 'Content-Type: application/json' \
  -d '{"name": "Alice", "age": "twenty"}'

発生するエラー

すると、以下のようなエラーレスポンスが返ってきます。

{
  "detail": [
    {
      "loc": ["body", "age"],
      "msg": "value is not a valid integer",
      "type": "type_error.integer"
    }
  ]
}

value is not a valid integer(値が有効な整数ではありません)」というエラーが出ましたね。ageフィールドには整数が必要ですが、送信したデータでは文字列 "twenty" を渡してしまったため、FastAPIは自動的にエラーを返してくれました。

どうしてこうなるの?

FastAPIは、Pydanticというライブラリを使って、リクエストのデータを自動的にバリデーション(検証)しています。つまり、APIにリクエストが送られると、指定された型に従ってデータがチェックされ、合わない場合はエラーが発生します。この仕組みは非常に便利で、型のミスを早い段階で発見できるのです。

でも、せっかくなので、このエラーをどうやってキャッチし、ユーザーにもっと親切なエラーメッセージを返す方法も見てみましょう。

カスタムエラーハンドリング

FastAPIでは、エラーハンドリングをカスタマイズして、よりわかりやすいメッセージをユーザーに返すことができます。例えば、ユーザーが間違ったデータを送ってきた場合、「年齢は整数でなければなりません」というようなメッセージを表示させることができます。

以下のコードで、エラーハンドリングを実装してみましょう。

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, ValidationError

app = FastAPI()

class User(BaseModel):
    name: str
    age: int

@app.exception_handler(ValidationError)
async def validation_exception_handler(request, exc):
    return JSONResponse(
        status_code=422,
        content={"message": "入力データにエラーがあります。年齢は整数で入力してください。"},
    )

@app.post("/create_user/")
async def create_user(user: User):
    return {"message": f"ユーザー {user.name} が登録されました!年齢は {user.age} です。"}

このコードでは、ValidationError が発生した場合、ユーザーに「年齢は整数で入力してください」というメッセージを返すようにしています。

これで、ユーザーが誤った型のデータを送ってきた時に、もっと親切で理解しやすいエラーメッセージを表示できるようになりました。実際に、再び文字列の年齢データを送ってみましょう。

curl -X 'POST' \
  'http://127.0.0.1:8000/create_user/' \
  -H 'Content-Type: application/json' \
  -d '{"name": "Alice", "age": "twenty"}'

新しいエラーレスポンス

今度は、以下のようなレスポンスが返ってきます。

{
  "message": "入力データにエラーがあります。年齢は整数で入力してください。"
}

これで、ユーザーはどこが間違っているのか、より明確に理解することができるようになりました。エラーを丁寧に扱うことで、ユーザーが迷うことなく修正できるように導いてあげることができますね。

さらなる改善:デフォルト値とオプション型

さらにもう一歩進んで、FastAPIではデフォルト値やオプション型を使って、型エラーを防ぐこともできます。たとえば、年齢をオプションにして、入力がなければデフォルトで18歳とすることも可能です。

from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class User(BaseModel):
    name: str
    age: Optional[int] = 18

@app.post("/create_user/")
async def create_user(user: User):
    return {"message": f"ユーザー {user.name} が登録されました!年齢は {user.age} です。"}

このコードでは、ageフィールドが必須ではなくなり、入力がない場合は自動的に18歳が設定されます。これで、ユーザーが年齢を入力し忘れた場合でも、アプリがエラーにならずに動作するようになります。

curl -X 'POST' \
  'http://127.0.0.1:8000/create_user/' \
  -H 'Content-Type: application/json' \
  -d '{"name": "Bob"}'

実行結果:

{
  "message": "ユーザー Bob が登録されました!年齢は 18 です。"
}

終わりに

今回、FastAPIでよく遭遇する「型エラー」の原因と対処法について解説しました。エラーメッセージはプログラムが正確に動作するために非常に重要ですが、それをユーザーにどう伝えるかもまた大切です。FastAPIは、エラーハンドリングを柔軟にカスタマイズできるため、ユーザーに優しいAPIを作ることができます。

型エラーは一見難しそうに思えるかもしれませんが、FastAPIの力を借りれば、エラーを素早く解決し、エラーが起きにくいコードを書くことができます。これからもFastAPIでの開発を楽しんで、さらなるスキル

アップを目指していきましょう!