class APIError extends Error {
constructor(status, message, code) {
super(message);
this.name = 'APIError';
this.status = status;
this.code = code;
}
}
class AuthenticationError extends APIError {
constructor(message) {
super(401, message, 'authentication_error');
this.name = 'AuthenticationError';
}
}
class NotFoundError extends APIError {
constructor(resource) {
super(404, `${resource} not found`, 'not_found');
this.name = 'NotFoundError';
}
}
class RateLimitError extends APIError {
constructor(retryAfter) {
super(429, 'Rate limit exceeded', 'rate_limit_exceeded');
this.name = 'RateLimitError';
this.retryAfter = retryAfter;
}
}
async function fetchWithCustomErrors(url, options) {
const response = await fetch(url, options);
if (response.ok) {
return await response.json();
}
const error = await response.json();
switch (response.status) {
case 401:
throw new AuthenticationError(error.message);
case 404:
throw new NotFoundError('Resource');
case 429:
const retryAfter = response.headers.get('Retry-After');
throw new RateLimitError(retryAfter);
default:
throw new APIError(response.status, error.message, error.error);
}
}
// Usage
try {
const member = await fetchWithCustomErrors(url, options);
} catch (error) {
if (error instanceof AuthenticationError) {
console.log('Please re-authenticate');
} else if (error instanceof NotFoundError) {
console.log('Resource was deleted');
} else if (error instanceof RateLimitError) {
console.log(`Wait ${error.retryAfter}s before retrying`);
}
}