# Standards API routes from fastapi import APIRouter, UploadFile, File, HTTPException, Query from typing import List, Optional from loguru import logger from app.core.models import Standard, StandardUploadResponse from app.services.standards import StandardsService # Create services standards_service = StandardsService() # Create router router = APIRouter(prefix="/standards", tags=["standards"]) @router.get("/", response_model=List[Standard]) async def get_all_standards(): """ Get all available compliance standards. Returns: List of all standards """ try: standards = await standards_service.get_all_standards() return standards except Exception as e: logger.error(f"Error retrieving standards: {str(e)}") raise HTTPException(status_code=500, detail=f"Error retrieving standards: {str(e)}") @router.get("/{standard_id}", response_model=Standard) async def get_standard(standard_id: str): """ Get a specific standard by ID. Args: standard_id: The standard ID Returns: Standard details """ try: standard = await standards_service.get_standard(standard_id) if not standard: raise HTTPException(status_code=404, detail=f"Standard with ID {standard_id} not found") return standard except HTTPException: raise except Exception as e: logger.error(f"Error retrieving standard: {str(e)}") raise HTTPException(status_code=500, detail=f"Error retrieving standard: {str(e)}") @router.post("/upload", response_model=StandardUploadResponse) async def upload_standard(file: UploadFile = File(...)): """ Upload a new compliance standard definition. Args: file: JSON file containing standard definition Returns: StandardUploadResponse with standard ID """ try: # Check file extension if not file.filename: raise HTTPException(status_code=400, detail="Filename is required") if not file.filename.lower().endswith('.json'): raise HTTPException(status_code=400, detail="Standard definition must be a JSON file") # Log the standards service instance ID to verify singleton pattern logger.info(f"Standards API - Using StandardsService instance: {id(standards_service)}") logger.info(f"Standards API - Standards count before upload: {len(standards_service.standards)}") # Process standard standard = await standards_service.upload_standard(file.file, file.filename) # Log the updated standards count logger.info(f"Standards API - Standards count after upload: {len(standards_service.standards)}") logger.info(f"Standards API - Uploaded standard: {standard.name} (ID: {standard.id})") return StandardUploadResponse( standard_id=standard.id, name=standard.name, requirement_count=len(standard.requirements), message="Standard uploaded successfully." ) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Error processing standard: {str(e)}") raise HTTPException(status_code=500, detail=f"Error processing standard: {str(e)}") @router.get("/search/", response_model=List[Standard]) async def search_standards(name: Optional[str] = Query(None, description="Standard name to search for")): """ Search for standards by name. Args: name: Standard name to search for (optional) Returns: List of matching standards """ try: if name: standard = await standards_service.get_standard_by_name(name) return [standard] if standard else [] else: return await standards_service.get_all_standards() except Exception as e: logger.error(f"Error searching standards: {str(e)}") raise HTTPException(status_code=500, detail=f"Error searching standards: {str(e)}")