Source code for julee.api.app

"""
FastAPI application for julee CEAP workflow system.

This module provides the HTTP API layer for the Capture, Extract, Assemble,
Publish workflow system. It follows clean architecture principles with
proper dependency injection and error handling.

The API provides endpoints for:
- Knowledge service queries (CRUD operations)
- Assembly specifications (CRUD operations)
- Health checks and system status

All endpoints use domain models for responses and follow RESTful conventions
with proper HTTP status codes and error handling.
"""

import logging
from collections.abc import AsyncGenerator, Callable
from contextlib import asynccontextmanager
from typing import Any

import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi_pagination import add_pagination
from fastapi_pagination.utils import disable_installed_extensions_check

from julee.api.dependencies import (
    get_knowledge_service_config_repository,
    get_startup_dependencies,
)
from julee.api.routers import (
    assembly_specifications_router,
    documents_router,
    knowledge_service_configs_router,
    knowledge_service_queries_router,
    system_router,
    workflows_router,
)

# Disable pagination extensions check for cleaner startup
disable_installed_extensions_check()

[docs] logger = logging.getLogger(__name__)
[docs] def setup_logging() -> None: """Configure logging for the application.""" logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", handlers=[ logging.StreamHandler(), ], ) # Set specific log levels logging.getLogger("julee").setLevel(logging.DEBUG) logging.getLogger("fastapi").setLevel(logging.INFO) logging.getLogger("uvicorn").setLevel(logging.INFO)
# Setup logging setup_logging()
[docs] def resolve_dependency(app: FastAPI, dependency_func: Callable[[], Any]) -> Any: """Resolve a dependency, respecting test overrides.""" override = app.dependency_overrides.get(dependency_func) return override() if override else dependency_func()
@asynccontextmanager
[docs] async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: """Lifespan context manager for application startup and shutdown.""" # Startup logger.info("Starting application initialization") try: # Check if we're in test mode by looking for repository overrides if get_knowledge_service_config_repository in app.dependency_overrides: logger.info("Test mode detected, skipping system initialization") else: # Normal production initialization startup_deps = await resolve_dependency(app, get_startup_dependencies) service = await startup_deps.get_system_initialization_service() # Execute initialization results = await service.initialize() logger.info( "Application initialization completed successfully", extra={ "initialization_results": results, "tasks_completed": results.get("tasks_completed", []), }, ) except Exception as e: logger.error( "Application initialization failed", exc_info=True, extra={ "error_type": type(e).__name__, "error_message": str(e), }, ) # Re-raise to prevent application startup if critical init fails raise yield # Shutdown (if needed) logger.info("Application shutdown")
# Create FastAPI app
[docs] app = FastAPI( title="Julee Example CEAP API", description="API for the Capture, Extract, Assemble, Publish workflow", version="0.1.0", docs_url="/docs", redoc_url="/redoc", lifespan=lifespan, )
# Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], # Configure appropriately for production allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Add pagination support _ = add_pagination(app) # Include routers app.include_router(system_router, tags=["System"]) app.include_router( knowledge_service_queries_router, prefix="/knowledge_service_queries", tags=["Knowledge Service Queries"], ) app.include_router( knowledge_service_configs_router, prefix="/knowledge_service_configs", tags=["Knowledge Service Configs"], ) app.include_router( assembly_specifications_router, prefix="/assembly_specifications", tags=["Assembly Specifications"], ) app.include_router( documents_router, prefix="/documents", tags=["Documents"], ) app.include_router( workflows_router, prefix="/workflows", tags=["Workflows"], ) if __name__ == "__main__": uvicorn.run( "julee.api.app:app", host="0.0.0.0", port=8000, reload=True, log_level="info", )