Last updated

Error Handling Guide

This guide covers common errors you might encounter when integrating with the Hubby eSIM API and how to handle them effectively.

Error Response Format

All API errors follow this format:

{
  "success": false,
  "error": {
    "code": 400,
    "message": "Validation failed",
    "details": {
      "field": "departure_date",
      "issue": "must be a future date"
    }
  }
}

Common Error Codes

400 Bad Request

  • Invalid request body
  • Missing required fields
  • Validation failures
try {
  const response = await createBooking(data);
} catch (error) {
  if (error.code === 400) {
    // Handle validation errors
    const field = error.details?.field;
    const issue = error.details?.issue;
    console.error(`Validation error: ${field} - ${issue}`);
  }
}

401 Unauthorized

  • Missing authentication headers
  • Invalid API key
  • Invalid signature
  • Expired timestamp
try {
  const response = await fetchPackages();
} catch (error) {
  if (error.code === 401) {
    // Check authentication issues
    if (error.message.includes('timestamp expired')) {
      // Retry with new timestamp
      return await fetchPackages();
    }
    // Other auth errors need manual intervention
    notifyAdmin('Authentication failed:', error.message);
  }
}

404 Not Found

  • Invalid booking ID
  • Invalid package ID
  • Invalid country code
try {
  const booking = await getBooking(bookingId);
} catch (error) {
  if (error.code === 404) {
    // Handle missing resource
    return showUserFriendlyError('Booking not found');
  }
}

500 Internal Server Error

  • Temporary server issues
  • Implement retry logic
async function createBookingWithRetry(data) {
  const maxRetries = 3;
  let lastError;

  for (let i = 0; i < maxRetries; i++) {
    try {
      return await createBooking(data);
    } catch (error) {
      lastError = error;
      if (error.code === 500) {
        // Wait before retrying
        await new Promise(resolve => setTimeout(resolve, 1000));
        continue;
      }
      throw error;
    }
  }
  
  // Log the failure after max retries
  console.error('Failed to create booking after retries:', lastError);
  throw lastError;
}

Best Practices

1. Implement Retry Logic

class RetryableError extends Error {
  constructor(message, code) {
    super(message);
    this.code = code;
    this.isRetryable = code === 500 || code === 429;
  }
}

async function withRetry(operation, maxRetries = 3) {
  let lastError;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      lastError = error;
      if (!error.isRetryable) throw error;
      
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }

  throw lastError;
}

2. Log Errors Properly

function logError(error, context = {}) {
  const errorLog = {
    timestamp: new Date().toISOString(),
    code: error.code,
    message: error.message,
    stack: error.stack,
    context
  };

  // Log to your monitoring system
  console.error(JSON.stringify(errorLog));
}

3. Handle Network Issues

async function fetchWithTimeout(url, options, timeout = 5000) {
  const controller = new AbortController();
  const id = setTimeout(() => controller.abort(), timeout);

  try {
    const response = await fetch(url, {
      ...options,
      signal: controller.signal
    });
    return response;
  } catch (error) {
    if (error.name === 'AbortError') {
      throw new Error('Request timed out');
    }
    throw error;
  } finally {
    clearTimeout(id);
  }
}

4. Validate Input Before Sending

function validateBookingData(data) {
  const errors = [];

  if (!data.departure_date) {
    errors.push('Departure date is required');
  } else if (new Date(data.departure_date) < new Date()) {
    errors.push('Departure date must be in the future');
  }

  if (!data.email && !data.booking_id) {
    errors.push('Either email or booking_id is required');
  }

  if (errors.length > 0) {
    throw new ValidationError(errors.join(', '));
  }
}

Error Monitoring

Consider implementing error monitoring to track and analyze errors:

class ErrorMonitor {
  constructor() {
    this.errors = new Map();
  }

  track(error) {
    const key = `${error.code}:${error.message}`;
    const count = (this.errors.get(key) || 0) + 1;
    this.errors.set(key, count);

    if (count > 10) {
      this.alert(key, count);
    }
  }

  alert(errorKey, count) {
    // Implement your alerting logic
    console.warn(`High error rate detected: ${errorKey} (${count} occurrences)`);
  }
}

Getting Help

If you encounter persistent errors:

  1. Check our API status page
  2. Review the API reference
  3. Contact support@hubbyesim.com