from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.exceptions import HTTPException from fastapi.responses import JSONResponse from app.config import get_settings from app.database import Base, get_engine @asynccontextmanager async def lifespan(application: FastAPI): get_settings() # Verify DB connection and run migrations on startup engine = get_engine() async with engine.begin() as conn: # In production, Alembic handles migrations; this is a dev convenience await conn.run_sync(Base.metadata.create_all) yield await engine.dispose() app = FastAPI(title="Reactbin API", version="1.0.0", lifespan=lifespan) @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException): if isinstance(exc.detail, dict): return JSONResponse(status_code=exc.status_code, content=exc.detail) return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail}) @app.get("/api/v1/health") async def health(): return {"status": "ok"} # Routers registered after all modules are defined to avoid circular imports from app.routers import auth, images, tags # noqa: E402 app.include_router(auth.router, prefix="/api/v1") app.include_router(images.router, prefix="/api/v1") app.include_router(tags.router, prefix="/api/v1")