
* Created FastAPI application structure * Added database models for assets, exchanges, markets, and rates * Integrated with CoinCap API * Implemented REST API endpoints * Setup SQLite persistence with Alembic migrations * Added comprehensive documentation Generated with BackendIM... (backend.im)
117 lines
3.9 KiB
Python
117 lines
3.9 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, Query, Path, status
|
|
from sqlalchemy.orm import Session
|
|
from typing import Optional, List
|
|
import time
|
|
|
|
from app.services.coincap_api import coincap_api
|
|
from app.core.database import get_db
|
|
from app.api.schemas.asset import (
|
|
Asset, AssetCreate,
|
|
AssetResponse, AssetsResponse,
|
|
AssetHistoryResponse
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("", response_model=AssetsResponse)
|
|
async def get_assets(
|
|
search: Optional[str] = None,
|
|
ids: Optional[str] = None,
|
|
limit: Optional[int] = Query(100, le=2000),
|
|
offset: Optional[int] = Query(0, ge=0),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Get a list of assets with optional filters
|
|
"""
|
|
try:
|
|
response = await coincap_api.get_assets(search, ids, limit, offset)
|
|
return response
|
|
except HTTPException as e:
|
|
raise e
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Failed to fetch assets: {str(e)}"
|
|
)
|
|
|
|
|
|
@router.get("/{asset_id}", response_model=AssetResponse)
|
|
async def get_asset(
|
|
asset_id: str = Path(..., description="The asset ID (slug) to retrieve"),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Get details for a specific asset by ID
|
|
"""
|
|
try:
|
|
response = await coincap_api.get_asset(asset_id)
|
|
return response
|
|
except HTTPException as e:
|
|
raise e
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Failed to fetch asset {asset_id}: {str(e)}"
|
|
)
|
|
|
|
|
|
@router.get("/{asset_id}/markets", response_model=dict)
|
|
async def get_asset_markets(
|
|
asset_id: str = Path(..., description="The asset ID (slug) to retrieve markets for"),
|
|
limit: Optional[int] = Query(100, le=2000),
|
|
offset: Optional[int] = Query(0, ge=0),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Get markets for a specific asset
|
|
"""
|
|
try:
|
|
response = await coincap_api.get_asset_markets(asset_id, limit, offset)
|
|
return response
|
|
except HTTPException as e:
|
|
raise e
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Failed to fetch markets for asset {asset_id}: {str(e)}"
|
|
)
|
|
|
|
|
|
@router.get("/{asset_id}/history", response_model=AssetHistoryResponse)
|
|
async def get_asset_history(
|
|
asset_id: str = Path(..., description="The asset ID (slug) to retrieve history for"),
|
|
interval: str = Query(..., description="Interval choices: m1, m5, m15, m30, h1, h2, h6, h12, d1"),
|
|
start: Optional[int] = Query(None, description="UNIX time in milliseconds"),
|
|
end: Optional[int] = Query(None, description="UNIX time in milliseconds"),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Get historical data for a specific asset
|
|
"""
|
|
# Validate interval choices
|
|
valid_intervals = ["m1", "m5", "m15", "m30", "h1", "h2", "h6", "h12", "d1"]
|
|
if interval not in valid_intervals:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=f"Invalid interval. Choose from: {', '.join(valid_intervals)}"
|
|
)
|
|
|
|
# Both start and end must be provided if one is provided
|
|
if (start is None and end is not None) or (start is not None and end is None):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Both 'start' and 'end' parameters must be provided together"
|
|
)
|
|
|
|
try:
|
|
response = await coincap_api.get_asset_history(asset_id, interval, start, end)
|
|
return response
|
|
except HTTPException as e:
|
|
raise e
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Failed to fetch history for asset {asset_id}: {str(e)}"
|
|
) |