# services/suppliers/app/main.py """ Supplier & Procurement Service FastAPI Application """ import os from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse import structlog # Import core modules from app.core.config import settings from app.core.database import init_db, close_db from app.api import suppliers, purchase_orders, deliveries from shared.monitoring.health import router as health_router from shared.monitoring.metrics import setup_metrics_early # from shared.auth.decorators import setup_auth_middleware logger = structlog.get_logger() @asynccontextmanager async def lifespan(app: FastAPI): """Application lifespan management""" # Startup logger.info("Starting Supplier Service", version=settings.VERSION) try: # Initialize database await init_db() logger.info("Database initialized successfully") yield except Exception as e: logger.error("Startup failed", error=str(e)) raise finally: # Shutdown logger.info("Shutting down Supplier Service") try: await close_db() logger.info("Database connections closed") except Exception as e: logger.error("Shutdown error", error=str(e)) # Create FastAPI application app = FastAPI( title=settings.APP_NAME, description=settings.DESCRIPTION, version=settings.VERSION, openapi_url=f"{settings.API_V1_STR}/openapi.json", docs_url=f"{settings.API_V1_STR}/docs", redoc_url=f"{settings.API_V1_STR}/redoc", lifespan=lifespan ) # CORS middleware app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Setup metrics try: setup_metrics_early(app, "suppliers-service") logger.info("Metrics setup completed") except Exception as e: logger.error("Metrics setup failed", error=str(e)) # Setup authentication middleware (commented out - not implemented) # setup_auth_middleware(app) # Exception handlers @app.exception_handler(ValueError) async def value_error_handler(request: Request, exc: ValueError): """Handle validation errors""" return JSONResponse( status_code=400, content={ "error": "Validation Error", "detail": str(exc), "type": "value_error" } ) @app.exception_handler(Exception) async def general_exception_handler(request: Request, exc: Exception): """Handle general exceptions""" logger.error( "Unhandled exception", error=str(exc), path=request.url.path, method=request.method ) return JSONResponse( status_code=500, content={ "error": "Internal Server Error", "detail": "An unexpected error occurred", "type": "internal_error" } ) # Include routers app.include_router(health_router, prefix="/health", tags=["health"]) app.include_router(suppliers.router, prefix=settings.API_V1_STR) app.include_router(purchase_orders.router, prefix=settings.API_V1_STR) app.include_router(deliveries.router, prefix=settings.API_V1_STR) # Include enhanced performance tracking router from app.api.performance import router as performance_router app.include_router(performance_router, prefix=settings.API_V1_STR) # Root endpoint @app.get("/") async def root(): """Root endpoint with service information""" return { "service": settings.SERVICE_NAME, "version": settings.VERSION, "description": settings.DESCRIPTION, "status": "running", "docs_url": f"{settings.API_V1_STR}/docs", "health_url": "/health" } # Service info endpoint @app.get(f"{settings.API_V1_STR}/info") async def service_info(): """Service information endpoint""" return { "service": settings.SERVICE_NAME, "version": settings.VERSION, "description": settings.DESCRIPTION, "api_version": "v1", "environment": settings.ENVIRONMENT, "features": [ "supplier_management", "vendor_onboarding", "purchase_orders", "delivery_tracking", "quality_reviews", "price_list_management", "invoice_tracking", "supplier_ratings", "procurement_workflow", "performance_tracking", "performance_analytics", "supplier_scorecards", "performance_alerts", "business_model_detection", "dashboard_analytics", "cost_optimization", "risk_assessment", "benchmarking" ] } if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host="0.0.0.0", port=8000, reload=os.getenv("RELOAD", "false").lower() == "true", log_level="info" )