import axios from 'axios'; export class ExchangeRateService { private cachedRate: number | null = null; private cacheExpiry: Date | null = null; private readonly CACHE_DURATION_MS = 60 * 60 * 1000; private readonly FALLBACK_RATE: number; constructor() { this.FALLBACK_RATE = parseFloat(process.env.NGN_PER_USD || '750'); } async getNGNToUSDRate(): Promise { if (this.cachedRate && this.cacheExpiry && new Date() < this.cacheExpiry) { console.log('Using cached exchange rate:', this.cachedRate); return this.cachedRate; } try { const rate = await this.fetchExchangeRate(); this.cachedRate = rate; this.cacheExpiry = new Date(Date.now() + this.CACHE_DURATION_MS); console.log('Fetched new exchange rate:', rate); return rate; } catch (error) { console.error('Failed to fetch exchange rate, using fallback:', error); return this.FALLBACK_RATE; } } private async fetchExchangeRate(): Promise { try { const response = await axios.get('https://api.exchangerate-api.com/v4/latest/USD', { timeout: 5000, }); const rate = response.data.rates?.NGN; if (rate && rate > 0) { return rate; } } catch (error) { console.warn('ExchangeRate-API failed, trying alternative...'); } // Option 2: CurrencyAPI (requires free API key, but more reliable) const currencyApiKey = process.env.CURRENCY_API_KEY; if (currencyApiKey) { try { const response = await axios.get( `https://api.currencyapi.com/v3/latest?apikey=${currencyApiKey}¤cies=NGN&base_currency=USD`, { timeout: 5000 } ); const rate = response.data.data?.NGN?.value; if (rate && rate > 0) { return rate; } } catch (error) { console.warn('CurrencyAPI failed, trying alternative...'); } } // Option 3: Fixer.io (requires API key) const fixerApiKey = process.env.FIXER_API_KEY; if (fixerApiKey) { try { const response = await axios.get( `https://api.fixer.io/latest?access_key=${fixerApiKey}&base=USD&symbols=NGN`, { timeout: 5000 } ); const rate = response.data.rates?.NGN; if (rate && rate > 0) { return rate; } } catch (error) { console.warn('Fixer.io failed, using fallback...'); } } // If all APIs fail, throw error to use fallback throw new Error('All exchange rate APIs failed'); } /** * Get the fallback rate (from env or default) */ getFallbackRate(): number { return this.FALLBACK_RATE; } /** * Clear the cache (useful for testing or manual refresh) */ clearCache(): void { this.cachedRate = null; this.cacheExpiry = null; } }