Skip to main content

Error Response Format

All errors follow this standard structure:
{
  "status": false,
  "error": "error_code",
  "message": "Detailed error message"
}

Common Error Codes

HTTP StatusError CodeDescriptionHow to Handle
400eksik alanMissing required fieldCheck request body
401yetkisiz erişimInvalid/expired tokenRefresh access token
403URL hatalıInvalid UUID or unauthorizedVerify resource ID and permissions
404sipariş bulunamadıOrder not foundOrder may have been deleted
404restoran bulunamadıRestaurant not foundCheck restaurant ID
404ürün bulunamadıFood item not foundCheck food ID
422eksik alanMalformed requestValidate request format
429çok fazla istekRate limit exceededWait 30 seconds before retry
500Internal server errorServer errorRetry with exponential backoff

Error Handling Strategy

1

Catch All Errors

Always wrap API calls in try-catch blocks
2

Parse Error Response

Extract error code and message from response
3

Handle Specific Errors

Implement specific handling for each error type
4

Log for Debugging

Log errors with context for troubleshooting
5

Notify User

Display user-friendly error messages

Implementation Example

class APIError extends Error {
  constructor(status, errorCode, message) {
    super(message);
    this.status = status;
    this.errorCode = errorCode;
    this.name = 'APIError';
  }
}

async function makeApiCall(endpoint, options = {}) {
  try {
    const response = await fetch(endpoint, options);
    const data = await response.json();
    
    if (!data.status) {
      throw new APIError(
        response.status,
        data.error,
        data.message || data.error
      );
    }
    
    return data.data;
    
  } catch (error) {
    // Handle network errors
    if (error instanceof TypeError) {
      throw new APIError(0, 'network_error', 'Unable to connect to API');
    }
    
    throw error;
  }
}

async function handleApiCall(apiFunction) {
  try {
    return await apiFunction();
  } catch (error) {
    if (error instanceof APIError) {
      return handleAPIError(error);
    } else {
      console.error('Unexpected error:', error);
      throw error;
    }
  }
}

function handleAPIError(error) {
  switch (error.status) {
    case 401:
      return handleAuthError(error);
    
    case 403:
      return handleForbiddenError(error);
    
    case 404:
      return handleNotFoundError(error);
    
    case 422:
      return handleValidationError(error);
    
    case 429:
      return handleRateLimitError(error);
    
    case 500:
      return handleServerError(error);
    
    default:
      return handleGenericError(error);
  }
}

Handling Specific Errors

async function handleAuthError(error) {
  console.log('Token expired or invalid');
  
  // 1. Try to refresh token
  try {
    await refreshAccessToken();
    
    // 2. Retry the failed request
    return await retryLastRequest();
    
  } catch (refreshError) {
    // 3. If refresh fails, redirect to login
    redirectToLogin();
    throw new Error('Authentication failed');
  }
}

async function refreshAccessToken() {
  const credentials = getStoredCredentials();
  
  const response = await login(
    credentials.appSecret,
    credentials.restSecret
  );
  
  storeAccessToken(response.access_token);
  return response;
}

Retry Strategy

class RetryHandler {
  constructor(maxRetries = 3) {
    this.maxRetries = maxRetries;
    this.retryableErrors = [429, 500, 502, 503, 504];
  }
  
  async execute(apiFunction, attempt = 1) {
    try {
      return await apiFunction();
      
    } catch (error) {
      // Check if error is retryable
      if (!this.shouldRetry(error, attempt)) {
        throw error;
      }
      
      // Calculate delay with exponential backoff
      const delay = this.calculateDelay(error, attempt);
      
      console.log(`Retry attempt ${attempt}/${this.maxRetries} in ${delay}ms`);
      await sleep(delay);
      
      // Retry
      return this.execute(apiFunction, attempt + 1);
    }
  }
  
  shouldRetry(error, attempt) {
    if (attempt >= this.maxRetries) {
      return false;
    }
    
    if (error instanceof APIError) {
      return this.retryableErrors.includes(error.status);
    }
    
    // Retry network errors
    return error instanceof TypeError;
  }
  
  calculateDelay(error, attempt) {
    // Rate limit: wait full 30 seconds
    if (error.status === 429) {
      return 30000;
    }
    
    // Exponential backoff for other errors: 1s, 2s, 4s
    return 1000 * Math.pow(2, attempt - 1);
  }
}

// Usage
const retryHandler = new RetryHandler(3);

try {
  const orders = await retryHandler.execute(() => 
    getOrders()
  );
} catch (error) {
  console.error('Failed after retries:', error);
}

Logging Best Practices

class ErrorLogger {
  log(error, context = {}) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      error: {
        name: error.name,
        message: error.message,
        stack: error.stack,
        status: error.status,
        errorCode: error.errorCode
      },
      context: {
        ...context,
        userId: currentUser?.id,
        restaurantId: currentRestaurant?.id,
        endpoint: context.endpoint,
        requestData: context.requestData
      },
      environment: process.env.NODE_ENV,
      version: APP_VERSION
    };
    
    // Log to console
    console.error('API Error:', logEntry);
    
    // Send to error tracking service
    if (errorTracker) {
      errorTracker.captureException(error, logEntry);
    }
    
    // Store locally for debugging
    this.storeLog(logEntry);
  }
  
  storeLog(logEntry) {
    const logs = JSON.parse(localStorage.getItem('errorLogs') || '[]');
    logs.push(logEntry);
    
    // Keep only last 100 errors
    if (logs.length > 100) {
      logs.shift();
    }
    
    localStorage.setItem('errorLogs', JSON.stringify(logs));
  }
  
  getLogs() {
    return JSON.parse(localStorage.getItem('errorLogs') || '[]');
  }
}

const logger = new ErrorLogger();

// Usage
try {
  await apiCall();
} catch (error) {
  logger.log(error, {
    endpoint: '/orders/get-current',
    operation: 'fetch_orders'
  });
}

User-Friendly Messages

function getUserMessage(error) {
  const messages = {
    401: 'Your session has expired. Please log in again.',
    403: 'You don\'t have permission to perform this action.',
    404: 'The requested item was not found.',
    422: 'Please check your input and try again.',
    429: 'Too many requests. Please wait a moment.',
    500: 'Something went wrong. Please try again later.'
  };
  
  return messages[error.status] || 
         'An unexpected error occurred. Please try again.';
}
function notifyUser(message, type = 'error') {
  const notification = {
    error: { color: 'red', icon: '❌' },
    warning: { color: 'orange', icon: '⚠️' },
    info: { color: 'blue', icon: 'ℹ️' }
  }[type];
  
  showToast(`${notification.icon} ${message}`, notification.color);
}

Complete Error Handling System

class APIClient {
  constructor() {
    this.retryHandler = new RetryHandler(3);
    this.logger = new ErrorLogger();
  }
  
  async request(endpoint, options = {}) {
    return this.retryHandler.execute(async () => {
      try {
        const response = await fetch(endpoint, {
          ...options,
          headers: {
            'Access-Token': await this.getToken(),
            'Content-Type': 'application/json',
            ...options.headers
          }
        });
        
        const data = await response.json();
        
        if (!data.status) {
          throw new APIError(
            response.status,
            data.error,
            data.message
          );
        }
        
        return data.data;
        
      } catch (error) {
        this.logger.log(error, {
          endpoint,
          method: options.method || 'GET',
          requestData: options.body
        });
        
        throw error;
      }
    });
  }
  
  async getToken() {
    // Token management logic
    return tokenManager.getValidToken();
  }
}

// Usage
const api = new APIClient();

try {
  const orders = await api.request('/orders/get-current');
  processOrders(orders);
} catch (error) {
  const message = getUserMessage(error);
  notifyUser(message);
}

Monitoring & Alerts

Set up monitoring for:
  • High error rates (> 5%)
  • Repeated 401 errors (auth issues)
  • Frequent 429 errors (rate limiting)
  • 500 errors (server issues)
  • Network timeouts
class ErrorMonitor {
  constructor() {
    this.errorCounts = {};
    this.alertThresholds = {
      401: 3,   // Alert after 3 auth errors
      429: 5,   // Alert after 5 rate limits
      500: 2    // Alert after 2 server errors
    };
  }
  
  recordError(error) {
    const code = error.status;
    this.errorCounts[code] = (this.errorCounts[code] || 0) + 1;
    
    if (this.shouldAlert(code)) {
      this.sendAlert(code, this.errorCounts[code]);
    }
  }
  
  shouldAlert(code) {
    const threshold = this.alertThresholds[code] || 10;
    return this.errorCounts[code] >= threshold;
  }
  
  sendAlert(code, count) {
    console.error(`🚨 ALERT: ${count} errors with code ${code}`);
    // Send to monitoring service
  }
}

Need Help?

Having persistent errors? Contact our support team for assistance.