# Fast API 500 Exception Handler 처리

Real world에 나가기 전 서버에서 꼭 챙겨야 하는 것 중 하나는 500 error handling이다. 500 internal server error는 의도한 것도 예상했던 에러도 아니니 발견하고 빨리 고치는 수 밖엔 없다. 발생 하였을 때, 내부적으로는 자세한 로그를 남겨야 하지만, 외부로 자세한 내용을 알려줄 필요는 없다. (보안 이슈)

Fast API 공식 문서에서도 동일한 내용을 찾아 볼 수 있다.

FastAPI uses it so that, if you use a Pydantic model in response_model, and your data has an error, you will see the error in your log.

But the client/user will not see it. Instead, the client will receive an "Internal Server Error" with a HTTP status code 500.

It should be this way because if you have a Pydantic ValidationError in your response or anywhere in your code (not in the client's request), it's actually a bug in your code.

And while you fix it, your clients/users shouldn't have access to internal information about the error, as that could expose a security vulnerability.

# 기본 error handler 추가 방법

FastAPI 에서 제공하는 데코레이터를 이용하여 간편하게 @app.exception_handler 로 핸들러를 등록할 수 있다.

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

from starlette.exceptions import HTTPException as StarletteHTTPException

app = FastAPI()

@app.exception_handler(StarletteHTTPException) # Exception class로 
async def http_exception_handler(request: Request, exc):
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)

@app.exception_handler(500) # error http code로도 가능! 
async def http_500_exception_handler(request: Request, exc):
    # plain text로 응답을 보내는 경우
    return PlainTextResponse("Internal server error", status_code=exc.status_code)
    
@app.exception_handler(404)
async def http_not_found_handler(request, exc):
    # custom json 형태로 응답을 보내는 경우 
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}),
    )

만약 error handler를 세분화해서 파일 자체를 나누어야 하는 상황이라면 다음과 같이 add_exception_handler()를 이용할 수도 있다.

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

def get_application() -> FastAPI:

    application.add_exception_handler(
        Exception, exception_error_handler)
    
    return application

app = get_application()

async def exception_error_handler(_: Request, exc) -> JSONResponse:
    return JSONResponse({
        "statusCode": exc.code,
        "message": exc.message,
    }, status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)

# 근데 500 error handler가 제대로 동작 안한다

위와 같이 등록하였는데도 이상하게 400 에러에 대해서는 handler가 잘 먹히는데 500 에러 같은 경우에는 response에 계속 노출이 되었다. FastAPI 기본 설정에서 debugTrue 로 되어있으면 internal server error의 내부 로직이 그대로 계속 노출되게 된다. 기본값이 False 이니, 만약 개발 환경에서도 필요하지 않다면 아예 빼는 것도 방법이다.

from fastapi import FastAPI

server = FastAPI(
    title=app_settings.PROJECT_NAME,
    version=app_settings.VERSION,
    debug=app_settings.debug # default : False
)

# reference