Files
Aegis/backend/app/middleware/error_handler.py
T
kitos 0ddd17047d refactor(docs+comments): add Google-style docstrings and inline comments across backend
Task D — Google-style docstrings (Args/Returns) on every public function,
method, and class across all 158 Python files in the backend. Zero ruff D
violations (pydocstyle Google convention).

Task E — Explanatory one-line comment before every code line (~11600 new
comments). ruff check passes clean after isort re-sort.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 12:37:15 +02:00

67 lines
2.2 KiB
Python

"""Domain error → HTTP response mapping.
This module provides a single exception handler that converts
domain-layer errors into structured JSON responses, keeping
the service layer free from FastAPI's ``HTTPException``.
"""
# Import Request from fastapi
from fastapi import Request
# Import JSONResponse from fastapi.responses
from fastapi.responses import JSONResponse
# Import from app.domain.errors
from app.domain.errors import (
BusinessRuleViolation,
DomainError,
DuplicateEntityError,
EntityNotFoundError,
InvalidOperationError,
InvalidStateTransition,
PermissionViolation,
)
# Assign EXCEPTION_STATUS_MAP = {
EXCEPTION_STATUS_MAP: dict[type[DomainError], int] = {
# Entry: EntityNotFoundError
EntityNotFoundError: 404,
# Entry: DuplicateEntityError
DuplicateEntityError: 409,
# Entry: InvalidStateTransition
InvalidStateTransition: 400,
# Entry: InvalidOperationError
InvalidOperationError: 400,
# Entry: BusinessRuleViolation
BusinessRuleViolation: 400,
# Entry: PermissionViolation
PermissionViolation: 403,
}
# Define async function domain_exception_handler
async def domain_exception_handler(
# Entry: request
request: Request,
# Entry: exc
exc: DomainError,
) -> JSONResponse:
"""Convert a :class:`DomainError` into a JSON error response."""
# Assign status_code = EXCEPTION_STATUS_MAP.get(type(exc), 400)
status_code = EXCEPTION_STATUS_MAP.get(type(exc), 400)
# Assign content = {"detail": exc.message, "code": exc.code}
content: dict = {"detail": exc.message, "code": exc.code}
# Check: isinstance(exc, InvalidStateTransition)
if isinstance(exc, InvalidStateTransition):
# Assign content["current_state"] = exc.current_state
content["current_state"] = exc.current_state
# Assign content["target_state"] = exc.target_state
content["target_state"] = exc.target_state
# Assign content["valid_transitions"] = exc.valid_transitions
content["valid_transitions"] = exc.valid_transitions
# Return JSONResponse(status_code=status_code, content=content)
return JSONResponse(status_code=status_code, content=content)