인공지능 개발자 수다(유튜브 바로가기) 자세히보기

Fastapi

[FastAPI] 예외(Exception) 처리 방법 (10)

Suda_777 2025. 1. 4. 21:03

목차

    반응형

    1. 개요

    FastAPI에서 예외를 처리하는 대표적인 방법은 아래와 같다.

    • HTTPException 사용
    • Custom Exception 만들기
    • 예외처리 핸들러 등록하기

    2.   HTTPException 사용

    FastAPI에서 기본적으로 제공하는 예외 클래스

    간단히 사용할 때 사용.

    from fastapi import FastAPI, HTTPException
    
    app = FastAPI()
    
    @app.get("/items/{item_id}")
    async def read_item(item_id: int):
        if item_id < 1:
            raise HTTPException(status_code=400, detail="Invalid item_id")
        return {"item_id": item_id}

     


    3.  Custom 예외

    3.1. 왜 사용하는가?

    • 예외를 좀더 쉽게 추적하고 디버깅 하기위해
    • 코드의 가독성, 유지보수를 위해
    • 상태 코드와 메시지로만 예외를 구분하면 코드가 길어지고 복잡
    • 복잡한 시스템을 만들 때 사용해야 한다.

    Custom Exception 없이 예외를 처리하는 경우

    @app.get("/process")
    async def process(value: int):
        if value < 0:
            raise HTTPException(status_code=400, detail="Negative values are not allowed")
        if value > 100:
            raise HTTPException(status_code=403, detail="Value exceeds limit")
        # More conditions...

     

    Custom Exception 으로 예외를 처리하는 경우

    class NegativeValueException(Exception):
        pass
    
    class ValueExceedsLimitException(Exception):
        pass
    
    @app.get("/process")
    async def process(value: int):
        if value < 0:
            raise NegativeValueException()
        if value > 100:
            raise ValueExceedsLimitException()

     

    3.2.  예외 정의

    Custom Exception 최상위 클래스 예시

    from datetime import datetime
    
    class CustomException(Exception):
        def __init__(
            self,
            name: str,
            status_code: int,
            message: str,
            details: str = None,
            timestamp: str = None,
            request_url: str = None,
        ):
            self.name = name
            self.status_code = status_code
            self.message = message
            self.details = details
            self.timestamp = timestamp or datetime.utcnow().isoformat()
            self.request_url = request_url

     

    Custom Exception의 하위 클래스 예시 코드

    • 상위 클래스를 상속받고, 상세 속성을 세팅한다.
    class ValidationError(CustomException):
        def __init__(self, details: str, request_url: str = None):
            super().__init__(
                name="ValidationError",
                status_code=422,
                message="The provided data is invalid.",
                details=details,
                request_url=request_url,
            )

     

    class AuthenticationError(CustomException):
        def __init__(self, details: str = "Authentication failed", request_url: str = None):
            super().__init__(
                name="AuthenticationError",
                status_code=401,
                message="You are not authorized to perform this action.",
                details=details,
                request_url=request_url,
            )

     

    3.3. 예외 사용

    사용자 정의 예외 핸들러를 사용해 예외 상황을 처리할 수 있다. (HTTPException 도 사용 가능)

    @app.exception_handler(ExceptionType) 를 사용해 예외를 등록한다.

    등록한 예외가 발생하면, 정의한 함수가 실행된다.

    @app.exception_handler(ValueError)
    async def value_error_handler(request: Request, exc: ValueError):
        return JSONResponse(
            status_code=400,
            content={"error": "ValueError", "message": str(exc)},
        )
    
    @app.get("/test")
    async def test_endpoint(value: int):
        if value < 0:
            raise ValueError("Negative values are not allowed.")
        return {"value": value}

     

    예외 결과 아래와 같이 출력된다.

    {
      "error": "ValueError",
      "message": "Negative values are not allowed."
    }

    4. 전역 예외 처리

    4.1. Exception에 예외 핸들러 등록

    Exception에 예외 핸들러를 등록하면, 모든 예외에 일괄적으로 처리할 수 있다.

    @app.exception_handler(Exception)
    async def global_exception_handler(request: Request, exc: Exception):
        return JSONResponse(
            status_code=500,
            content={"message": "An unexpected error occurred"},
        )

     

    4.2. Middleware를 이용한 처리

    전역적으로 예외를 처리하려면 미들웨어를 사용할 수도 있다.

    from fastapi.middleware.trustedhost import TrustedHostMiddleware
    from starlette.middleware.base import BaseHTTPMiddleware
    from starlette.requests import Request
    from starlette.responses import JSONResponse
    
    @app.middleware("http")
    async def custom_middleware(request: Request, call_next):
        try:
            response = await call_next(request)
            return response
        except Exception as exc:
            return JSONResponse(
                status_code=500,
                content={"message": "An error occurred in middleware"},
            )

     


    5. Pydantic Validation 예외 처리

    • 기본적으로 FastAPI는 Pydantic을 사용하여 요청 데이터의 유효성을 검사한다.
    • 데이터 유효성 검사에서 문제가 발생하면 RequestValidationError가 발생
    • 사용자 정의 응답 형식을 제공하거나 디버깅 정보를 추가하려면 RequestValidationError를 커스터마이징 한다.
    • 위와 마찬가지로 @app.exception_handler() 를 사용한다.
    from fastapi import FastAPI, Request
    from fastapi.exceptions import RequestValidationError
    from fastapi.responses import JSONResponse
    
    app = FastAPI()
    
    @app.exception_handler(RequestValidationError)
    async def validation_exception_handler(request: Request, exc: RequestValidationError):
        return JSONResponse(
            status_code=422,
            content={
                "error": "Validation Error",
                "details": exc.errors(),  # 유효성 검증 오류 리스트
                "body": exc.body,         # 요청 본문
            },
        )

     

     

     

    반응형

    'Fastapi' 카테고리의 다른 글

    [FastAPI] 미들웨어(Middleware) (11)  (0) 2025.01.04
    [FastAPI] API의 Output (9)  (0) 2025.01.04
    [FastAPI] API의 Input (8)  (0) 2025.01.02
    [FastAPI] JWT 기반 인증 (7)  (1) 2025.01.01
    [FastAPI] SQLAlchemy 상세 - Delete (6-4)  (0) 2025.01.01