feat(api): enhance price history fetching with range support and improved error handling
This commit is contained in:
@@ -28,6 +28,34 @@ const COINGECKO_RANGE_TO_DAYS: Record<MarketChartRange, string> = {
|
|||||||
all: "max",
|
all: "max",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function buildHistoryUrls(providerId: string, range: MarketChartRange): string[] {
|
||||||
|
const encodedId = encodeURIComponent(providerId);
|
||||||
|
const days = COINGECKO_RANGE_TO_DAYS[range];
|
||||||
|
|
||||||
|
if (range === "all") {
|
||||||
|
const nowInSeconds = Math.floor(Date.now() / 1000);
|
||||||
|
const tenYearsAgoInSeconds = nowInSeconds - 60 * 60 * 24 * 365 * 10;
|
||||||
|
|
||||||
|
return [
|
||||||
|
`${COINGECKO_BASE_URL}/coins/${encodedId}/market_chart?vs_currency=usd&days=max`,
|
||||||
|
`${COINGECKO_BASE_URL}/coins/${encodedId}/market_chart?vs_currency=usd&days=max&interval=daily`,
|
||||||
|
`${COINGECKO_BASE_URL}/coins/${encodedId}/market_chart?vs_currency=usd&days=3650`,
|
||||||
|
`${COINGECKO_BASE_URL}/coins/${encodedId}/market_chart?vs_currency=usd&days=3650&interval=daily`,
|
||||||
|
`${COINGECKO_BASE_URL}/coins/${encodedId}/market_chart/range?vs_currency=usd&from=${tenYearsAgoInSeconds}&to=${nowInSeconds}`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (range === "1y") {
|
||||||
|
return [
|
||||||
|
`${COINGECKO_BASE_URL}/coins/${encodedId}/market_chart?vs_currency=usd&days=${encodeURIComponent(days)}&interval=daily`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
`${COINGECKO_BASE_URL}/coins/${encodedId}/market_chart?vs_currency=usd&days=${encodeURIComponent(days)}`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
function buildCoinGeckoHeaders(): HeadersInit {
|
function buildCoinGeckoHeaders(): HeadersInit {
|
||||||
const headers: Record<string, string> = {
|
const headers: Record<string, string> = {
|
||||||
accept: "application/json"
|
accept: "application/json"
|
||||||
@@ -108,18 +136,18 @@ export async function fetchCryptoPriceHistory(
|
|||||||
providerId: string,
|
providerId: string,
|
||||||
range: MarketChartRange,
|
range: MarketChartRange,
|
||||||
): Promise<CryptoPricePoint[]> {
|
): Promise<CryptoPricePoint[]> {
|
||||||
const days = COINGECKO_RANGE_TO_DAYS[range];
|
const urls = buildHistoryUrls(providerId, range);
|
||||||
const url = `${COINGECKO_BASE_URL}/coins/${encodeURIComponent(
|
let lastStatus: number | null = null;
|
||||||
providerId,
|
|
||||||
)}/market_chart?vs_currency=usd&days=${encodeURIComponent(days)}`;
|
|
||||||
|
|
||||||
|
for (const url of urls) {
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
next: { revalidate: 60 },
|
next: { revalidate: 60 },
|
||||||
headers: buildCoinGeckoHeaders(),
|
headers: buildCoinGeckoHeaders(),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Unable to load crypto price history (${response.status})`);
|
lastStatus = response.status;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = (await response.json()) as {
|
const payload = (await response.json()) as {
|
||||||
@@ -133,14 +161,23 @@ export async function fetchCryptoPriceHistory(
|
|||||||
entry.length >= 2 &&
|
entry.length >= 2 &&
|
||||||
Number.isFinite(entry[0]) &&
|
Number.isFinite(entry[0]) &&
|
||||||
Number.isFinite(entry[1]) &&
|
Number.isFinite(entry[1]) &&
|
||||||
entry[1] > 0,
|
entry[1] >= 0,
|
||||||
)
|
)
|
||||||
.map(([timestamp, priceUsd]) => ({
|
.map(([timestamp, priceUsd]) => ({
|
||||||
timestamp: new Date(timestamp).toISOString(),
|
timestamp: new Date(timestamp).toISOString(),
|
||||||
priceUsd,
|
priceUsd,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (points.length > 1) {
|
||||||
return points;
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastStatus !== null) {
|
||||||
|
throw new Error(`Unable to load crypto price history (${lastStatus})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Crypto price history is unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchCryptoData(): Promise<CryptoRateResult> {
|
export async function fetchCryptoData(): Promise<CryptoRateResult> {
|
||||||
|
|||||||
Reference in New Issue
Block a user