deploymate / app /main.py
shakauthossain's picture
V2.0.0
2df0cf9 verified
"""
Main FastAPI application for DeployMate.
"""
from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI, HTTPException, Request
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, JSONResponse
from slowapi import _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded
from app.api.deps import get_logger, get_settings
from app.api.routes.nginx import router as nginx_router
from app.api.routes.scripts import router as scripts_router
from app.api.routes.docker import router as docker_router
from app.core.config import settings
from app.core.logging import logger
from app.core.security import limiter, rate_limit_middleware
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan context manager."""
logger.info("Starting DeployMate API")
yield
logger.info("Shutting down DeployMate API")
# Create FastAPI application
app = FastAPI(
title="DeployMate API",
version="1.0.0",
description="API for generating VPS setup scripts and nginx configurations",
lifespan=lifespan,
)
# Rate limiting
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
app.add_middleware(rate_limit_middleware)
# CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=settings.allowed_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Exception handlers
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
"""Handle Pydantic validation errors."""
client_ip = request.client.host if request.client else "unknown"
errors = []
for error in exc.errors():
errors.append(
{
"type": error.get("type"),
"loc": error.get("loc"),
"msg": error.get("msg"),
"input": error.get("input"),
}
)
logger.error(f"Validation error from {client_ip}: {errors}")
return JSONResponse(
status_code=422,
content={"detail": errors},
)
# Root endpoint
@app.get("/")
async def root():
"""Root endpoint returning API information."""
return {
"message": "DeployMate API",
"version": "1.0.0",
"docs": "/docs",
"redoc": "/redoc",
}
# File download endpoint
@app.get("/download/{filename}")
async def download_file(
filename: str,
request: Request,
settings=Depends(get_settings),
logger=Depends(get_logger)
):
"""Download a generated file."""
client_ip = request.client.host if request.client else "unknown"
logger.info(f"File download request from {client_ip}: {filename}")
file_path = settings.generated_dir / filename
if not file_path.exists():
logger.warning(f"File not found: {filename}")
raise HTTPException(status_code=404, detail="File not found")
logger.info(f"Serving file: {filename}")
return FileResponse(
path=file_path, filename=filename, media_type="application/octet-stream"
)
# Include API routers
app.include_router(scripts_router, prefix="/api/v1", tags=["scripts"])
app.include_router(nginx_router, prefix="/api/v1", tags=["nginx"])
app.include_router(docker_router, prefix="/api/v1", tags=["docker"])