JAVASCRIPT
Robust API Request with Retry Logic
Implement a JavaScript fetch wrapper that automatically retries failed API requests, improving reliability for transient network issues or server errors.
async function fetchWithRetry(url, options = {}, retries = 3, delay = 1000) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
if (response.ok) {
return response;
} else if (response.status === 429) {
// Too Many Requests - respect Retry-After header if present
const retryAfter = response.headers.get('Retry-After');
const retryDelay = retryAfter ? parseInt(retryAfter, 10) * 1000 : delay * Math.pow(2, i); // Exponential backoff
console.warn(`Rate limited. Retrying in ${retryDelay / 1000}s...`);
await new Promise(resolve => setTimeout(resolve, retryDelay));
} else if (response.status >= 500 && response.status < 600) {
// Server error, may be transient
console.warn(`Server error (${response.status}). Retrying in ${delay / 1000}s...`);
await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i))); // Exponential backoff
} else {
// Non-retriable client error (4xx) or other unhandled status
const errorData = await response.json().catch(() => response.text());
throw new Error(`API error ${response.status}: ${JSON.stringify(errorData)}`);
}
} catch (error) {
if (error instanceof TypeError) {
// Network error (e.g., DNS failure, no internet) - often retriable
console.warn(`Network error: ${error.message}. Retrying in ${delay / 1000}s...`);
await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i))); // Exponential backoff
} else {
throw error; // Re-throw non-retryable errors
}
}
}
throw new Error(`Failed to fetch ${url} after ${retries} attempts.`);
}
// Example usage:
// (async () => {
// try {
// const data = await fetchWithRetry('https://api.example.com/data', { method: 'GET' });
// const jsonResponse = await data.json();
// console.log('Fetched data:', jsonResponse);
// } catch (error) {
// console.error('Failed to fetch data after retries:', error.message);
// }
// })();
How it works: This snippet provides a `fetchWithRetry` function that wraps the standard Fetch API, adding resilience to API integrations. It automatically retries requests multiple times with an exponential backoff strategy for network errors, server-side issues (5xx), and rate limiting (429). It also respects the `Retry-After` header for rate limits and explicitly handles non-retriable client errors (4xx) by throwing immediately, ensuring your application doesn't get stuck in a retry loop for permanent issues.