Add API endpoints for health checks, process control, recipe management, system management, and user management

- Implement health check endpoints for system monitoring including basic, detailed, readiness, liveness, and metrics.
- Create process control endpoints to start, stop, pause, resume, and manage processes.
- Add recipe management endpoints for listing, creating, retrieving, updating, deleting, duplicating, and validating recipes.
- Introduce system management endpoints for retrieving system information, active alarms, and configuration.
- Establish user management endpoints for listing and creating users with placeholder implementations.
- Define Pydantic schemas for API request/response validation related to recipes, processes, and users.
This commit is contained in:
2025-08-06 22:15:54 +02:00
parent 9cdd074a39
commit c3bc2e453b
19 changed files with 4949 additions and 0 deletions

View File

@@ -0,0 +1,256 @@
"""
FastAPI main application for chocolate tempering machine control system.
Provides REST API endpoints for system control and monitoring.
"""
import logging
from contextlib import asynccontextmanager
from typing import Dict, Any
from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.responses import JSONResponse
import uvicorn
from ...shared.config import settings
from ...shared.database import init_database, create_tables, close_database
from ..hardware.hardware_manager import hardware_manager
from ..recipe.recipe_controller import recipe_controller
from ..safety.safety_monitor import safety_monitor
from ..safety.error_handler import error_handler
from .routers import recipes, process, hardware, users, system, health
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan manager for startup and shutdown tasks."""
# Startup
logger.info("Starting chocolate tempering machine control system")
try:
# Initialize database
init_database()
await create_tables()
logger.info("Database initialized")
# Initialize hardware manager
if await hardware_manager.initialize():
logger.info("Hardware manager initialized")
else:
logger.error("Hardware manager initialization failed")
# Initialize safety monitor
if await safety_monitor.initialize():
logger.info("Safety monitor initialized")
else:
logger.error("Safety monitor initialization failed")
logger.info("System startup completed successfully")
except Exception as e:
logger.critical(f"System startup failed: {e}")
raise
yield
# Shutdown
logger.info("Shutting down chocolate tempering machine control system")
try:
# Stop any running recipes
await recipe_controller.emergency_stop(reason="System shutdown")
# Shutdown safety monitor
await safety_monitor.shutdown()
# Shutdown hardware manager
await hardware_manager.shutdown()
# Close database connections
await close_database()
logger.info("System shutdown completed")
except Exception as e:
logger.error(f"Error during shutdown: {e}")
# Create FastAPI application
app = FastAPI(
title=settings.web.api_title,
version=settings.web.api_version,
description="Industrial chocolate tempering machine control system API",
docs_url="/docs",
redoc_url="/redoc",
openapi_url="/openapi.json",
lifespan=lifespan,
)
# Add middleware
app.add_middleware(
CORSMiddleware,
allow_origins=settings.web.cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.add_middleware(
TrustedHostMiddleware,
allowed_hosts=["*"] # Configure appropriately for production
)
# Global exception handler
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
"""Global exception handler for unhandled errors."""
logger.error(f"Unhandled exception in {request.url}: {exc}")
# Handle error through error handling system
await error_handler.handle_error(exc, "web_api", {
"url": str(request.url),
"method": request.method,
"client": request.client.host if request.client else "unknown"
})
return JSONResponse(
status_code=500,
content={
"error": "Internal server error",
"message": "An unexpected error occurred",
"request_id": getattr(request.state, "request_id", "unknown")
}
)
# HTTP exception handler
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
"""Handler for HTTP exceptions."""
return JSONResponse(
status_code=exc.status_code,
content={
"error": exc.detail,
"status_code": exc.status_code
}
)
# Request ID middleware
@app.middleware("http")
async def add_request_id(request: Request, call_next):
"""Add request ID for tracing."""
import uuid
request_id = str(uuid.uuid4())
request.state.request_id = request_id
response = await call_next(request)
response.headers["X-Request-ID"] = request_id
return response
# Include routers
app.include_router(
health.router,
prefix="/health",
tags=["health"]
)
app.include_router(
recipes.router,
prefix="/api/v1/recipes",
tags=["recipes"]
)
app.include_router(
process.router,
prefix="/api/v1/process",
tags=["process"]
)
app.include_router(
hardware.router,
prefix="/api/v1/hardware",
tags=["hardware"]
)
app.include_router(
users.router,
prefix="/api/v1/users",
tags=["users"]
)
app.include_router(
system.router,
prefix="/api/v1/system",
tags=["system"]
)
# Root endpoint
@app.get("/", response_model=Dict[str, Any])
async def root():
"""Root endpoint with system information."""
return {
"name": settings.app_name,
"version": settings.app_version,
"environment": settings.environment,
"api_version": "v1",
"docs_url": "/docs",
"health_url": "/health"
}
# API info endpoint
@app.get("/api/v1/info", response_model=Dict[str, Any])
async def api_info():
"""API information endpoint."""
return {
"api_title": settings.web.api_title,
"api_version": settings.web.api_version,
"environment": settings.environment,
"features": {
"recipe_management": True,
"process_control": True,
"hardware_monitoring": True,
"safety_monitoring": True,
"user_management": True,
"real_time_monitoring": True,
},
"endpoints": {
"recipes": "/api/v1/recipes",
"process": "/api/v1/process",
"hardware": "/api/v1/hardware",
"users": "/api/v1/users",
"system": "/api/v1/system",
"health": "/health",
}
}
def create_app() -> FastAPI:
"""Factory function to create FastAPI app."""
return app
def run_server():
"""Run the development server."""
uvicorn.run(
"tempering_machine.services.web.main:app",
host=settings.web.host,
port=settings.web.port,
reload=settings.web.reload,
workers=settings.web.workers if not settings.web.reload else 1,
access_log=settings.web.access_log,
log_level=settings.log_level.lower(),
)
if __name__ == "__main__":
run_server()