azzaraqi
Deploy FastAPI backend with Supabase pooler support
b84ea83
Raw
History Blame Contribute Delete
4.68 kB
"""
Apl_GS API β€” FastAPI Application Entry Point
Run:
python app.py
Or directly with uvicorn:
uvicorn app:app --host 0.0.0.0 --port 5000 --reload
API Docs:
http://localhost:5000/docs (Swagger UI)
http://localhost:5000/redoc (ReDoc)
Architecture Reference:
insights/architecture_rule.md
"""
import os
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from dotenv import load_dotenv
# Load environment variables FIRST (before any config imports)
load_dotenv()
from web.route import router
from config.rate_limiter import rate_limit_middleware
from config.database_config import init_db, close_db
# ── Logging ──
logging.basicConfig(
level=os.getenv("LOG_LEVEL", "INFO"),
format="%(asctime)s β€” %(name)s β€” %(levelname)s β€” %(message)s",
)
logger = logging.getLogger(__name__)
# ── App Metadata ──
APP_NAME = os.getenv("APP_NAME", "Apl_GS API")
APP_VERSION = "1.0.0"
APP_ENV = os.getenv("APP_ENV", "development")
APP_DEBUG = os.getenv("APP_DEBUG", "False").lower() == "true"
# ── Lifespan (startup + shutdown) ──
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifecycle β€” runs on startup and shutdown."""
# ── STARTUP ──
logger.info(f"πŸš€ Starting {APP_NAME} v{APP_VERSION}")
logger.info(f"πŸ“ Environment: {APP_ENV}")
logger.info(f"πŸ”§ Debug mode: {APP_DEBUG}")
logger.info(f"🌐 Port: {os.getenv('PORT', '5000')}")
# Initialize database tables
try:
await init_db()
logger.info("βœ… Database initialized successfully")
except Exception as e:
logger.error(f"❌ Database initialization failed: {e}")
logger.warning("⚠️ API will start but database operations will fail")
logger.warning("⚠️ Make sure PostgreSQL 15+ is installed and running!")
yield # Application runs here
# ── SHUTDOWN ──
logger.info("πŸ›‘ Shutting down Apl_GS API")
await close_db()
# ── Create FastAPI Instance ──
app = FastAPI(
title=APP_NAME,
version=APP_VERSION,
description=(
"Apl_GS Backend API β€” Visit & Checklist Management System.\n\n"
"**No authentication required** β€” protected by rate limiter.\n\n"
"Built with FastAPI + PostgreSQL 15+.\n\n"
"πŸ“– Architecture Reference: `insights/architecture_rule.md`"
),
docs_url="/docs",
redoc_url="/redoc",
openapi_url="/openapi.json",
lifespan=lifespan,
)
# ── CORS Middleware ──
cors_origins = os.getenv(
"CORS_ORIGINS", "http://localhost"
).split(",")
app.add_middleware(
CORSMiddleware,
allow_origins=[origin.strip() for origin in cors_origins],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ── Rate Limiter Middleware ──
app.middleware("http")(rate_limit_middleware)
# ── Include API Routes ──
app.include_router(router)
# ── Root Endpoint ──
@app.get("/", tags=["Root"], summary="API root β€” basic info and links")
async def root():
"""
Root endpoint β€” returns API info, version, and documentation links.
"""
return {
"status": "success",
"data": {
"name": APP_NAME,
"version": APP_VERSION,
"environment": APP_ENV,
"docs": "/docs",
"redoc": "/redoc",
"health": "/api/v1/health",
},
"message": "Apl_GS API is running",
}
# ── Global Exception Handler ──
@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
"""Handle unexpected exceptions gracefully."""
logger.error(f"Unhandled exception: {exc}", exc_info=True)
return JSONResponse(
status_code=500,
content={
"status": "error",
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred",
"details": str(exc) if APP_DEBUG else None,
},
},
)
# ── Run with Uvicorn ──
if __name__ == "__main__":
import uvicorn
host = os.getenv("HOST", "0.0.0.0")
port = int(os.getenv("PORT", "5000"))
logger.info(f"🌟 Running on http://{host}:{port}")
logger.info(f"πŸ“š Swagger UI: http://{host}:{port}/docs")
logger.info(f"πŸ“š ReDoc: http://{host}:{port}/redoc")
uvicorn.run(
"app:app",
host=host,
port=port,
reload=(APP_ENV == "development"),
log_level=os.getenv("LOG_LEVEL", "info").lower(),
)