Error Handling
Handle errors and exceptions in the Recal SDK.
Understanding Error Handling
The Recal SDK provides a comprehensive error handling system through the RecalError class. All SDK methods throw typed errors that you can catch and handle appropriately in your application.
RecalError Class
The SDK uses a custom RecalError class that extends the native JavaScript Error with additional properties:
class RecalError extends Error {
statusCode?: number // HTTP status code (404, 400, 500, etc.)
details?: unknown // Additional error details from the API
}Basic Error Handling
Wrap SDK calls in try-catch blocks to handle errors:
import { Recal, RecalError } from 'recal-sdk'
const recal = new Recal({ token: process.env.RECAL_TOKEN })
try {
const user = await recal.users.get('user_123')
console.log('User found:', user)
} catch (error) {
if (error instanceof RecalError) {
console.error('Recal API Error:', error.message)
console.error('Status Code:', error.statusCode)
console.error('Details:', error.details)
} else {
console.error('Unexpected error:', error)
}
}Common Error Status Codes
400 Bad Request
Invalid request parameters or missing required fields.
try {
await recal.events.createEvent('user_id', 'google', 'primary', {
subject: 'Meeting',
// Missing required 'start' and 'end' fields
})
} catch (error) {
if (error instanceof RecalError && error.statusCode === 400) {
console.error('Invalid request:', error.message)
// Handle validation errors
}
}401 Unauthorized
Invalid or missing API token.
const recal = new Recal({ token: 'invalid_token' })
try {
await recal.users.list()
} catch (error) {
if (error instanceof RecalError && error.statusCode === 401) {
console.error('Authentication failed - check your API token')
// Prompt user to re-authenticate or check token
}
}404 Not Found
Resource doesn't exist (user, organization, event, etc.).
try {
await recal.users.get('nonexistent_user')
} catch (error) {
if (error instanceof RecalError && error.statusCode === 404) {
console.error('User not found')
// Handle missing resource
}
}429 Too Many Requests
Rate limit exceeded.
try {
await recal.calendar.listEvents('user_id', {
start: '2024-01-01T00:00:00Z',
end: '2024-12-31T23:59:59Z'
})
} catch (error) {
if (error instanceof RecalError && error.statusCode === 429) {
console.error('Rate limit exceeded - please retry later')
// Implement exponential backoff
}
}500 Internal Server Error
Server-side error.
try {
await recal.oauth.verifyCode('google', { code: 'auth_code', state: 'state' })
} catch (error) {
if (error instanceof RecalError && error.statusCode === 500) {
console.error('Server error - please try again')
// Log error and notify monitoring system
}
}Error Handling Patterns
Centralized Error Handler
Create a reusable error handler for consistent error handling:
function handleRecalError(error: unknown, context: string) {
if (error instanceof RecalError) {
console.error(`[${context}] Recal API Error:`, {
message: error.message,
statusCode: error.statusCode,
details: error.details
})
// Handle specific status codes
switch (error.statusCode) {
case 400:
return { error: 'Invalid request', retry: false }
case 401:
return { error: 'Authentication failed', retry: false }
case 404:
return { error: 'Resource not found', retry: false }
case 429:
return { error: 'Rate limit exceeded', retry: true }
case 500:
return { error: 'Server error', retry: true }
default:
return { error: 'Unknown error', retry: false }
}
}
console.error(`[${context}] Unexpected error:`, error)
return { error: 'Unexpected error', retry: false }
}
// Usage
try {
await recal.users.create('user_123')
} catch (error) {
const result = handleRecalError(error, 'User Creation')
if (result.retry) {
// Implement retry logic
}
}Retry with Exponential Backoff
Handle transient errors with automatic retries:
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
initialDelay = 1000
): Promise<T> {
let lastError: Error
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn()
} catch (error) {
lastError = error as Error
// Only retry on specific errors
if (error instanceof RecalError) {
const shouldRetry = [429, 500, 503].includes(error.statusCode || 0)
if (!shouldRetry || attempt === maxRetries - 1) {
throw error
}
const delay = initialDelay * Math.pow(2, attempt)
console.log(`Retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`)
await new Promise(resolve => setTimeout(resolve, delay))
} else {
throw error
}
}
}
throw lastError!
}
// Usage
const user = await withRetry(() => recal.users.get('user_123'))Graceful Degradation
Handle errors gracefully without breaking your application:
async function getUserCalendars(userId: string) {
try {
return await recal.calendar.list(userId)
} catch (error) {
if (error instanceof RecalError) {
console.warn('Failed to fetch calendars:', error.message)
return [] // Return empty array as fallback
}
throw error
}
}Best Practices
- Always Use Try-Catch: Wrap all SDK calls in try-catch blocks
- Check Error Types: Use
instanceof RecalErrorto identify SDK errors - Log Error Details: Include
statusCodeanddetailsin logs for debugging - Handle Specific Codes: Implement different logic for different status codes
- Implement Retries: Retry transient errors (429, 500) with exponential backoff
- User-Friendly Messages: Convert technical errors to user-friendly messages
- Monitor Errors: Track error rates and patterns in your monitoring system
- Validate Input: Catch validation errors early before making API calls
Type Safety
TypeScript provides type checking for error handling:
import { Recal, RecalError } from 'recal-sdk'
async function safeUserFetch(userId: string) {
const recal = new Recal({ token: process.env.RECAL_TOKEN })
try {
const user = await recal.users.get(userId)
return { success: true, data: user }
} catch (error) {
// Type guard ensures proper error handling
if (error instanceof RecalError) {
return {
success: false,
error: error.message,
statusCode: error.statusCode
}
}
return { success: false, error: 'Unknown error' }
}
}