From ef657c4939d5454dce9a05bdf5d2d59618880192 Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Fri, 31 Oct 2025 11:29:24 +0400 Subject: [PATCH] refactor: cleaned main file --- core/__init__.py | 4 +++ core/app_settings.py | 11 ++++++ core/exceptions.py | 17 +++++++++ core/lifespan.py | 16 +++++++++ core/middlewares.py | 19 ++++++++++ logger/builder.py | 2 +- main.py | 68 +++++++++--------------------------- {core => utils}/singleton.py | 0 8 files changed, 84 insertions(+), 53 deletions(-) create mode 100644 core/__init__.py create mode 100644 core/app_settings.py create mode 100644 core/exceptions.py create mode 100644 core/lifespan.py create mode 100644 core/middlewares.py rename {core => utils}/singleton.py (100%) diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..4d839bf --- /dev/null +++ b/core/__init__.py @@ -0,0 +1,4 @@ +from .lifespan import lifespan as lifespan +from .app_settings import settings as settings +from .middlewares import register_middlewares as register_middlewares +from .exceptions import register_exception_handlers as register_exception_handlers diff --git a/core/app_settings.py b/core/app_settings.py new file mode 100644 index 0000000..cb0fb82 --- /dev/null +++ b/core/app_settings.py @@ -0,0 +1,11 @@ +from fastapi.responses import ORJSONResponse + + +class Settings: + ROOT_PATH = "/api" + DEFAULT_RESPONSE_CLASS = ORJSONResponse + ORIGINS = ["http://localhost:3000"] + STATIC_DIR = "static" + + +settings = Settings() diff --git a/core/exceptions.py b/core/exceptions.py new file mode 100644 index 0000000..a0f2efa --- /dev/null +++ b/core/exceptions.py @@ -0,0 +1,17 @@ +from fastapi import Request +from fastapi.applications import AppType +from starlette.responses import JSONResponse + +from utils.exceptions import ObjectNotFoundException, ForbiddenException + + +def register_exception_handlers(app: AppType): + @app.exception_handler(ObjectNotFoundException) + async def not_found_exception_handler( + request: Request, exc: ObjectNotFoundException + ): + return JSONResponse(status_code=404, content={"detail": exc.name}) + + @app.exception_handler(ForbiddenException) + async def forbidden_exception_handler(request: Request, exc: ForbiddenException): + return JSONResponse(status_code=403, content={"detail": exc.name}) diff --git a/core/lifespan.py b/core/lifespan.py new file mode 100644 index 0000000..8ed3285 --- /dev/null +++ b/core/lifespan.py @@ -0,0 +1,16 @@ +import contextlib + +from fastapi.applications import AppType + +from task_management import broker + + +@contextlib.asynccontextmanager +async def lifespan(app: AppType): + if not broker.is_worker_process: + await broker.startup() + + yield + + if not broker.is_worker_process: + await broker.shutdown() diff --git a/core/middlewares.py b/core/middlewares.py new file mode 100644 index 0000000..b42ad32 --- /dev/null +++ b/core/middlewares.py @@ -0,0 +1,19 @@ +from fastapi.applications import AppType +from fastapi.middleware.cors import CORSMiddleware +from fastapi.middleware.gzip import GZipMiddleware + +from .app_settings import settings + + +def register_middlewares(app: AppType): + app.add_middleware( + CORSMiddleware, + allow_origins=settings.ORIGINS, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + app.add_middleware( + GZipMiddleware, + minimum_size=1_000, + ) diff --git a/logger/builder.py b/logger/builder.py index 70b3df1..9c6f8c4 100644 --- a/logger/builder.py +++ b/logger/builder.py @@ -10,7 +10,7 @@ from logger.constants import ( from logger.formatter import JsonFormatter from logger.gunzip_rotating_file_handler import GunZipRotatingFileHandler from logger.filters import LevelFilter, RequestIdFilter -from core.singleton import Singleton +from utils.singleton import Singleton class LoggerBuilder(metaclass=Singleton): diff --git a/main.py b/main.py index d8be8aa..12ba079 100644 --- a/main.py +++ b/main.py @@ -1,64 +1,28 @@ -import contextlib - import taskiq_fastapi -from fastapi import FastAPI, Request -from fastapi.middleware.cors import CORSMiddleware -from fastapi.middleware.gzip import GZipMiddleware -from fastapi.responses import ORJSONResponse +from fastapi import FastAPI from fastapi.staticfiles import StaticFiles -from starlette.responses import JSONResponse import routers +from core import lifespan, settings, register_middlewares, register_exception_handlers from task_management import broker from utils.auto_include_routers import auto_include_routers -from utils.exceptions import * - -origins = ["http://localhost:3000"] -@contextlib.asynccontextmanager -async def lifespan(app): - if not broker.is_worker_process: - await broker.startup() +def create_app() -> FastAPI: + app = FastAPI( + separate_input_output_schemas=True, + default_response_class=settings.DEFAULT_RESPONSE_CLASS, + root_path=settings.ROOT_PATH, + lifespan=lifespan, + ) - yield + register_middlewares(app) + register_exception_handlers(app) + auto_include_routers(app, routers, full_path=True) + app.mount("/static", StaticFiles(directory=settings.STATIC_DIR), name="static") - if not broker.is_worker_process: - await broker.shutdown() + taskiq_fastapi.init(broker, "main:app") + return app -app = FastAPI( - separate_input_output_schemas=True, - default_response_class=ORJSONResponse, - root_path="/api", - # lifespan=lifespan, -) - -app.add_middleware( - CORSMiddleware, - allow_origins=origins, - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) -app.add_middleware( - GZipMiddleware, - minimum_size=1_000, -) - -taskiq_fastapi.init(broker, "main:app") - - -@app.exception_handler(ObjectNotFoundException) -async def not_found_exception_handler(request: Request, exc: ObjectNotFoundException): - return JSONResponse(status_code=404, content={"detail": exc.name}) - - -@app.exception_handler(ForbiddenException) -async def forbidden_exception_handler(request: Request, exc: ForbiddenException): - return JSONResponse(status_code=403, content={"detail": exc.name}) - - -auto_include_routers(app, routers, True) - -app.mount("/static", StaticFiles(directory="static"), name="static") +app = create_app() diff --git a/core/singleton.py b/utils/singleton.py similarity index 100% rename from core/singleton.py rename to utils/singleton.py