The SDK provides consistent, type-safe error handling across all API operations with automatic recovery mechanisms and structured error responses.

ApiResult Pattern

All SDK methods return a consistent ApiResult<T> structure:

type ApiResult<T> = {
  success: true;
  data: T;
} | {
  success: false;
  error: ApiErrorResponse;
};

Type-Safe Error Handling

const result = await client.catalog.getProduct('product-id');

if (result.success) {
  // βœ… TypeScript knows result.data is a Product
  console.log(result.data.name);
  console.log(result.data.selling_price);
} else {
  // βœ… TypeScript knows result.error is ApiErrorResponse
  console.error(result.error.message);
  console.error(result.error.code);
  
  // Handle specific error types
  switch (result.error.code) {
    case 'NOT_FOUND':
      showProductNotFound();
      break;
    case 'VALIDATION_ERROR':
      showValidationError(result.error.details);
      break;
    default:
      showGenericError(result.error.message);
  }
}

Error Types & Codes

The SDK provides structured error responses with consistent codes:

Automatic Error Recovery

Token Refresh

The SDK automatically handles token expiry:

// This request may trigger automatic token refresh
const result = await client.customer.getCustomerDetail('user-id');

// No manual token handling needed!
if (result.success) {
  console.log(result.data.email);
}

Authentication Recovery

The SDK automatically handles token refresh and authentication recovery:

// SDK handles token refresh transparently
const client = new StorefrontSDK({
  storeId: 'your-store-id',
  apiKey: 'your-api-key',
  tokenStorage: new BrowserTokenStorage() // Enables automatic token management
});

Error Handling Patterns

Component Error Boundaries

// React error boundary for SDK errors
class SDKErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }
  
  render() {
    if (this.state.hasError) {
      // Handle SDK-specific errors
      if (this.state.error?.code === 'NETWORK_ERROR') {
        return <NetworkErrorPage />;
      }
      
      return <GenericErrorPage error={this.state.error} />;
    }
    
    return this.props.children;
  }
}

Form Validation

// Handle validation errors in forms
async function submitForm(formData) {
  const result = await client.customer.updateCustomerDetail('user-id', formData);
  
  if (!result.success) {
    if (result.error.code === 'VALIDATION_ERROR') {
      // Display field-specific errors
      setFieldErrors(result.error.details);
      return;
    }
    
    // Handle other errors
    setGeneralError(result.error.message);
  }
  
  // Success
  showSuccessMessage();
}

Global Error Handler

// Global error handler for SDK operations
const handleSDKError = (error: ApiErrorResponse) => {
  // Log to monitoring service
  errorLogger.log(error);
  
  // Show user-friendly messages
  switch (error.code) {
    case 'NETWORK_ERROR':
      toast.error('Connection problem. Please check your internet.');
      break;
    case 'UNAUTHORIZED':
      toast.error('Session expired. Please log in again.');
      redirectToLogin();
      break;
    case 'SERVER_ERROR':
      toast.error('Server error. Please try again later.');
      break;
    default:
      toast.error(error.message || 'Something went wrong.');
  }
};

// Use in SDK operations
const result = await client.catalog.listProducts();
if (!result.success) {
  handleSDKError(result.error);
}

Error Monitoring

Custom Error Logging

const client = new StorefrontSDK({
  storeId: 'your-store-id',
  apiKey: 'your-api-key',
  debug: true,
  logger: (level, message, data) => {
    if (level === 'error') {
      // Send to error tracking service
      Sentry.captureException(new Error(message), {
        extra: data,
        tags: { source: 'storefront-sdk' }
      });
    }
  }
});

Error Analytics

// Track error patterns
const trackError = (error: ApiErrorResponse, context: string) => {
  analytics.track('sdk_error', {
    error_code: error.code,
    error_message: error.message,
    context,
    timestamp: new Date().toISOString(),
    user_agent: navigator.userAgent
  });
};

// Usage
const result = await client.order.createOrder(orderData);
if (!result.success) {
  trackError(result.error, 'checkout_flow');
}

Best Practices

Always Check Success

Never assume SDK operations succeed - always check the success field

Handle Specific Errors

Use error codes to provide appropriate user experiences for different failure scenarios

Implement Fallbacks

Provide graceful degradation when operations fail

Monitor Errors

Track error rates and patterns to identify issues early

Cross-References

The SDK’s error handling builds on top of the patterns described in the Storefront Guides, providing automatic recovery and type safety for a better developer experience.