Files
blog.pyaqa.ru/app/infrastructure/middleware/error_handler.py
Sergey Vanyushkin ca4e8877a5 docs: add AI code generation requirements and comprehensive Google-style docstrings
- Add AI code generation requirements to AGENTS.md
- Add module-level docstrings to all 46 Python modules
- Add detailed Google-style docstrings to all classes and functions
- Remove all inline comments following self-documenting code principle
- Include Args, Returns, Raises sections in function docstrings
- Add Attributes and Examples sections to class docstrings
2026-05-02 13:15:21 +03:00

132 lines
3.5 KiB
Python

"""Exception handling middleware.
This module provides exception handlers for FastAPI application.
Maps domain exceptions to appropriate HTTP status codes.
"""
from datetime import UTC, datetime
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
from app.domain.exceptions import (
AlreadyExistsException,
DomainException,
ForbiddenException,
NotFoundException,
UnauthorizedException,
ValidationException,
)
def get_status_code(exc: DomainException) -> int:
"""Map domain exceptions to HTTP status codes.
Args:
exc: Domain exception instance.
Returns:
HTTP status code for the exception type.
"""
match exc:
case ValidationException():
return 400
case UnauthorizedException():
return 401
case ForbiddenException():
return 403
case NotFoundException():
return 404
case AlreadyExistsException():
return 409
case _:
return 500
async def domain_exception_handler(request: Request, exc: DomainException) -> JSONResponse:
"""Handle domain exceptions.
Converts domain exceptions to JSON error responses.
Args:
request: FastAPI request object.
exc: Domain exception instance.
Returns:
JSONResponse with error details.
"""
status_code = get_status_code(exc)
return JSONResponse(
status_code=status_code,
content={
"error": exc.__class__.__name__,
"message": exc.message,
"timestamp": datetime.now(UTC).isoformat(),
"path": str(request.url.path),
},
)
async def http_exception_handler(request: Request, exc: StarletteHTTPException) -> JSONResponse:
"""Handle HTTP exceptions.
Converts Starlette HTTP exceptions to JSON error responses.
Args:
request: FastAPI request object.
exc: Starlette HTTP exception instance.
Returns:
JSONResponse with error details.
"""
return JSONResponse(
status_code=exc.status_code,
content={
"error": "HTTPException",
"message": str(exc.detail),
"timestamp": datetime.now(UTC).isoformat(),
"path": str(request.url.path),
},
)
async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse:
"""Handle generic exceptions.
Converts unhandled exceptions to generic error responses.
Hides internal details for security.
Args:
request: FastAPI request object.
exc: Generic exception instance.
Returns:
JSONResponse with generic error message.
"""
return JSONResponse(
status_code=500,
content={
"error": "InternalServerError",
"message": "An unexpected error occurred",
"timestamp": datetime.now(UTC).isoformat(),
"path": str(request.url.path),
},
)
def register_exception_handlers(app: FastAPI) -> None:
"""Register all exception handlers with FastAPI app.
Args:
app: FastAPI application instance.
Raises:
TypeError: If app is not a FastAPI instance.
"""
if not isinstance(app, FastAPI):
raise TypeError("app must be a FastAPI instance")
app.add_exception_handler(DomainException, domain_exception_handler) # type: ignore[arg-type]
app.add_exception_handler(StarletteHTTPException, http_exception_handler) # type: ignore[arg-type]