import contextlib import logging from collections.abc import AsyncIterator import anydi.ext.fastapi from anydi.ext.starlette.middleware import RequestScopedMiddleware from fansifter_common.api import openapi from fansifter_common.context.asgi.middleware import ( CorrelationIdMiddleware, RequestContextMiddleware, ) from fastapi import FastAPI from jwtauth import JWTAuth from jwtauth.asgi.middleware import JWTAuthenticationMiddleware from starlette.middleware import Middleware from preference_center.api import error_handlers from preference_center.api.middleware.logger import RequestLoggerMiddleware from preference_center.api.routers.debug import router as debug_router from preference_center.api.routers.double_opt_in import router as double_opt_in_router from preference_center.api.routers.profile import router as profile_router from preference_center.api.routers.songwhip import router as songwhip_router from preference_center.config import settings from preference_center.container import container def get_app() -> FastAPI: """Get FastAPI application instance.""" # Get JWTAuth instance jwt_auth = container.resolve(JWTAuth) @contextlib.asynccontextmanager async def lifespan(_app: FastAPI) -> AsyncIterator[None]: """Start and close DI container on application startup and shutdown.""" await container.astart() yield await container.aclose() # Create FastAPI application app = FastAPI( debug=settings.debug, title=settings.service_name, version=settings.service_version, openapi_url=settings.openapi_url, description="Preference Center", servers=settings.openapi_servers, middleware=[ Middleware(RequestScopedMiddleware, container=container), Middleware(CorrelationIdMiddleware), Middleware(RequestContextMiddleware), Middleware( RequestLoggerMiddleware, exclude_paths=["/hello/", "/openapi.json", "/docs"], logger=logging.getLogger(__name__), ), Middleware( JWTAuthenticationMiddleware, environment=settings.environment, enabled=settings.jwt_auth_enabled, exclude_paths=settings.jwt_auth_exclude_paths, auth=jwt_auth, ), ], lifespan=lifespan, ) # Extend OpenAPI openapi.extend(app) # Register exception handlers error_handlers.register(app) # Include routers app.include_router(profile_router) app.include_router(songwhip_router) app.include_router(double_opt_in_router) if settings.include_debug_router: app.include_router(debug_router) # Install Container extension anydi.ext.fastapi.install(app, container=container) return app