import os from typing import List import httpx from fastapi import APIRouter, HTTPException, Query, status router = APIRouter(prefix="/exchange-rates", tags=["exchange-rates"]) @router.get("", status_code=status.HTTP_200_OK) async def get_exchange_rates(symbols: str = Query("EUR,USD,NOK", description="Comma-separated currency codes to fetch vs CZK")): """ Fetch exchange rates from UniRate API on the backend and return CZK-per-target rates. - Always requests CZK in addition to requested symbols to compute conversion from USD-base. - Returns a list of {currencyCode, rate} where rate is CZK per 1 unit of the target currency. """ api_key = os.getenv("UNIRATE_API_KEY") if not api_key: raise HTTPException(status_code=500, detail="Server is not configured with UNIRATE_API_KEY") # Ensure CZK is included for conversion requested = [s.strip().upper() for s in symbols.split(",") if s.strip()] if "CZK" not in requested: requested.append("CZK") query_symbols = ",".join(sorted(set(requested))) url = f"https://unirateapi.com/api/rates?api_key={api_key}&symbols={query_symbols}" try: async with httpx.AsyncClient(timeout=httpx.Timeout(15.0)) as client: resp = await client.get(url) if resp.status_code != httpx.codes.OK: raise HTTPException(status_code=502, detail=f"Upstream UniRate error: HTTP {resp.status_code}") data = resp.json() except httpx.HTTPError as e: raise HTTPException(status_code=502, detail=f"Failed to contact UniRate: {str(e)}") # Validate response structure rates = data.get("rates") if isinstance(data, dict) else None base = data.get("base") if isinstance(data, dict) else None if not rates or base != "USD" or "CZK" not in rates: # Prefer upstream message when available detail = data.get("message") if isinstance(data, dict) else None if not detail and isinstance(data, dict): err = data.get("error") if isinstance(err, dict): detail = err.get("info") raise HTTPException(status_code=502, detail=detail or "Invalid response from UniRate API") czk_per_usd = rates["CZK"] # Build result excluding CZK itself result = [] for code in requested: if code == "CZK": continue target_per_usd = rates.get(code) if target_per_usd in (None, 0): # Skip unavailable or invalid continue czk_per_target = czk_per_usd / target_per_usd result.append({"currencyCode": code, "rate": czk_per_target}) return result