diff --git a/hyperglass/api/__init__.py b/hyperglass/api/__init__.py index 4df62b6..91ac098 100644 --- a/hyperglass/api/__init__.py +++ b/hyperglass/api/__init__.py @@ -5,6 +5,7 @@ from pathlib import Path # Third Party Imports from fastapi import FastAPI +from fastapi.exceptions import RequestValidationError from fastapi.openapi.utils import get_openapi from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.middleware.cors import CORSMiddleware @@ -13,7 +14,9 @@ from starlette.staticfiles import StaticFiles # Project Imports from hyperglass.api.error_handlers import app_handler +from hyperglass.api.error_handlers import default_handler from hyperglass.api.error_handlers import http_handler +from hyperglass.api.error_handlers import validation_handler from hyperglass.api.events import on_shutdown from hyperglass.api.events import on_startup from hyperglass.api.routes import docs @@ -60,6 +63,12 @@ app.add_exception_handler(StarletteHTTPException, http_handler) # Backend Application Error Handler app.add_exception_handler(HyperglassError, app_handler) +# Validation Error Handler +app.add_exception_handler(RequestValidationError, validation_handler) + +# Uncaught Error Handler +app.add_exception_handler(Exception, default_handler) + def _custom_openapi(): """Generate custom OpenAPI config.""" diff --git a/hyperglass/api/error_handlers.py b/hyperglass/api/error_handlers.py index b00d9cb..a8a8f97 100644 --- a/hyperglass/api/error_handlers.py +++ b/hyperglass/api/error_handlers.py @@ -1,7 +1,18 @@ """API Error Handlers.""" + # Third Party Imports from starlette.responses import UJSONResponse +from hyperglass.configuration import params + + +async def default_handler(request, exc): + """Handle uncaught errors.""" + return UJSONResponse( + {"output": params.messages.general, "level": "danger", "keywords": []}, + status_code=500, + ) + async def http_handler(request, exc): """Handle web server errors.""" @@ -17,3 +28,12 @@ async def app_handler(request, exc): {"output": exc.message, "level": exc.level, "keywords": exc.keywords}, status_code=exc.status_code, ) + + +async def validation_handler(request, exc): + """Handle Pydantic validation errors raised by FastAPI.""" + error = exc.errors()[0] + return UJSONResponse( + {"output": error["msg"], "level": "error", "keywords": error["loc"]}, + status_code=400, + )