Files
secure-online-shop/app/core/exceptions.py
T

83 lines
2.9 KiB
Python

from __future__ import annotations
import logging
from fastapi import FastAPI, HTTPException, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from sqlalchemy.exc import SQLAlchemyError
logger = logging.getLogger("app.errors")
class AppError(Exception):
def __init__(self, status_code: int, detail: str) -> None:
self.status_code = status_code
self.detail = detail
super().__init__(detail)
class BadRequestError(AppError):
def __init__(self, detail: str = "Bad request") -> None:
super().__init__(status.HTTP_400_BAD_REQUEST, detail)
class UnauthorizedError(AppError):
def __init__(self, detail: str = "Authentication failed") -> None:
super().__init__(status.HTTP_401_UNAUTHORIZED, detail)
class ForbiddenError(AppError):
def __init__(self, detail: str = "Access denied") -> None:
super().__init__(status.HTTP_403_FORBIDDEN, detail)
class NotFoundError(AppError):
def __init__(self, detail: str = "Resource not found") -> None:
super().__init__(status.HTTP_404_NOT_FOUND, detail)
class ConflictError(AppError):
def __init__(self, detail: str = "Conflict detected") -> None:
super().__init__(status.HTTP_409_CONFLICT, detail)
class TooManyRequestsError(AppError):
def __init__(self, detail: str = "Too many requests") -> None:
super().__init__(status.HTTP_429_TOO_MANY_REQUESTS, detail)
def register_exception_handlers(app: FastAPI) -> None:
@app.exception_handler(AppError)
async def handle_app_error(_: Request, exc: AppError) -> JSONResponse:
return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})
@app.exception_handler(HTTPException)
async def handle_http_exception(_: Request, exc: HTTPException) -> JSONResponse:
return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})
@app.exception_handler(RequestValidationError)
async def handle_validation_error(
_: Request, exc: RequestValidationError
) -> JSONResponse:
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={"detail": "Validation error"},
)
@app.exception_handler(SQLAlchemyError)
async def handle_database_error(_: Request, exc: SQLAlchemyError) -> JSONResponse:
logger.exception("Database operation failed")
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={"detail": "Internal server error"},
)
@app.exception_handler(Exception)
async def handle_unexpected_error(_: Request, exc: Exception) -> JSONResponse:
logger.exception("Unhandled application error")
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={"detail": "Internal server error"},
)