ヒトリ歩き

愚痴とかいろいろ書きます

FastAPIのエラーハンドラーを使ってコードをシンプルに!!

エラーハンドラーの設定をすることで、try-except毎にレスポンスの組み立てが不要になり、コードがシンプルになると考える。
自分はこのエラーハンドラーの機能があり、助かってる。

エラーハンドラーの設定

特定のエラーに対する応答結果をカスタマイズしたい場合、@app.exception_handlerを設定する。

@app.exception_handler(ValidationError)
async def handle_validation_error(request: Request, exc: ValidationError):
    return JSONResponse(
        status_code=400,
        content={"message": "ValidationErrorが発生したよ"}
    )

exception_handlerデコレータのパラメータにハンドリングするExceptionクラスを指定する。
関数のパラメータは、第一パラメータにRequestクラス、第二パラメータには処理するExceptionクラスを指定。
最後に、返却したい応答結果をJSONResponseクラスを使って、応答結果を設定する。 JSONResponseクラスのstatus_codeステータスコードcontentパラメータに応答内容を設定。

上記の場合、ステータスコードが400、応答内容にJSONのmessageキーにValidationErrorが発生したよの値を設定したデータを返す。

動作確認

応答結果を組み立てる際に、pydanticでValidationErrorが発生するソースコードを用意して実際に動かしてみる。

実際に、動作をさせてみると。
エラーハンドラーの設定がない場合、500エラーが返却される。

エラーハンドラーの設定がある場合、期待する応答が返却される。

最後に

このエラーハンドリングを使うことで、返却したい応答用のExceptionクラスをレイズすれば、応答結果を返すことができる。 そうすることで、try-except毎に応答結果を生成する処理は不要になり、コードがシンプルになると考える。 自分は、try-except毎に応答結果の処理を作りたくないので、エラーハンドリングの機能があって助かっている。

参考

fastapi.tiangolo.com

ソースコード

pydanticのインストールも必要。

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field, PositiveInt, RootModel, ValidationError
from typing import List
from logging import getLogger, StreamHandler

logger = getLogger(__name__)
logger.addHandler(StreamHandler())
logger.setLevel("INFO")


class Product(BaseModel):
    id: int = Field(...)
    name: str = Field(...)
    cost : PositiveInt = 0

class Products(RootModel):
    root: List[Product]


app = FastAPI()

@app.get("/")
def hello():

    product = Product(id=1, name="チョコ", cost=100)
    products = Products.model_validate(product)

    return products

@app.exception_handler(ValidationError)
async def handle_validation_error(request: Request, exc: ValidationError):
    logger.info("Call Exception Handler!!")
    return JSONResponse(
        status_code=400,
        content={"message": "ValidationErrorが発生したよ"}
    )