Volver a la wiki

global_exception_handler · Manejador global de excepciones API

Descripción

Handler global de excepciones para todos los ~509 endpoints de la API Ninja de CreaRack. Se encarga de capturar cualquier excepción no manejada en los endpoints y traducirla a una respuesta HTTP 500 estandarizada.

Ubicación: config/urls.py

Función pública: global_exception_handler(request, exc) → Response

Interfaz

@api.exception_handler(Exception)
def global_exception_handler(request, exc):
    """
    Handler registrado globalmente en la API Ninja.
    
    Args:
        request: HttpRequest del endpoint que falló.
        exc: Exception capturada.
    
    Returns:
        Response HTTP 500 con cuerpo estandarizado.
    """

Comportamiento

Producción (DEBUG=False)

Respuesta al cliente:

{
  "error": "Internal server error"
}

Logs (registro en api.errors):

ERROR:api.errors:Unhandled API error on GET /api/racks/list
  <full traceback con exc_info=exc>

Motivación: Evitar fuga de información sensible (rutas internas, SQL, hosts).

Desarrollo local (DEBUG=True)

Respuesta al cliente:

{
  "error": "Internal server error",
  "detail": "<str(exc)>",
  "type": "ExceptionClassName"
}

Logs: Igual que en producción.

Motivación: Facilitar debugging local sin perder contexto.

Componentes internos

Logger (_api_logger)

Cuerpo de respuesta

Contexto histórico

Antes (hasta commit 4e82336): El handler devolvía {"error": str(exc), "type": exc.__class__.__name__} incondicionalmente, exponiendo información sensible (rutas del servidor, consultas SQL, nombres de máquinas) a cualquier cliente que provocara un error.

Hallazgo s105: Auditoría de seguridad (Auditoría Suprema Etapa 3 · T4) identificó esto como fuga de información transversal a todos los endpoints.

Cambio (commit 4e82336): Implementación del nuevo handler con cierre de fuga (decision T4).

Extensión a manejadores locales (D1-04, mega-auditoría 24-09-2026, v1.157.0)

El handler global solo actúa cuando ningún except local atrapa antes la excepción. Catorce endpoints seguían con su propio except Exception as e: return N, {"message": str(e)} — el handler global nunca llegaba a verlos, así que el mismo texto crudo (rutas, SQL, mensajes de librerías) se colaba igual, endpoint a endpoint:

Mismo patrón que el handler global: logger.exception("<contexto>") deja el detalle en el log, la respuesta HTTP pasa a un mensaje fijo con el mismo código. Los errores de dominio pensados para que el usuario los lea se conservan aparte (capturados por su tipo, no por Exception genérico): SVG no válido al crear un stencil, o ZIP con ruta insegura/demasiado grande al analizar una restauración (este último además pasa de 500 a 400, que es el código que le corresponde). En racks/services/library.py, el servicio de importación de Visio envolvía cualquier fallo en ValueError(f"Parsing failed: {e}") que el endpoint devolvía tal cual — ahora registra el detalle y relanza ValueError("Parsing failed") fijo; como contrapartida, los avisos propios del parser (formato no soportado, sin figuras) también se ven solo como “Parsing failed”.

Límite honesto: terminal/api/sentinel_ingest.py (ingesta del Agente local) se queda igual, con "error": str(e) en su 500 — un test existente (tests/api/test_bulk_ingest_honest_status.py) exige ahí el texto crudo. Cambiarlo es una decisión de producto aparte, no un olvido.

Pruebas

Archivo: tests/api/test_t4_exception_handler.py

Impacto en endpoints

Alcance: Todos los ~509 endpoints de la API Ninja (handler global) + 14 endpoints con manejo local propio (D1-04, v1.157.0).

Cambio observable en el cliente:

Verificación: Nadie en el codebase consumía el campo type del 500 → frontend sin cambios necesarios.

Configuración

Dependencias:

Registración: Se registra globalmente en la instancia api de Ninja a través del decorador @api.exception_handler(Exception).

Véase también

Subir