Skip to content

Commit 68039e0

Browse files
committed
Fix Bitcoin price API for production with CORS and error handling
1 parent b774f56 commit 68039e0

4 files changed

Lines changed: 74 additions & 14 deletions

File tree

pages/api/coinbase-realtime.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ if (typeof global !== 'undefined') {
7676
}
7777

7878
export default async function handler(req, res) {
79+
// CRITICAL FOR PRODUCTION: Add CORS headers
80+
res.setHeader('Access-Control-Allow-Origin', '*');
81+
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
82+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
83+
84+
// If it's a preflight request, send 200
85+
if (req.method === 'OPTIONS') {
86+
return res.status(200).end();
87+
}
88+
89+
// Log request in production for debugging
90+
console.log('Coinbase realtime API called, environment:', process.env.NODE_ENV);
7991
// If WebSocket is not available or hasn't received data yet
8092
if (!lastPrice) {
8193
console.log('WebSocket data not available, fetching direct price');

pages/api/price-history.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,23 @@ let cacheTimestamp = 0;
99
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes cache for historical data
1010

1111
export default async function handler(req, res) {
12+
// CRITICAL FOR PRODUCTION: Add CORS headers
13+
res.setHeader('Access-Control-Allow-Origin', '*');
14+
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
15+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
16+
17+
// If it's a preflight request, send 200
18+
if (req.method === 'OPTIONS') {
19+
return res.status(200).end();
20+
}
21+
1222
// Set cache headers for the browser - allow for more frequent updates
1323
// We use WebSockets for real-time data, so this is just for the historical data
1424
res.setHeader('Cache-Control', 'public, max-age=60, s-maxage=300');
1525

26+
// Log for debugging in production
27+
console.log('Price history API called, environment:', process.env.NODE_ENV);
28+
1629
try {
1730
// Try to use cache if available and not expired
1831
const now = Date.now();

src/hooks/useBitcoinPrice.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,23 @@ export function useBitcoinPrice(initialTimeframe: TimeFrame = '1D'): UseBitcoinP
161161

162162
// Set up polling on mount
163163
useEffect(() => {
164+
// Add debug log for production
165+
console.log('Setting up Bitcoin price polling in', process.env.NODE_ENV);
166+
164167
// Do NOT use fallback data - just show loading state until real data arrives
165168
// The initial fetch is fast enough with WebSockets
166169

167170
// Initial fetch
168-
fetchBitcoinData(true);
171+
console.log('Starting initial Bitcoin price fetch');
172+
fetchBitcoinData(true)
173+
.then(() => console.log('Initial Bitcoin price fetch complete'))
174+
.catch(err => console.error('Error in initial price fetch:', err));
169175

170176
// Set up refresh interval for real-time updates
171177
pollingIntervalRef.current = setInterval(() => {
172-
fetchBitcoinData(true);
178+
console.log('Executing periodic Bitcoin price refresh');
179+
fetchBitcoinData(true)
180+
.catch(err => console.error('Error in periodic price fetch:', err));
173181
}, REFRESH_INTERVAL);
174182

175183
// Cleanup on unmount

src/lib/minimalBitcoinApi.ts

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,24 @@ export async function getBitcoinPrice(timeframe: TimeFrame): Promise<BitcoinPric
7878

7979
clearTimeout(timeoutId);
8080

81-
if (realtimeResponse.ok) {
82-
const realtimeData = await realtimeResponse.json();
83-
84-
if (realtimeData.success && realtimeData.price) {
85-
realtimePrice = realtimeData.price;
86-
console.log('Using real-time price:', realtimePrice, 'from', realtimeData.source || 'unknown');
87-
} else {
88-
console.warn('Real-time API returned success:false');
89-
}
90-
} else {
81+
// Try to parse even if status is not OK
82+
let realtimeData;
83+
try {
84+
realtimeData = await realtimeResponse.json();
85+
console.log('Real-time API response:', realtimeData);
86+
} catch (parseError) {
87+
console.warn('Failed to parse real-time API response', parseError);
88+
const text = await realtimeResponse.text();
89+
console.warn('Raw response:', text);
90+
}
91+
92+
if (realtimeData && realtimeData.success && realtimeData.price) {
93+
realtimePrice = realtimeData.price;
94+
console.log('Using real-time price:', realtimePrice, 'from', realtimeData.source || 'unknown');
95+
} else if (!realtimeResponse.ok) {
9196
console.warn('Real-time API returned non-OK status:', realtimeResponse.status);
97+
} else {
98+
console.warn('Real-time API returned invalid data:', realtimeData);
9299
}
93100
} catch (error) {
94101
console.warn('Failed to get real-time price, will use historical data:', error);
@@ -123,11 +130,31 @@ export async function getBitcoinPrice(timeframe: TimeFrame): Promise<BitcoinPric
123130

124131
clearTimeout(timeoutId);
125132

133+
// Try to parse the response even if status is not OK
134+
let result;
135+
try {
136+
result = await response.json();
137+
console.log('Historical API response structure:',
138+
result ?
139+
`success=${!!result.success}, has timeframes=${!!result.timeframes}, timeframe count=${result.timeframes ? Object.keys(result.timeframes).length : 0}` :
140+
'null response'
141+
);
142+
} catch (error) {
143+
console.error('Failed to parse historical API response', error);
144+
const text = await response.text();
145+
console.error('Raw historical response:', text);
146+
throw new Error(`Failed to parse API response: ${error instanceof Error ? error.message : String(error)}`);
147+
}
148+
126149
if (!response.ok) {
127-
throw new Error(`API error: ${response.status}`);
150+
console.error(`Historical API error: ${response.status}`);
128151
}
129152

130-
const result = await response.json();
153+
// Validate the response structure
154+
if (!result || !result.price || !result.timeframes) {
155+
console.error('Invalid historical API response structure:', result);
156+
throw new Error('Invalid historical data structure');
157+
}
131158

132159
// Save to cache for future use
133160
saveToCache(result);

0 commit comments

Comments
 (0)