from uuid import uuid4 from fastapi import FastAPI, HTTPException, Request from fastapi.exceptions import RequestValidationError from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from sqlalchemy import text from app.api.router import api_router from app.core.config import get_settings from app.core.database import SessionLocal settings = get_settings() app = FastAPI( title="Maskan CRM API", version="0.1.0", docs_url="/api/docs", openapi_url="/api/openapi.json", ) app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) def error_response( *, request: Request, status_code: int, code: str, message: str, details: object | None = None, ) -> JSONResponse: request_id = getattr(request.state, "request_id", str(uuid4())) return JSONResponse( status_code=status_code, content={ "error": { "code": code, "message": message, "details": details, "request_id": request_id, }, }, headers={"X-Request-ID": request_id}, ) @app.middleware("http") async def request_id_middleware(request: Request, call_next): request.state.request_id = request.headers.get("X-Request-ID") or str(uuid4()) response = await call_next(request) response.headers["X-Request-ID"] = request.state.request_id return response @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse: return error_response( request=request, status_code=exc.status_code, code=f"HTTP_{exc.status_code}", message=str(exc.detail), ) @app.exception_handler(RequestValidationError) async def validation_exception_handler( request: Request, exc: RequestValidationError, ) -> JSONResponse: return error_response( request=request, status_code=422, code="VALIDATION_ERROR", message="One or more fields are invalid.", details=exc.errors(), ) @app.get("/health/live", tags=["Health"]) def live() -> dict[str, str]: return {"status": "ok", "service": "maskan-crm-api"} @app.get("/health/ready", tags=["Health"]) def ready() -> dict[str, str]: with SessionLocal() as db: db.execute(text("SELECT 1")) return {"status": "ready", "database": "connected"} @app.get("/api/v1/status", tags=["Health"]) def status() -> dict[str, str]: return { "product": "Maskan CRM", "mode": settings.mode, "environment": settings.environment, } app.include_router(api_router)