class APIError extends Error {
constructor(message, status, type, code) {
super(message);
this.status = status;
this.type = type;
this.code = code;
}
}
async function safeAPICall(apiFunc, ...args) {
const maxRetries = 3;
let retryDelay = 1000;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await apiFunc(...args);
} catch (error) {
// Parse error details
const status = error.status || 500;
const errorData = error.response?.data?.error || {};
// Handle different error types
switch (status) {
case 401:
throw new APIError(
'Authentication failed. Check your API key.',
401,
'authentication_error',
errorData.code
);
case 402:
throw new APIError(
'Insufficient credits. Please add credits.',
402,
'insufficient_credits_error',
errorData.code
);
case 429:
// Rate limited - exponential backoff
const waitTime = retryDelay * Math.pow(2, attempt);
console.log(`Rate limited. Waiting ${waitTime}ms...`);
await new Promise((resolve) => setTimeout(resolve, waitTime));
continue;
case 500:
case 502:
case 503:
// Server errors - retry
if (attempt < maxRetries - 1) {
console.log(`Server error. Retrying in ${retryDelay}ms...`);
await new Promise((resolve) => setTimeout(resolve, retryDelay));
continue;
}
break;
}
// Can't handle this error
throw error;
}
}
throw new Error('Max retries exceeded');
}
// Usage
try {
const response = await safeAPICall(
openai.chat.completions.create.bind(openai),
{
model: 'gpt-3.5-turbo',
messages: [{ role: 'user', content: 'Hello!' }],
}
);
} catch (error) {
console.error('Failed to complete request:', error.message);
}