Datasourceforcryptocurrency-2 / backend /routers /expanded_providers_api.py
Really-amin's picture
Upload 946 files
942e436 verified
#!/usr/bin/env python3
from fastapi import APIRouter, HTTPException, Query, Path, Body
from typing import Optional, Dict, Any, List
from datetime import datetime, timezone
import logging
from backend.services.expanded_providers import (
get_provider_manager,
initialize_providers,
fetch_market_data,
fetch_fear_greed,
fetch_news,
fetch_ohlcv,
get_all_provider_health,
ProviderCategory,
PROVIDER_REGISTRY
)
logger = logging.getLogger(__name__)
router = APIRouter(
prefix="/api/providers/expanded", # Changed to avoid duplicate with hf_providers_api
tags=["Expanded Providers"]
)
def create_response(data: Any, source: str, meta: Dict = None) -> Dict[str, Any]:
return {
"success": True,
"data": data,
"meta": {
"source": source,
"generated_at": datetime.now(timezone.utc).isoformat(),
**(meta or {})
}
}
@router.get("/initialize")
async def init_providers():
try:
result = initialize_providers()
return create_response(result, "expanded_providers")
except Exception as e:
logger.error(f"Failed to initialize providers: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/list")
async def list_providers(
category: Optional[str] = Query(None, description="Filter by category")
):
try:
manager = get_provider_manager()
manager.initialize()
providers = []
for pid, provider in manager.get_all_providers().items():
if category and provider.config.category.value != category:
continue
providers.append({
"id": pid,
"name": provider.config.name,
"category": provider.config.category.value,
"base_url": provider.config.base_url,
"free_tier": provider.config.free_tier,
"requires_auth": provider.config.requires_auth,
"rate_limit": provider.config.rate_limit_per_minute,
"priority": provider.config.priority
})
return create_response(
providers,
"expanded_providers",
{"total": len(providers)}
)
except Exception as e:
logger.error(f"Failed to list providers: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/categories")
async def list_categories():
try:
categories = [{"id": c.value, "name": c.name} for c in ProviderCategory]
return create_response(categories, "expanded_providers")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/health")
async def get_providers_health():
try:
health = get_all_provider_health()
online = sum(1 for h in health if h["status"] == "online")
offline = sum(1 for h in health if h["status"] == "error")
unknown = sum(1 for h in health if h["status"] == "unknown")
return create_response(
health,
"expanded_providers",
{
"total": len(health),
"online": online,
"offline": offline,
"unknown": unknown
}
)
except Exception as e:
logger.error(f"Failed to get provider health: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/health/{provider_id}")
async def get_provider_health(provider_id: str = Path(...)):
try:
manager = get_provider_manager()
provider = manager.get_provider(provider_id)
if not provider:
raise HTTPException(status_code=404, detail=f"Provider {provider_id} not found")
health = provider.get_health()
return create_response({
"id": provider_id,
"name": provider.config.name,
"status": health.status,
"latency_ms": health.latency_ms,
"last_check": health.last_check,
"error_message": health.error_message,
"success_rate": health.success_rate
}, provider.config.name)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/{provider_id}/fetch")
async def fetch_from_provider(
provider_id: str = Path(...),
endpoint: Optional[str] = Query(None),
symbol: Optional[str] = Query(None),
limit: Optional[int] = Query(100)
):
try:
manager = get_provider_manager()
provider = manager.get_provider(provider_id)
if not provider:
raise HTTPException(status_code=404, detail=f"Provider {provider_id} not found")
kwargs = {}
if endpoint:
kwargs["endpoint"] = endpoint
if symbol:
kwargs["symbol"] = symbol
kwargs["symbols"] = [symbol]
kwargs["limit"] = limit
result = await provider.fetch_data(**kwargs)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error", "Provider request failed"))
return create_response(
result.get("data"),
provider.config.name,
{"latency_ms": result.get("latency_ms")}
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to fetch from {provider_id}: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/market/prices")
async def get_market_prices(
symbols: str = Query("bitcoin,ethereum", description="Comma-separated coin IDs")
):
try:
symbol_list = [s.strip() for s in symbols.split(",")]
result = await fetch_market_data(symbol_list)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(
result.get("data"),
result.get("provider", "unknown"),
{"latency_ms": result.get("latency_ms")}
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/market/fear-greed")
async def get_fear_greed_index():
try:
result = await fetch_fear_greed()
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(
result.get("data"),
result.get("provider", "alternative_me")
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/news/latest")
async def get_latest_news():
try:
result = await fetch_news()
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(
result.get("data"),
result.get("provider", "cryptopanic")
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/market/ohlcv/{symbol}")
async def get_ohlcv_data(
symbol: str = Path(...),
interval: str = Query("1h", description="Candle interval")
):
try:
result = await fetch_ohlcv(symbol, interval)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(
result.get("data"),
result.get("provider", "unknown")
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/blockchain/{chain}/balance/{address}")
async def get_blockchain_balance(
chain: str = Path(..., description="blockchain: ethereum, bsc, tron"),
address: str = Path(...)
):
try:
manager = get_provider_manager()
provider_map = {
"ethereum": "etherscan_0",
"eth": "etherscan_0",
"bsc": "bscscan",
"binance": "bscscan",
"tron": "tronscan",
"trx": "tronscan"
}
provider_id = provider_map.get(chain.lower())
if not provider_id:
raise HTTPException(status_code=400, detail=f"Unsupported chain: {chain}")
provider = manager.get_provider(provider_id)
if not provider:
raise HTTPException(status_code=404, detail=f"Provider for {chain} not found")
if hasattr(provider, "get_balance"):
result = await provider.get_balance(address)
else:
result = await provider.fetch_data(address=address)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(
result.get("data"),
provider.config.name
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/blockchain/{chain}/gas")
async def get_gas_price(chain: str = Path(...)):
try:
manager = get_provider_manager()
if chain.lower() in ["ethereum", "eth"]:
provider = manager.get_provider("etherscan_0")
if provider and hasattr(provider, "get_gas_price"):
result = await provider.get_gas_price()
if result.get("success"):
return create_response(result.get("data"), provider.config.name)
raise HTTPException(status_code=400, detail=f"Gas price not available for {chain}")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/social/reddit/{subreddit}")
async def get_reddit_posts(
subreddit: str = Path(...),
sort: str = Query("hot", description="hot, new, top, rising"),
limit: int = Query(25, le=100)
):
try:
manager = get_provider_manager()
provider = manager.get_provider("reddit")
if not provider:
raise HTTPException(status_code=404, detail="Reddit provider not available")
result = await provider.get_subreddit_posts(subreddit, sort, limit)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "reddit")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/defi/protocols")
async def get_defi_protocols():
try:
manager = get_provider_manager()
provider = manager.get_provider("defillama")
if not provider:
raise HTTPException(status_code=404, detail="DefiLlama provider not available")
result = await provider.get_protocols()
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "defillama")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/defi/tvl")
async def get_total_tvl():
try:
manager = get_provider_manager()
provider = manager.get_provider("defillama")
if not provider:
raise HTTPException(status_code=404, detail="DefiLlama provider not available")
result = await provider.get_tvl_history()
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "defillama")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/dex/pairs/{token_address}")
async def get_dex_pairs(token_address: str = Path(...)):
try:
manager = get_provider_manager()
provider = manager.get_provider("dexscreener")
if not provider:
raise HTTPException(status_code=404, detail="DexScreener provider not available")
result = await provider.get_token_pairs(token_address)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "dexscreener")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/exchange/{exchange}/ticker")
async def get_exchange_ticker(
exchange: str = Path(...),
symbol: str = Query(..., description="Trading pair symbol")
):
try:
manager = get_provider_manager()
exchange_map = {
"binance": "binance",
"kraken": "kraken",
"bybit": "bybit",
"okx": "okx",
"htx": "htx",
"huobi": "htx",
"gateio": "gateio",
"gate": "gateio",
"kucoin": "kucoin"
}
provider_id = exchange_map.get(exchange.lower())
if not provider_id:
raise HTTPException(status_code=400, detail=f"Unsupported exchange: {exchange}")
provider = manager.get_provider(provider_id)
if not provider:
raise HTTPException(status_code=404, detail=f"Provider for {exchange} not found")
if hasattr(provider, "get_ticker"):
result = await provider.get_ticker(symbol)
else:
result = await provider.fetch_data(symbol=symbol)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), provider.config.name)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/exchange/{exchange}/orderbook")
async def get_exchange_orderbook(
exchange: str = Path(...),
symbol: str = Query(...),
limit: int = Query(100, le=1000)
):
try:
manager = get_provider_manager()
provider = manager.get_provider(exchange.lower())
if not provider:
raise HTTPException(status_code=404, detail=f"Provider for {exchange} not found")
if hasattr(provider, "get_orderbook"):
result = await provider.get_orderbook(symbol, limit)
else:
raise HTTPException(status_code=400, detail=f"Orderbook not available for {exchange}")
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), provider.config.name)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/metrics/global")
async def get_global_metrics():
try:
manager = get_provider_manager()
coingecko = manager.get_provider("coingecko")
if coingecko:
result = await coingecko.get_global()
if result.get("success"):
return create_response(result.get("data"), "coingecko")
coinpaprika = manager.get_provider("coinpaprika")
if coinpaprika:
result = await coinpaprika.get_global()
if result.get("success"):
return create_response(result.get("data"), "coinpaprika")
raise HTTPException(status_code=502, detail="No provider available for global metrics")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/trending")
async def get_trending_coins():
try:
manager = get_provider_manager()
provider = manager.get_provider("coingecko")
if not provider:
raise HTTPException(status_code=404, detail="CoinGecko provider not available")
result = await provider.get_trending()
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "coingecko")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/batch/prices")
async def batch_get_prices(
request: Dict[str, Any] = Body(...)
):
try:
symbols = request.get("symbols", ["bitcoin", "ethereum"])
vs_currencies = request.get("vs_currencies", "usd")
manager = get_provider_manager()
provider = manager.get_provider("coingecko")
if not provider:
raise HTTPException(status_code=404, detail="CoinGecko provider not available")
result = await provider.get_prices(symbols, vs_currencies)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "coingecko")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/v1/news/crypto")
async def get_crypto_news_newsapi(
query: str = Query("cryptocurrency OR bitcoin OR ethereum", description="Search query")
):
try:
manager = get_provider_manager()
provider = manager.get_provider("newsapi")
if not provider:
raise HTTPException(status_code=404, detail="NewsAPI provider not available")
result = await provider.get_crypto_news(query)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "newsapi")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/v1/news/headlines")
async def get_news_headlines(
category: str = Query("business", description="News category")
):
try:
manager = get_provider_manager()
provider = manager.get_provider("newsapi")
if not provider:
raise HTTPException(status_code=404, detail="NewsAPI provider not available")
result = await provider.get_top_headlines(category)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "newsapi")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/v1/market/cmc/listings")
async def get_cmc_listings(
limit: int = Query(100, le=5000, description="Number of listings")
):
try:
manager = get_provider_manager()
provider = manager.get_provider("coinmarketcap")
if not provider:
raise HTTPException(status_code=404, detail="CoinMarketCap provider not available")
result = await provider.get_listings(limit)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "coinmarketcap")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/v1/market/cmc/quotes/{symbols}")
async def get_cmc_quotes(
symbols: str = Path(..., description="Comma-separated symbols like BTC,ETH")
):
try:
manager = get_provider_manager()
provider = manager.get_provider("coinmarketcap")
if not provider:
raise HTTPException(status_code=404, detail="CoinMarketCap provider not available")
symbol_list = [s.strip().upper() for s in symbols.split(",")]
result = await provider.get_latest_quotes(symbol_list)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "coinmarketcap")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/v1/market/cmc/global")
async def get_cmc_global_metrics():
try:
manager = get_provider_manager()
provider = manager.get_provider("coinmarketcap")
if not provider:
raise HTTPException(status_code=404, detail="CoinMarketCap provider not available")
result = await provider.get_global_metrics()
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "coinmarketcap")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/v1/market/cmc/trending")
async def get_cmc_trending():
try:
manager = get_provider_manager()
provider = manager.get_provider("coinmarketcap")
if not provider:
raise HTTPException(status_code=404, detail="CoinMarketCap provider not available")
result = await provider.get_trending()
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "coinmarketcap")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/v1/sentiment/external")
async def get_external_sentiment(
symbol: str = Query("BTC", description="Cryptocurrency symbol")
):
try:
manager = get_provider_manager()
provider = manager.get_provider("sentiment_api")
if not provider:
raise HTTPException(status_code=404, detail="Sentiment API provider not available")
result = await provider.get_market_sentiment(symbol)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "sentiment_api")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/v1/sentiment/social")
async def get_social_sentiment(
symbol: str = Query("BTC", description="Cryptocurrency symbol")
):
try:
manager = get_provider_manager()
provider = manager.get_provider("sentiment_api")
if not provider:
raise HTTPException(status_code=404, detail="Sentiment API provider not available")
result = await provider.get_social_sentiment(symbol)
if not result.get("success"):
raise HTTPException(status_code=502, detail=result.get("error"))
return create_response(result.get("data"), "sentiment_api")
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))