Spaces:
Sleeping
Sleeping
File size: 4,681 Bytes
b84ea83 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | """
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(),
)
|