Spaces:
No application file
No application file
| """ | |
| Docker & Kubernetes Document Generation API β REST API Service | |
| Generate PDFs, contracts, reports, and forms from templates with dynamic Docker & Kubernetes data. Embed document generation in any app. | |
| Features: | |
| """ | |
| import os | |
| from contextlib import asynccontextmanager | |
| from typing import Optional, List | |
| from datetime import datetime, timezone | |
| from fastapi import FastAPI, Depends, HTTPException, Request, status | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import JSONResponse | |
| from slowapi import Limiter | |
| from slowapi.util import get_remote_address | |
| from slowapi.errors import RateLimitExceeded | |
| from dotenv import load_dotenv | |
| from models import ItemCreate, ItemUpdate, ItemResponse, HealthResponse | |
| from auth import get_current_user, create_access_token, verify_password | |
| load_dotenv() | |
| limiter = Limiter(key_func=get_remote_address) | |
| _db: dict = {} # In-memory store β swap for real DB in production | |
| async def lifespan(app: FastAPI): | |
| print(f"{app.title} starting up...") | |
| yield | |
| print(f"{app.title} shutting down...") | |
| app = FastAPI( | |
| title="Docker & Kubernetes Document Generation API", | |
| description="Generate PDFs, contracts, reports, and forms from templates with dynamic Docker & Kubernetes data. Embed document generation in any app.", | |
| version="1.0.0", | |
| lifespan=lifespan, | |
| docs_url="/docs", | |
| redoc_url="/redoc", | |
| openapi_url="/openapi.json", | |
| ) | |
| app.state.limiter = limiter | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=os.getenv("ALLOWED_ORIGINS", "*").split(","), | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| async def rate_limit_handler(request: Request, exc: RateLimitExceeded): | |
| return JSONResponse( | |
| status_code=status.HTTP_429_TOO_MANY_REQUESTS, | |
| content={"error": "Rate limit exceeded", "detail": str(exc)}, | |
| ) | |
| async def global_exception_handler(request: Request, exc: Exception): | |
| return JSONResponse( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| content={"error": "Internal server error", "detail": str(exc)}, | |
| ) | |
| # ββ Health ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def health(): | |
| return { | |
| "status": "healthy", | |
| "service": "Docker & Kubernetes Document Generation API", | |
| "version": "1.0.0", | |
| "timestamp": datetime.now(timezone.utc).isoformat(), | |
| "items_count": len(_db), | |
| } | |
| # ββ Auth ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def login(request: Request, username: str, password: str): | |
| if not verify_password(username, password): | |
| raise HTTPException(status_code=401, detail="Invalid credentials") | |
| token = create_access_token({"sub": username}) | |
| return {"access_token": token, "token_type": "bearer"} | |
| # ββ CRUD ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def list_items( | |
| request: Request, | |
| skip: int = 0, | |
| limit: int = 50, | |
| search: Optional[str] = None, | |
| current_user: str = Depends(get_current_user), | |
| ): | |
| items = list(_db.values()) | |
| if search: | |
| items = [i for i in items if search.lower() in i.get("name", "").lower()] | |
| return items[skip : skip + limit] | |
| async def create_item( | |
| request: Request, | |
| item: ItemCreate, | |
| current_user: str = Depends(get_current_user), | |
| ): | |
| item_id = f"item_{len(_db) + 1:06d}" | |
| record = { | |
| "id": item_id, | |
| **item.model_dump(), | |
| "created_by": current_user, | |
| "created_at": datetime.now(timezone.utc).isoformat(), | |
| "updated_at": datetime.now(timezone.utc).isoformat(), | |
| } | |
| _db[item_id] = record | |
| return record | |
| async def get_item( | |
| request: Request, | |
| item_id: str, | |
| current_user: str = Depends(get_current_user), | |
| ): | |
| if item_id not in _db: | |
| raise HTTPException(status_code=404, detail=f"Item {item_id} not found") | |
| return _db[item_id] | |
| async def update_item( | |
| request: Request, | |
| item_id: str, | |
| item: ItemUpdate, | |
| current_user: str = Depends(get_current_user), | |
| ): | |
| if item_id not in _db: | |
| raise HTTPException(status_code=404, detail=f"Item {item_id} not found") | |
| record = _db[item_id] | |
| updates = item.model_dump(exclude_unset=True) | |
| record.update({**updates, "updated_at": datetime.now(timezone.utc).isoformat()}) | |
| _db[item_id] = record | |
| return record | |
| async def delete_item( | |
| request: Request, | |
| item_id: str, | |
| current_user: str = Depends(get_current_user), | |
| ): | |
| if item_id not in _db: | |
| raise HTTPException(status_code=404, detail=f"Item {item_id} not found") | |
| del _db[item_id] | |
| # ββ Stats βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def stats(request: Request, current_user: str = Depends(get_current_user)): | |
| return { | |
| "total_items": len(_db), | |
| "service": "Docker & Kubernetes Document Generation API", | |
| "niche": "docker_kubernetes", | |
| } | |