Error Handling

Handle API errors gracefully in your application

Basic Error Handling

import { VedikaClient, VedikaError } from '@vedika/sdk';

const vedika = new VedikaClient();

try {
  const chart = await vedika.birthChart({
    datetime: '1990-05-15T10:30:00+05:30',
    latitude: 28.6139,
    longitude: 77.2090
  });
} catch (error) {
  if (error instanceof VedikaError) {
    console.error('API Error:', error.message);
    console.error('Error Code:', error.code);
    console.error('Status:', error.status);
  } else {
    console.error('Unexpected error:', error);
  }
}

Error Codes Reference

Code Status Description Action
INVALID_API_KEY 401 API key is invalid or missing Check API key configuration
EXPIRED_API_KEY 401 API key has expired Regenerate key in dashboard
INSUFFICIENT_CREDITS 402 Not enough credits for request Add credits to account
RATE_LIMITED 429 Too many requests Wait and retry with backoff
INVALID_PARAMETERS 400 Invalid request parameters Check parameter values
INVALID_DATE 400 Invalid date format Use ISO 8601 format
INVALID_COORDINATES 400 Latitude/longitude out of range Lat: -90 to 90, Lng: -180 to 180
SERVICE_UNAVAILABLE 503 Service temporarily unavailable Retry with exponential backoff
TIMEOUT 504 Request timed out Retry or increase timeout

VedikaError Object

interface VedikaError extends Error {
  code: string;           // Error code (e.g., 'INVALID_API_KEY')
  status: number;         // HTTP status code
  message: string;        // Human-readable message
  details?: object;       // Additional error details
  requestId?: string;     // Request ID for support
  retryable: boolean;     // Whether request can be retried
  retryAfter?: number;    // Seconds to wait before retry (for rate limits)
}

// Example error object
{
  name: 'VedikaError',
  code: 'RATE_LIMITED',
  status: 429,
  message: 'Rate limit exceeded. Please wait before retrying.',
  retryable: true,
  retryAfter: 60,
  requestId: 'req_abc123xyz'
}

Handle Specific Errors

import { VedikaClient, VedikaError } from '@vedika/sdk';

async function fetchChart(birthDetails) {
  const vedika = new VedikaClient();

  try {
    return await vedika.birthChart(birthDetails);
  } catch (error) {
    if (!(error instanceof VedikaError)) {
      throw error;  // Re-throw unexpected errors
    }

    switch (error.code) {
      case 'INVALID_API_KEY':
      case 'EXPIRED_API_KEY':
        // Redirect to settings or show API key error
        console.error('Authentication failed. Please check your API key.');
        throw new Error('Please configure your API key');

      case 'INSUFFICIENT_CREDITS':
        // Redirect to billing or show upgrade prompt
        console.error('No credits remaining.');
        throw new Error('Please add credits to continue');

      case 'RATE_LIMITED':
        // Show rate limit message with retry time
        const waitTime = error.retryAfter || 60;
        console.error(`Rate limited. Retry in ${waitTime} seconds.`);
        throw new Error(`Too many requests. Please wait ${waitTime} seconds.`);

      case 'INVALID_DATE':
        // Show date format error
        console.error('Invalid date format:', error.details);
        throw new Error('Please enter a valid date (YYYY-MM-DD)');

      case 'INVALID_COORDINATES':
        // Show location error
        console.error('Invalid coordinates');
        throw new Error('Please enter valid location coordinates');

      case 'SERVICE_UNAVAILABLE':
      case 'TIMEOUT':
        // Show temporary error, maybe retry
        console.error('Service temporarily unavailable');
        throw new Error('Service is temporarily unavailable. Please try again.');

      default:
        console.error('Unexpected API error:', error.code);
        throw new Error('An unexpected error occurred. Please try again.');
    }
  }
}

Automatic Retries

// SDK has built-in retry logic
const vedika = new VedikaClient({
  apiKey: process.env.VEDIKA_API_KEY,
  maxRetries: 3,           // Retry up to 3 times (default)
  retryDelay: 1000,        // Start with 1 second delay
  retryBackoff: 2,         // Double delay each retry
  timeout: 30000           // 30 second timeout
});

// Retries happen automatically for:
// - Network errors
// - 5xx server errors
// - 429 rate limit errors (respects Retry-After header)

// NOT retried:
// - 4xx client errors (invalid params, auth errors)
// - Timeout after configured duration

Custom Retry Logic

async function withRetry(fn, options = {}) {
  const {
    maxRetries = 3,
    baseDelay = 1000,
    maxDelay = 30000,
    retryOn = ['RATE_LIMITED', 'SERVICE_UNAVAILABLE', 'TIMEOUT']
  } = options;

  let lastError;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;

      // Don't retry non-retryable errors
      if (error instanceof VedikaError && !retryOn.includes(error.code)) {
        throw error;
      }

      // Don't retry on last attempt
      if (attempt === maxRetries) {
        break;
      }

      // Calculate delay with exponential backoff
      let delay = baseDelay * Math.pow(2, attempt);

      // Respect Retry-After header for rate limits
      if (error.retryAfter) {
        delay = error.retryAfter * 1000;
      }

      // Cap the delay
      delay = Math.min(delay, maxDelay);

      console.log(`Retry ${attempt + 1}/${maxRetries} in ${delay}ms...`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }

  throw lastError;
}

// Usage
const chart = await withRetry(
  () => vedika.birthChart(birthDetails),
  { maxRetries: 3, baseDelay: 2000 }
);

Validate Before Request

import { validateBirthDetails } from '@vedika/sdk';

function validateInput(birthDetails) {
  const errors = [];

  // Date validation
  const date = new Date(birthDetails.datetime);
  if (isNaN(date.getTime())) {
    errors.push('Invalid date format. Use ISO 8601 (YYYY-MM-DDTHH:mm:ss+offset)');
  }

  // Latitude validation
  if (birthDetails.latitude < -90 || birthDetails.latitude > 90) {
    errors.push('Latitude must be between -90 and 90');
  }

  // Longitude validation
  if (birthDetails.longitude < -180 || birthDetails.longitude > 180) {
    errors.push('Longitude must be between -180 and 180');
  }

  // Future date check
  if (date > new Date()) {
    errors.push('Birth date cannot be in the future');
  }

  return errors;
}

// Usage
const errors = validateInput(birthDetails);
if (errors.length > 0) {
  console.error('Validation errors:', errors);
  return;
}

// Proceed with API call
const chart = await vedika.birthChart(birthDetails);

Global Error Handler

// Create a wrapper with global error handling
class VedikaService {
  constructor(apiKey) {
    this.client = new VedikaClient({ apiKey });
    this.onError = null;  // Error callback
  }

  setErrorHandler(handler) {
    this.onError = handler;
  }

  async execute(method, params) {
    try {
      return await this.client[method](params);
    } catch (error) {
      // Log error
      console.error(`Vedika API Error [${method}]:`, error);

      // Track error (e.g., Sentry)
      if (typeof Sentry !== 'undefined') {
        Sentry.captureException(error, {
          tags: { api: 'vedika', method },
          extra: { params }
        });
      }

      // Call error handler
      if (this.onError) {
        this.onError(error, method, params);
      }

      throw error;
    }
  }

  birthChart(params) {
    return this.execute('birthChart', params);
  }

  panchang(params) {
    return this.execute('panchang', params);
  }

  // ... other methods
}

// Usage
const vedika = new VedikaService(process.env.VEDIKA_API_KEY);

vedika.setErrorHandler((error, method, params) => {
  // Show user-friendly toast notification
  showToast({
    type: 'error',
    message: getErrorMessage(error)
  });
});

function getErrorMessage(error) {
  const messages = {
    'INSUFFICIENT_CREDITS': 'Please add credits to continue using the service.',
    'RATE_LIMITED': 'Too many requests. Please slow down.',
    'SERVICE_UNAVAILABLE': 'Service temporarily unavailable. Please try again.'
  };
  return messages[error.code] || 'An error occurred. Please try again.';
}

Related Topics