From 19d7f17310028f24c321870d8b83f12c8b439d06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Tue, 14 Nov 2023 16:11:15 +0100 Subject: [PATCH] add cors headers in exception handler in cors --- pkgs/clan-cli/clan_cli/webui/app.py | 29 ++--------- .../clan-cli/clan_cli/webui/error_handlers.py | 48 ++++++++++++++----- pkgs/clan-cli/clan_cli/webui/settings.py | 32 +++++++++++++ pkgs/clan-cli/tests/api.py | 2 +- 4 files changed, 72 insertions(+), 39 deletions(-) create mode 100644 pkgs/clan-cli/clan_cli/webui/settings.py diff --git a/pkgs/clan-cli/clan_cli/webui/app.py b/pkgs/clan-cli/clan_cli/webui/app.py index 98556fa20..3cf6d9b0f 100644 --- a/pkgs/clan-cli/clan_cli/webui/app.py +++ b/pkgs/clan-cli/clan_cli/webui/app.py @@ -1,47 +1,24 @@ import logging -import os -from enum import Enum from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.routing import APIRoute from fastapi.staticfiles import StaticFiles -from ..errors import ClanError from .assets import asset_path from .error_handlers import clan_error_handler from .routers import clan_modules, flake, health, machines, root, vms +from .settings import settings from .tags import tags_metadata # Logging setup log = logging.getLogger(__name__) -class EnvType(Enum): - production = "production" - development = "development" - - @staticmethod - def from_environment() -> "EnvType": - t = os.environ.get("CLAN_WEBUI_ENV", "production") - try: - return EnvType[t] - except KeyError: - log.warning(f"Invalid environment type: {t}, fallback to production") - return EnvType.production - - def is_production(self) -> bool: - return self == EnvType.production - - def is_development(self) -> bool: - return self == EnvType.development - - def setup_app() -> FastAPI: - env = EnvType.from_environment() app = FastAPI() - if env.is_development(): + if settings.env.is_development(): # Allow CORS in development mode for nextjs dev server app.add_middleware( CORSMiddleware, @@ -59,7 +36,7 @@ def setup_app() -> FastAPI: # Needs to be last in register. Because of wildcard route app.include_router(root.router) - app.add_exception_handler(ClanError, clan_error_handler) + app.add_exception_handler(Exception, clan_error_handler) app.mount("/static", StaticFiles(directory=asset_path()), name="static") diff --git a/pkgs/clan-cli/clan_cli/webui/error_handlers.py b/pkgs/clan-cli/clan_cli/webui/error_handlers.py index d14e4ce50..4f815999b 100644 --- a/pkgs/clan-cli/clan_cli/webui/error_handlers.py +++ b/pkgs/clan-cli/clan_cli/webui/error_handlers.py @@ -5,20 +5,44 @@ from fastapi.encoders import jsonable_encoder from fastapi.responses import JSONResponse from ..errors import ClanError +from .settings import settings log = logging.getLogger(__name__) def clan_error_handler(request: Request, exc: Exception) -> JSONResponse: - assert isinstance(exc, ClanError) - log.error("ClanError: %s", exc) - detail = [ - { - "loc": [], - "msg": str(exc), - } - ] - return JSONResponse( - status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, - content=jsonable_encoder(dict(detail=detail)), - ) + headers = {} + + if settings.env.is_development(): + headers["Access-Control-Allow-Origin"] = "*" + headers["Access-Control-Allow-Methods"] = "*" + + if isinstance(exc, ClanError): + log.error(f"ClanError: {exc}") + detail = [ + { + "loc": [], + "msg": str(exc), + } + ] + return JSONResponse( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + content=jsonable_encoder(dict(detail=detail)), + headers=headers, + ) + else: + log.exception(f"Unhandled Exception: {exc}") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content=jsonable_encoder( + dict( + detail=[ + { + "loc": [], + "msg": str(exc), + } + ] + ) + ), + headers=headers, + ) diff --git a/pkgs/clan-cli/clan_cli/webui/settings.py b/pkgs/clan-cli/clan_cli/webui/settings.py new file mode 100644 index 000000000..115dd7fc7 --- /dev/null +++ b/pkgs/clan-cli/clan_cli/webui/settings.py @@ -0,0 +1,32 @@ +import logging +import os +from enum import Enum + +log = logging.getLogger(__name__) + + +class EnvType(Enum): + production = "production" + development = "development" + + @staticmethod + def from_environment() -> "EnvType": + t = os.environ.get("CLAN_WEBUI_ENV", "production") + try: + return EnvType[t] + except KeyError: + log.warning(f"Invalid environment type: {t}, fallback to production") + return EnvType.production + + def is_production(self) -> bool: + return self == EnvType.production + + def is_development(self) -> bool: + return self == EnvType.development + + +class Settings: + env = EnvType.from_environment() + + +settings = Settings() diff --git a/pkgs/clan-cli/tests/api.py b/pkgs/clan-cli/tests/api.py index 3f3f9497c..d7b07d8fb 100644 --- a/pkgs/clan-cli/tests/api.py +++ b/pkgs/clan-cli/tests/api.py @@ -11,4 +11,4 @@ from clan_cli.webui.app import app def api() -> TestClient: # logging.getLogger("httpx").setLevel(level=logging.WARNING) logging.getLogger("asyncio").setLevel(logging.INFO) - return TestClient(app) + return TestClient(app, raise_server_exceptions=False)