import contextlib from collections.abc import AsyncIterator import pyxdi.ext.fastapi from audience_common.auth.jwt import JWTAuth from audience_common.ext.starlette.middleware.auth import JWTAuthenticationMiddleware from audience_common.ext.starlette.middleware.context import ( CorrelationIdMiddleware, RequestContextMiddleware, ) from audience_common.ext.starlette.middleware.logger import RequestLoggerMiddleware from audience_common.ext.starlette.middleware.query_string import ( QueryStringFlatteningMiddleware, ) from audience_common.ext.starlette.responses import ORJSONResponse from fastapi import FastAPI from fastapi.datastructures import Default from starlette.middleware import Middleware from campaigns.api import error_handlers, openapi from campaigns.api.routers.assets import router as assets_router from campaigns.api.routers.campaigns import router as campaigns_router from campaigns.api.routers.errors import router as errors_router from campaigns.api.routers.facebook import router as facebook_router from campaigns.api.routers.infra import router as infra_router from campaigns.api.routers.meta import router as meta_router from campaigns.api.routers.test import router as test_router from campaigns.config import AppSettings def get_application(di: pyxdi.PyxDI) -> FastAPI: """Create FastAPI application.""" settings = di.get_instance(AppSettings) jwt_auth = di.get_instance(JWTAuth) @contextlib.asynccontextmanager async def lifespan(_app: FastAPI) -> AsyncIterator[None]: """Start and close DI container on application startup and shutdown.""" await di.astart() yield await di.aclose() app = FastAPI( debug=settings.debug, title=settings.service_name, version=settings.service_version, openapi_url=settings.openapi_url, description="Fansifter Campaigns Management Service", servers=settings.openapi_servers, default_response_class=Default(ORJSONResponse), middleware=[ Middleware(CorrelationIdMiddleware), Middleware(RequestContextMiddleware), Middleware( RequestLoggerMiddleware, exclude_paths=[ "/hello/", "/openapi.json", "/docs", ], extra_headers=settings.debug, ), Middleware(QueryStringFlatteningMiddleware), 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(infra_router) app.include_router(errors_router) app.include_router(assets_router) app.include_router(campaigns_router) app.include_router(facebook_router) app.include_router(meta_router) # Include testing router if settings.include_test_router: app.include_router(test_router) # Install PyxDI extension pyxdi.ext.fastapi.install(app, di=di) return app