58 lines
1.8 KiB
Python
58 lines
1.8 KiB
Python
from __future__ import annotations
|
|
import uuid, traceback
|
|
from django.conf import settings
|
|
from rest_framework.views import exception_handler as drf_exception_handler
|
|
from rest_framework.response import Response
|
|
from rest_framework import status
|
|
from rest_framework.exceptions import ValidationError as DRFValidationError
|
|
from pydantic import ValidationError as PydValidationError
|
|
|
|
def envelope_exception_handler(exc, context):
|
|
"""
|
|
Envuelve *todas* las excepciones DRF en:
|
|
{ ok: false, code, message, errors?, hint?, trace_id, detail?(DEBUG) }
|
|
"""
|
|
resp = drf_exception_handler(exc, context)
|
|
trace_id = str(uuid.uuid4())
|
|
|
|
if resp is not None:
|
|
# DRF ya resolvió un status_code razonable
|
|
code = getattr(exc, "default_code", "error")
|
|
message = None
|
|
|
|
if isinstance(exc, DRFValidationError):
|
|
message = "Validation error"
|
|
else:
|
|
# fallback a string corto
|
|
message = str(getattr(exc, "detail", "")) or exc.__class__.__name__
|
|
|
|
data = {
|
|
"ok": False,
|
|
"code": code,
|
|
"message": message,
|
|
"errors": resp.data, # DRF normaliza los errores aquí
|
|
"hint": None,
|
|
"trace_id": trace_id,
|
|
}
|
|
if settings.DEBUG:
|
|
data["detail"] = _short_trace()
|
|
return Response(data, status=resp.status_code)
|
|
|
|
# Excepción no manejada por DRF -> 500
|
|
data = {
|
|
"ok": False,
|
|
"code": "server_error",
|
|
"message": "Unexpected server error",
|
|
"hint": None,
|
|
"trace_id": trace_id,
|
|
}
|
|
if settings.DEBUG:
|
|
data["detail"] = _short_trace()
|
|
return Response(data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
|
|
def _short_trace():
|
|
try:
|
|
return "\n".join(traceback.format_exc().splitlines()[-6:])
|
|
except Exception:
|
|
return None
|