"""Main FastAPI application.""" import logging import sys from fastapi import FastAPI, Request, status from fastapi.responses import JSONResponse from fastapi.exceptions import RequestValidationError from contextlib import asynccontextmanager from app.core.config import get_settings from app.api import auth from app.api.v1 import incrementables, debug from app.schemas import HealthResponse # Configure logging settings = get_settings() logging.basicConfig( level=getattr(logging, settings.log_level.upper()), format='{"time": "%(asctime)s", "level": "%(levelname)s", "name": "%(name)s", "message": "%(message)s"}', stream=sys.stdout ) logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """Application lifespan manager.""" logger.info(f"Starting {settings.service_name} v{settings.service_version}") yield logger.info(f"Shutting down {settings.service_name}") # Create FastAPI app app = FastAPI( title=settings.service_name, version=settings.service_version, description="MVE Incrementables Parser - Extracts incrementables data from PDFs", lifespan=lifespan ) # Exception handlers @app.exception_handler(RequestValidationError) async def validation_exception_handler(request: Request, exc: RequestValidationError): """Handle validation errors with custom format.""" logger.warning(f"Validation error: {exc.errors()}") return JSONResponse( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content={ "detail": "Validation error", "errors": exc.errors() } ) @app.exception_handler(Exception) async def general_exception_handler(request: Request, exc: Exception): """Handle unexpected errors.""" logger.error(f"Unexpected error: {str(exc)}", exc_info=True) return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={ "detail": "Internal server error" } ) # Health check endpoint @app.get("/health", response_model=HealthResponse, tags=["Health"]) async def health_check(): """ Health check endpoint. Returns service status and version information. """ return HealthResponse( status="ok", service=settings.service_name, version=settings.service_version ) # Include routers app.include_router(auth.router) app.include_router(incrementables.router) app.include_router(debug.router) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=9876)