first commit - MVE Incrementables Parser microservice with FastAPI, JWT, Celery, Redis

This commit is contained in:
Ernesto Herrera
2026-03-02 21:31:50 -07:00
commit 068d859f42
27 changed files with 2337 additions and 0 deletions

90
app/main.py Normal file
View File

@@ -0,0 +1,90 @@
"""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)