import logging from contextlib import asynccontextmanager from fastapi import FastAPI, Request, Response from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.base import BaseHTTPMiddleware from app.db.session import engine from app.db.base import Base from app.routers import monitors, checks, scheduler from app.services.scheduler import uptime_scheduler # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Create database tables Base.metadata.create_all(bind=engine) class CORSMiddleware2(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): # Handle preflight requests if request.method == "OPTIONS": response = Response() response.headers["Access-Control-Allow-Origin"] = "*" response.headers["Access-Control-Allow-Methods"] = ( "GET, POST, PUT, DELETE, OPTIONS" ) response.headers["Access-Control-Allow-Headers"] = "*" response.headers["Access-Control-Max-Age"] = "3600" return response # Process the request response = await call_next(request) # Add CORS headers to the response response.headers["Access-Control-Allow-Origin"] = "*" response.headers["Access-Control-Allow-Methods"] = ( "GET, POST, PUT, DELETE, OPTIONS" ) response.headers["Access-Control-Allow-Headers"] = "*" response.headers["Access-Control-Expose-Headers"] = "*" return response @asynccontextmanager async def lifespan(app: FastAPI): # Startup logger.info("Starting Uptime Monitoring API...") uptime_scheduler.start() yield # Shutdown logger.info("Shutting down Uptime Monitoring API...") uptime_scheduler.stop() app = FastAPI( title="Uptime Monitoring API", description="API for monitoring website/endpoint uptime and performance", version="1.0.0", openapi_url="/openapi.json", lifespan=lifespan, ) # Add custom CORS middleware app.add_middleware(CORSMiddleware2) # Also add the standard CORS middleware as backup app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=False, # Must be False when using wildcard origins allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], allow_headers=["*"], expose_headers=["*"], ) # Include routers app.include_router(monitors.router, prefix="/api/v1") app.include_router(checks.router, prefix="/api/v1") app.include_router(scheduler.router, prefix="/api/v1") @app.get("/") async def root(): return { "title": "Uptime Monitoring API", "documentation": "/docs", "health_check": "/health", } @app.get("/health") async def health_check(): return {"status": "healthy", "service": "uptime-monitoring-api"} @app.options("/{full_path:path}") async def options_handler(full_path: str): """Handle preflight OPTIONS requests""" from fastapi import Response response = Response() response.headers["Access-Control-Allow-Origin"] = "*" response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS" response.headers["Access-Control-Allow-Headers"] = "*" response.headers["Access-Control-Max-Age"] = "3600" return response if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)