import contextlib import logging from collections.abc import AsyncGenerator import anydi.ext.fastapi from anydi.ext.starlette.middleware import RequestScopedMiddleware from fansifter_common.api import openapi from fansifter_common.api.middleware.query_string import QueryStringFlatteningMiddleware from fansifter_common.context.asgi.middleware import ( CorrelationIdMiddleware, RequestContextMiddleware, ) from fastapi import FastAPI from fastapi.datastructures import Default from fastapi.responses import JSONResponse from jwtauth import JWTAuth from jwtauth.asgi.middleware import JWTAuthenticationMiddleware from owslogger.asgi import RequestLoggingMiddleware from starlette.middleware import Middleware from ows_text_campaigns.api import error_handlers from ows_text_campaigns.api.auth import bearer_auth from ows_text_campaigns.api.routers.artist import router as artist_router from ows_text_campaigns.api.routers.campaigns import router as campaigns_router from ows_text_campaigns.api.routers.domains import router as domains_router from ows_text_campaigns.api.routers.infra import router as infra_router from ows_text_campaigns.api.routers.twilio import router as twilio_router from ows_text_campaigns.config import settings from ows_text_campaigns.container import container logger = logging.getLogger(__name__) def get_app() -> FastAPI: """Get FastAPI application instance.""" # Get JWTAuth instance jwt_auth = container.resolve(JWTAuth) @contextlib.asynccontextmanager async def lifespan(_app: FastAPI) -> AsyncGenerator[None]: """Start and close DI container on application startup and shutdown.""" async with container: yield # Create FastAPI application app = FastAPI( debug=settings.debug, title=settings.service_name, version=settings.service_version, openapi_url=settings.openapi_url, description="Text Campaigns", servers=settings.openapi_servers, default_response_class=Default(JSONResponse), 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, ), ], lifespan=lifespan, ) # Register exception error handlers error_handlers.register(app) # Include API routers app.include_router(infra_router) app.include_router(artist_router) app.include_router(domains_router) app.include_router(campaigns_router) app.include_router(twilio_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=bearer_auth.scheme_name, ) # Install Container extension anydi.ext.fastapi.install(app, container=container) return app