에러를 처리하기 위해서 보통 try, except문을 사용한다. 하지만 에러가 발생하는 모든 상횡에 대해 try문을 작성하는것은 비효율적이다.

HTTPException 사용하여 에러 내기

from fastapi import FastAPI, HTTPException, status

app = FastAPI()

users = {
    1: {"name": "Hi"},
    2: {"name": "Hello"},
    3: {"name": "안녕"},
}


@app.get("/users/{user_id}")
async def get_user(user_id: int):
    if user_id not in users.keys():
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"<User: {user_id}> is not exists.",
        )
    return users[user_id]

image

HTTPException을 이용하면 detail로 상세한 에러 정보를 알려줄 수 있지만 서버나 클라이언트 딴에서도 이 detail 문을 확인해야 에러 정보를 확인할 수 있기 때문에 좋은 방법은 아니다. 그래서 보통은 사용자 정의 에러를 만든다.

사용자 정의 에러

사용자 정의 에러를 만들기 위해서는 Exception 클래스를 상속받아야 한다.

from fastapi import FastAPI

app = FastAPI()


class SomeError(Exception):
    def __init__(self, name: str, code: int):
        self.name = name
        self.code = code

    def __str__(self):
        return f"<{self.name}> is occured. code: <{self.code}>"


app = FastAPI()


@app.get("/error")
async def get_error():
    raise SomeError("Hello", 511)

image

위에서 확인할 수 있는 에러 코는 500으로 서버에서 에러가 났기 때문에 클라이언트는 어디서 에러가 일어났는지 모른다. 따라서 아래와 같이 에러를 처리할 핸들러를 만든다.

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()


class SomeError(Exception):
    def __init__(self, name: str, code: int):
        self.name = name
        self.code = code

    def __str__(self):
        return f"<{self.name}> is occured. code: <{self.code}>"


app = FastAPI()


@app.exception_handler(SomeError)
async def some_error_handler(request: Request, exc: SomeError):
    return JSONResponse(
        content={"message": f"error is {exc.name}"}, status_code=exc.code
    )


@app.get("/error")
async def get_error():
    raise SomeError("Hello", 511)

에러코드가 511으로 바뀐것을 볼 수 있다.

image

방금은 파이썬 Exception을 상속받았다면, 이번에는 FastAPI의 HTTPException을 상속받아 에러를 정의해보자. 이 방법은 exception handler를 사용할 필요가 없다.

from typing import Any, Optional, Dict

from fastapi import FastAPI, HTTPException


class SomeFastAPIError(HTTPException):
    def __init__(
        self,
        status_code: int,
        detail: Any = None,
        headers: Optional[Dict[str, Any]] = None,
    ) -> None:
        super().__init__(
            status_code=status_code, detail=detail, headers=headers
        )


app = FastAPI()


@app.get("/error")
async def get_error():
    raise SomeFastAPIError(511, "Hello")