Files
mve-micro-docs/app/main.py

91 lines
2.5 KiB
Python

"""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
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)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=9876)