diff --git a/openbb_platform/platform/core/openbb_core/api/rest_api.py b/openbb_platform/platform/core/openbb_core/api/rest_api.py index f905dac108d..5fd051635be 100644 --- a/openbb_platform/platform/core/openbb_core/api/rest_api.py +++ b/openbb_platform/platform/core/openbb_core/api/rest_api.py @@ -10,31 +10,41 @@ from openbb_core.api.router.coverage import router as router_coverage from openbb_core.api.router.system import router as router_system from openbb_core.app.model.abstract.error import OpenBBError from openbb_core.app.service.auth_service import AuthService +from openbb_core.app.service.system_service import SystemService from openbb_core.app.version import VERSION from openbb_core.env import Env logger = logging.getLogger("uvicorn.error") +system = SystemService().system_settings + app = FastAPI( - title="OpenBB Platform API", - description="This is the OpenBB Platform API.", - version="0.0.1", - terms_of_service="http://example.com/terms/", + title=system.api_settings.title, + description=system.api_settings.description, + version=VERSION, + terms_of_service=system.api_settings.terms_of_service, contact={ - "name": "OpenBB Team", - "url": "https://openbb.co", - "email": "hello@openbb.co", + "name": system.api_settings.contact_name, + "url": system.api_settings.contact_url, + "email": system.api_settings.contact_email, }, license_info={ - "name": "MIT", - "url": "https://github.com/OpenBB-finance/OpenBBTerminal/blob/develop/LICENSE", + "name": system.api_settings.license_name, + "url": system.api_settings.license_url, }, + servers=[ + { + "url": s.url, + "description": s.description, + } + for s in system.api_settings.servers + ], ) app.add_middleware( CORSMiddleware, - allow_origins=["*"], - allow_methods=["*"], - allow_headers=["*"], + allow_origins=system.api_settings.cors.allow_origins, + allow_methods=system.api_settings.cors.allow_methods, + allow_headers=system.api_settings.cors.allow_headers, ) AppLoader.from_routers( app=app, @@ -69,7 +79,7 @@ Investment research for everyone, anywhere. @app.exception_handler(Exception) -async def api_exception_handler(request: Request, exc: Exception): +async def api_exception_handler(_: Request, exc: Exception): """Exception handler for all other exceptions.""" return JSONResponse( status_code=404, @@ -81,7 +91,7 @@ async def api_exception_handler(request: Request, exc: Exception): @app.exception_handler(OpenBBError) -async def openbb_exception_handler(request: Request, exc: OpenBBError): +async def openbb_exception_handler(_: Request, exc: OpenBBError): """Exception handler for OpenBB errors.""" openbb_error = exc.original status_code = 400 if "No results" in str(openbb_error) else 500 diff --git a/openbb_platform/platform/core/openbb_core/app/model/rest_api_settings.py b/openbb_platform/platform/core/openbb_core/app/model/rest_api_settings.py new file mode 100644 index 00000000000..d52757193ac --- /dev/null +++ b/openbb_platform/platform/core/openbb_core/app/model/rest_api_settings.py @@ -0,0 +1,41 @@ +"""FastAPI configuration settings model.""" +from functools import partial +from typing import List + +from pydantic import Field + +from openbb_core.app.model.abstract.tagged import Tagged + +FrozenField = partial(Field, frozen=True) + + +class Cors(Tagged): + """Cors model for FastAPI configuration.""" + + allow_origins: List[str] = FrozenField(default_factory=lambda: ["*"]) + allow_methods: List[str] = FrozenField(default_factory=lambda: ["*"]) + allow_headers: List[str] = FrozenField(default_factory=lambda: ["*"]) + + +class Servers(Tagged): + """Servers model for FastAPI configuration.""" + + url: str = FrozenField(default="http://localhost:8000") + description: str = FrozenField(default="Local OpenBB development server") + + +class FastAPISettings(Tagged): + """Settings model for FastAPI configuration.""" + + title: str = FrozenField(default="OpenBB Platform API") + description: str = FrozenField(default="This is the OpenBB Platform API.") + terms_of_service: str = FrozenField(default="http://example.com/terms/") + contact_name: str = FrozenField(default="OpenBB Team") + contact_url: str = FrozenField(default="https://openbb.co") + contact_email: str = FrozenField(default="hello@openbb.co") + license_name: str = FrozenField(default="MIT") + license_url: str = FrozenField( + default="https://github.com/OpenBB-finance/OpenBBTerminal/blob/develop/LICENSE" + ) + servers: List[Servers] = FrozenField(default_factory=lambda: [Servers()]) + cors: Cors = FrozenField(default_factory=Cors) diff --git a/openbb_platform/platform/core/openbb_core/app/model/system_settings.py b/openbb_platform/platform/core/openbb_core/app/model/system_settings.py index a4411f6c666..45202394f89 100644 --- a/openbb_platform/platform/core/openbb_core/app/model/system_settings.py +++ b/openbb_platform/platform/core/openbb_core/app/model/system_settings.py @@ -16,6 +16,8 @@ from openbb_core.app.constants import ( from openbb_core.app.model.abstract.tagged import Tagged from openbb_core.app.version import VERSION +from .rest_api_settings import FastAPISettings + FrozenField = partial(Field, frozen=True) @@ -46,6 +48,9 @@ class SystemSettings(Tagged): logging_suppress: bool = FrozenField(default=False) log_collect: bool = FrozenField(default=True) + # API section + api_settings: FastAPISettings = FrozenField(default_factory=FastAPISettings) + # Others test_mode: bool = FrozenField(default=False) headless: bool = FrozenField(default=False) @@ -63,7 +68,10 @@ class SystemSettings(Tagged): """Create an empty JSON file.""" path.write_text(json.dumps({}), encoding="utf-8") - @model_validator(mode="after") + # TODO: Figure out why this works only opposite to what the docs say + # https://docs.pydantic.dev/latest/concepts/validators/#model-validators + # based on docs first argument should be self, but it works only with cls + @model_validator(mode="after") # type: ignore @classmethod def create_openbb_directory(cls, values: "SystemSettings") -> "SystemSettings": """Create the OpenBB directory if it doesn't exist.""" @@ -78,7 +86,7 @@ class SystemSettings(Tagged): return values - @model_validator(mode="after") + @model_validator(mode="after") # type: ignore @classmethod def validate_posthog_handler(cls, values: "SystemSettings") -> "SystemSettings": """If the user has enabled log collection, then we need to add the Posthog."""