from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from typing import List, Optional import logging from app.database import get_db from app.schemas.assets import ( AssetResponse, SingleAssetResponse, AssetHistoryResponse, AssetMarketsResponse, ErrorResponse ) from app.services.coincap_client import CoinCapClient router = APIRouter(prefix="/assets", tags=["Assets"]) logger = logging.getLogger(__name__) # Initialize client client = CoinCapClient() @router.get( "", response_model=AssetResponse, summary="Get list of assets", description="Retrieve a list of assets with optional filters" ) async def get_assets( search: Optional[str] = None, ids: Optional[str] = None, limit: Optional[int] = Query(100, ge=1, le=2000), offset: Optional[int] = Query(0, ge=0), db: Session = Depends(get_db) ): try: response = await client.get_assets(search=search, ids=ids, limit=limit, offset=offset) return response except Exception as e: logger.error(f"Error fetching assets: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.get( "/{slug}", response_model=SingleAssetResponse, responses={404: {"model": ErrorResponse}}, summary="Get a specific asset", description="Retrieve details for a specific asset by its slug" ) async def get_asset(slug: str, db: Session = Depends(get_db)): try: response = await client.get_asset(slug) if not response.get("data"): raise HTTPException(status_code=404, detail=f"{slug} not found") return response except HTTPException: raise except Exception as e: logger.error(f"Error fetching asset {slug}: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.get( "/{slug}/markets", response_model=AssetMarketsResponse, responses={404: {"model": ErrorResponse}}, summary="Get markets for an asset", description="Retrieve markets for a specific asset" ) async def get_asset_markets( slug: str, limit: Optional[int] = Query(100, ge=1, le=2000), offset: Optional[int] = Query(0, ge=0), db: Session = Depends(get_db) ): try: response = await client.get_asset_markets(slug, limit=limit, offset=offset) if not response.get("data") and isinstance(response.get("data"), list): raise HTTPException(status_code=404, detail=f"{slug} not found") return response except HTTPException: raise except Exception as e: logger.error(f"Error fetching markets for asset {slug}: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.get( "/{slug}/history", response_model=AssetHistoryResponse, responses={404: {"model": ErrorResponse}}, summary="Get historical data for an asset", description="Retrieve historical price data for a specific asset" ) async def get_asset_history( slug: str, interval: str = Query(..., description="Time interval (m1, m5, m15, m30, h1, h2, h6, h12, d1)"), start: Optional[int] = None, end: Optional[int] = None, db: Session = Depends(get_db) ): # Validate interval valid_intervals = ["m1", "m5", "m15", "m30", "h1", "h2", "h6", "h12", "d1"] if interval not in valid_intervals: raise HTTPException( status_code=400, detail=f"Invalid interval. Must be one of: {', '.join(valid_intervals)}" ) # Validate start and end if (start is None and end is not None) or (start is not None and end is None): raise HTTPException( status_code=400, detail="Both start and end must be provided together or neither should be provided" ) try: response = await client.get_asset_history( slug, interval=interval, start=start, end=end ) if not response.get("data") and isinstance(response.get("data"), list): raise HTTPException(status_code=404, detail=f"{slug} not found") return response except HTTPException: raise except Exception as e: logger.error(f"Error fetching history for asset {slug}: {e}") raise HTTPException(status_code=500, detail=str(e))