import contextlib import logging from collections.abc import AsyncIterator import anydi.ext.fastapi from anydi.ext.starlette.middleware import RequestScopedMiddleware from debug_toolbar.middleware import DebugToolbarMiddleware from fansifter_common.api import openapi from fansifter_common.api.middleware.query_string import QueryStringFlatteningMiddleware from fansifter_common.context import get_request_context from fansifter_common.context.asgi.middleware import ( CorrelationIdMiddleware, RequestContextMiddleware, ) from fastapi import FastAPI from jwtauth import JWTAuth from jwtauth.asgi.middleware import JWTAuthenticationMiddleware from owslogger.asgi import RequestLoggingMiddleware from starlette.middleware import Middleware from dmp.api import auth, error_handlers from dmp.api.ad_reporting.router import router as ad_reporting_router from dmp.api.artists.router import router as artists_router from dmp.api.audiences.router import router as audiences_router from dmp.api.crm_campaign.router import router as crm_campaigns_router from dmp.api.crm_sublist.router import router as crm_sublists_router from dmp.api.devtools.router import router as devtools_router from dmp.api.google.router import router as google_router from dmp.api.infra.router import router as infra_router from dmp.api.meta.router import router as meta_router from dmp.api.rosters.router import router as rosters_router from dmp.api.shopify.router import router as shopify_router from dmp.api.songwhip.router import router as songwhip_router from dmp.api.tiktok.router import router as tiktok_router from dmp.config import settings from dmp.container import container logger = logging.getLogger(__name__) def get_app() -> FastAPI: """Get FastAPI application instance.""" # Get JWTAuth instance from the container jwt_auth = container.resolve(JWTAuth) @contextlib.asynccontextmanager async def lifespan(_app: FastAPI) -> AsyncIterator[None]: """Start and close DI container on application startup and shutdown.""" async with container: yield app = FastAPI( debug=settings.debug, title=settings.service_name, version=settings.service_version, openapi_url=settings.openapi_url, description="Audience Data Management Platform", servers=settings.openapi_servers, middleware=[ Middleware(RequestScopedMiddleware, container=container), Middleware(CorrelationIdMiddleware), Middleware(RequestContextMiddleware), Middleware( RequestLoggingMiddleware, exclude_paths=["/hello/", "/openapi.json", "/docs", "/redoc"], logger=logger, ), Middleware(QueryStringFlatteningMiddleware), Middleware( JWTAuthenticationMiddleware, environment=settings.environment, enabled=settings.jwt_auth_enabled, exclude_paths=settings.jwt_auth_exclude_paths, auth=jwt_auth, request_context_func=get_request_context, ), ], lifespan=lifespan, ) if settings.debug_toolbar_enabled: app.add_middleware( DebugToolbarMiddleware, panels=[ "dmp.api.devtools.panels.default_db.DefaultDBPanel", "dmp.api.devtools.panels.reporting_db.ReportingDBPanel", ], ) # Register exception handlers error_handlers.register(app) # Include routers app.include_router(infra_router) app.include_router(artists_router) app.include_router(audiences_router) app.include_router(shopify_router) app.include_router(meta_router) app.include_router(tiktok_router) app.include_router(google_router) app.include_router(ad_reporting_router) app.include_router(rosters_router) app.include_router(songwhip_router) app.include_router(crm_campaigns_router) app.include_router(crm_sublists_router) # Include DevTools router if settings.include_devtools_router: app.include_router(devtools_router) # Extend OpenAPI schema openapi.extend( app, jwt_auth_enabled=settings.jwt_auth_enabled, jwt_auth_exclude_paths=settings.jwt_auth_exclude_paths, bearer_auth_scheme_name=auth.bearer_auth.scheme_name, ) # Install Container extension anydi.ext.fastapi.install(app, container=container) return app