import logging from contextlib import asynccontextmanager from fastapi import FastAPI, Request, status from starlette.middleware.sessions import SessionMiddleware from fastapi.responses import RedirectResponse from starlette.staticfiles import StaticFiles from config import settings from database import init_db, AsyncSessionLocal from repositories.endpoint_repository import EndpointRepository from services.route_service import RouteManager from middleware.auth_middleware import AuthMiddleware from controllers.admin_controller import router as admin_router from oauth2 import oauth_router logging.basicConfig( level=logging.DEBUG if settings.debug else logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", ) logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """ Lifespan context manager for startup and shutdown events. """ # Startup logger.info("Initializing database...") await init_db() # Use the route manager already attached to app.state route_manager = app.state.route_manager logger.info("Refreshing routes...") await route_manager.refresh_routes() logger.info("Application startup complete.") yield # Shutdown logger.info("Application shutting down...") def create_app() -> FastAPI: """ Factory function to create and configure the FastAPI application. """ app = FastAPI( title=settings.title, version=settings.version, debug=settings.debug, lifespan=lifespan, ) # Attach route manager and session factory to app.state before any request route_manager = RouteManager(app, AsyncSessionLocal) app.state.route_manager = route_manager app.state.session_factory = AsyncSessionLocal # Add authentication middleware for admin routes (must be after SessionMiddleware) app.add_middleware(AuthMiddleware) # Add session middleware (must be before AuthMiddleware, but add_middleware prepends) app.add_middleware( SessionMiddleware, secret_key=settings.secret_key, session_cookie=settings.session_cookie_name, max_age=settings.session_max_age, https_only=False, same_site="lax", ) # Mount static files (optional, for future) # app.mount("/static", StaticFiles(directory="app/static"), name="static") # Add a simple health check endpoint @app.get("/health") async def health_check(): return {"status": "healthy", "service": "mock-api"} # Redirect root to Swagger documentation @app.get("/") async def root_redirect(): """Redirect the root URL to Swagger documentation.""" return RedirectResponse(url="/docs", status_code=status.HTTP_302_FOUND) # Include admin controller routes app.include_router(admin_router) # Include OAuth2 routes app.include_router(oauth_router) return app # Create the application instance app = create_app()