"""Consistent API error handling with stable error codes.""" class ApiError(Exception): """Raised by service/domain layers; converted to a consistent response.""" def __init__(self, code: str, message: str, details=None, status: int = 400): self.code = code self.message = message self.details = details or {} self.status = status super().__init__(message) def error_response(code: str, message: str, details=None) -> dict: return {"success": False, "error": {"code": code, "message": message, "details": details or {}}} def api_exception_handler(exc, context): """DRF exception handler that emits the stable error envelope.""" from rest_framework.views import exception_handler from rest_framework.response import Response if isinstance(exc, ApiError): return Response(error_response(exc.code, exc.message, exc.details), status=exc.status) response = exception_handler(exc, context) if response is not None: if isinstance(response.data, dict) and "detail" in response.data and len(response.data) == 1: return Response( error_response("API_ERROR", str(response.data["detail"])), status=response.status_code, ) return Response(error_response("API_ERROR", "Request failed", {"errors": response.data}), status=response.status_code) return None