Files
mockupAWS/src/api/deps.py
Luca Sacchi Ricciardi b18728f0f9 feat(api): implement complete API layer with services and endpoints
Complete API implementation (BE-006 to BE-010):

BE-006: API Dependencies & Configuration
- Add core/config.py with Settings and environment variables
- Add core/exceptions.py with AppException hierarchy
- Add api/deps.py with get_db() and get_running_scenario() dependencies
- Add pydantic-settings dependency

BE-007: Services Layer
- Add services/pii_detector.py: PIIDetector with email/SSN/credit card patterns
- Add services/cost_calculator.py: AWS cost calculation (SQS, Lambda, Bedrock)
- Add services/ingest_service.py: Log processing with hash, PII detection, metrics

BE-008: Scenarios API Endpoints
- POST /api/v1/scenarios - Create scenario
- GET /api/v1/scenarios - List with filters and pagination
- GET /api/v1/scenarios/{id} - Get single scenario
- PUT /api/v1/scenarios/{id} - Update scenario
- DELETE /api/v1/scenarios/{id} - Delete scenario
- POST /api/v1/scenarios/{id}/start - Start (draft->running)
- POST /api/v1/scenarios/{id}/stop - Stop (running->completed)
- POST /api/v1/scenarios/{id}/archive - Archive (completed->archived)

BE-009: Ingest API
- POST /ingest with X-Scenario-ID header validation
- Depends on get_running_scenario() for status check
- Returns LogResponse with processed metrics
- POST /flush for backward compatibility

BE-010: Metrics API
- GET /api/v1/scenarios/{id}/metrics - Full metrics endpoint
- Aggregates data from scenario_logs
- Calculates costs using CostCalculator
- Returns cost breakdown (SQS/Lambda/Bedrock)
- Returns timeseries data grouped by hour

Refactored main.py:
- Simplified to use api_router
- Added exception handlers
- Added health check endpoint

All endpoints tested and working.

Tasks: BE-006, BE-007, BE-008, BE-009, BE-010 complete
2026-04-07 14:35:50 +02:00

40 lines
1.2 KiB
Python

"""API dependencies."""
from typing import AsyncGenerator
from uuid import UUID
from fastapi import Depends, Header
from sqlalchemy.ext.asyncio import AsyncSession
from src.core.database import AsyncSessionLocal
from src.repositories.scenario import scenario_repository, ScenarioStatus
from src.core.exceptions import NotFoundException, ScenarioNotRunningException
async def get_db() -> AsyncGenerator[AsyncSession, None]:
"""Dependency that provides a database session."""
async with AsyncSessionLocal() as session:
try:
yield session
finally:
await session.close()
async def get_running_scenario(
scenario_id: str = Header(..., alias="X-Scenario-ID"),
db: AsyncSession = Depends(get_db),
):
"""Dependency that validates scenario exists and is running."""
try:
scenario_uuid = UUID(scenario_id)
except ValueError:
raise NotFoundException("Scenario")
scenario = await scenario_repository.get(db, scenario_uuid)
if not scenario:
raise NotFoundException("Scenario")
if scenario.status != ScenarioStatus.RUNNING.value:
raise ScenarioNotRunningException()
return scenario