from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from app.api.artifacts import router as artifacts_router from app.api.seed import router as seed_router from app.api.tags import router as tags_router from app.database import init_db from app.config import settings import logging import os from pathlib import Path # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) # Create FastAPI app app = FastAPI( title="Test Artifact Data Lake", description="API for storing and querying test artifacts including CSV, JSON, binary files, and packet captures", version="1.0.0", docs_url="/docs", redoc_url="/redoc" ) # Configure CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routers app.include_router(artifacts_router) app.include_router(seed_router) app.include_router(tags_router) # Static files configuration - will be set up after routes static_dir = Path("/app/static") @app.on_event("startup") async def startup_event(): """Initialize database on startup""" logger.info("Initializing database...") init_db() logger.info(f"Deployment mode: {settings.deployment_mode}") logger.info(f"Using storage backend: {settings.storage_backend}") logger.info("Application started successfully") @app.get("/api") async def api_root(): """API root endpoint""" return { "message": "Test Artifact Data Lake API", "version": "1.0.0", "docs": "/docs", "deployment_mode": settings.deployment_mode, "storage_backend": settings.storage_backend } @app.get("/") async def serve_angular_app(): """Serve Angular app index.html""" static_dir = Path("/app/static") if static_dir.exists(): return FileResponse(static_dir / "index.html") else: # Fallback if static files not found return { "message": "Test Artifact Data Lake API", "version": "1.0.0", "docs": "/docs", "deployment_mode": settings.deployment_mode, "storage_backend": settings.storage_backend } @app.get("/health") async def health_check(): """Health check endpoint""" return {"status": "healthy"} # Catch-all route for Angular client-side routing # This must be last to not interfere with API routes @app.get("/{full_path:path}") async def catch_all(full_path: str): """Serve Angular app for all non-API routes (SPA routing)""" if static_dir.exists(): # Check if the requested path is a file in the static directory file_path = static_dir / full_path if file_path.is_file() and file_path.exists(): # Determine media type based on file extension media_type = None if file_path.suffix == ".js": media_type = "application/javascript" elif file_path.suffix == ".css": media_type = "text/css" elif file_path.suffix in [".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico"]: media_type = f"image/{file_path.suffix[1:]}" return FileResponse(file_path, media_type=media_type) # Otherwise, serve index.html for client-side routing index_path = static_dir / "index.html" if index_path.exists(): return FileResponse(index_path, media_type="text/html") return {"error": "Static files not found"} if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host=settings.api_host, port=settings.api_port, reload=True )