Files
bakery-ia/services/data/app/api/traffic.py
2025-07-26 18:46:52 +02:00

160 lines
6.3 KiB
Python

# ================================================================
# services/data/app/api/traffic.py - FIXED VERSION
# ================================================================
"""Traffic data API endpoints with improved error handling"""
from fastapi import APIRouter, Depends, HTTPException, Query, Path
from typing import List, Dict, Any
from datetime import datetime, timedelta
import structlog
from uuid import UUID
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db
from app.services.traffic_service import TrafficService
from app.services.messaging import data_publisher
from app.schemas.external import (
TrafficDataResponse,
LocationRequest,
DateRangeRequest
)
from shared.auth.decorators import (
get_current_user_dep,
get_current_tenant_id_dep
)
router = APIRouter(tags=["traffic"])
traffic_service = TrafficService()
logger = structlog.get_logger()
@router.get("/tenants/{tenant_id}/current", response_model=TrafficDataResponse)
async def get_current_traffic(
latitude: float = Query(..., description="Latitude"),
longitude: float = Query(..., description="Longitude"),
tenant_id: UUID = Path(..., description="Tenant ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
):
"""Get current traffic data for location"""
try:
logger.debug("API: Getting current traffic", lat=latitude, lon=longitude)
traffic = await traffic_service.get_current_traffic(latitude, longitude)
if not traffic:
logger.warning("No traffic data available", lat=latitude, lon=longitude)
raise HTTPException(status_code=404, detail="Traffic data not available")
# Publish event (with error handling)
try:
await data_publisher.publish_traffic_updated({
"type": "current_requested",
"latitude": latitude,
"longitude": longitude,
"timestamp": datetime.utcnow().isoformat()
})
except Exception as pub_error:
logger.warning("Failed to publish traffic event", error=str(pub_error))
# Continue processing - event publishing failure shouldn't break the API
logger.debug("Successfully returning traffic data",
volume=traffic.traffic_volume,
congestion=traffic.congestion_level)
return traffic
except HTTPException:
# Re-raise HTTP exceptions
raise
except Exception as e:
logger.error("Unexpected error in traffic API", error=str(e))
import traceback
logger.error("Traffic API traceback", traceback=traceback.format_exc())
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
@router.get("/tenants/{tenant_id}/historical", response_model=List[TrafficDataResponse])
async def get_historical_traffic(
latitude: float = Query(..., description="Latitude"),
longitude: float = Query(..., description="Longitude"),
start_date: datetime = Query(..., description="Start date"),
end_date: datetime = Query(..., description="End date"),
db: AsyncSession = Depends(get_db),
tenant_id: UUID = Path(..., description="Tenant ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
):
"""Get historical traffic data"""
try:
# Validate date range
if end_date <= start_date:
raise HTTPException(status_code=400, detail="End date must be after start date")
if (end_date - start_date).days > 90:
raise HTTPException(status_code=400, detail="Date range cannot exceed 90 days")
historical_data = await traffic_service.get_historical_traffic(
latitude, longitude, start_date, end_date, db
)
# Publish event (with error handling)
try:
await data_publisher.publish_traffic_updated({
"type": "historical_requested",
"latitude": latitude,
"longitude": longitude,
"start_date": start_date.isoformat(),
"end_date": end_date.isoformat(),
"records_count": len(historical_data),
"timestamp": datetime.utcnow().isoformat()
})
except Exception as pub_error:
logger.warning("Failed to publish historical traffic event", error=str(pub_error))
# Continue processing
return historical_data
except HTTPException:
# Re-raise HTTP exceptions
raise
except Exception as e:
logger.error("Unexpected error in historical traffic API", error=str(e))
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
@router.post("/tenants/{tenant_id}/store")
async def store_traffic_data(
latitude: float = Query(..., description="Latitude"),
longitude: float = Query(..., description="Longitude"),
db: AsyncSession = Depends(get_db),
tenant_id: UUID = Path(..., description="Tenant ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep)
):
"""Store current traffic data to database"""
try:
# Get current traffic data
traffic = await traffic_service.get_current_traffic(latitude, longitude)
if not traffic:
raise HTTPException(status_code=404, detail="No traffic data to store")
# Convert to dict for storage
traffic_dict = {
"date": traffic.date,
"traffic_volume": traffic.traffic_volume,
"pedestrian_count": traffic.pedestrian_count,
"congestion_level": traffic.congestion_level,
"average_speed": traffic.average_speed,
"source": traffic.source
}
success = await traffic_service.store_traffic_data(
latitude, longitude, traffic_dict, db
)
if success:
return {"status": "success", "message": "Traffic data stored successfully"}
else:
raise HTTPException(status_code=500, detail="Failed to store traffic data")
except HTTPException:
raise
except Exception as e:
logger.error("Error storing traffic data", error=str(e))
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")