Documentation Index
Fetch the complete documentation index at: https://developers.lightyshare.com/llms.txt
Use this file to discover all available pages before exploring further.
Proper error handling is essential for building robust integrations with the Lightyshare API. This guide covers all error types and best practices for handling them.
HTTP Status Codes
The Lightyshare API uses standard HTTP status codes to indicate the success or failure of requests:
| Status Code | Description | Meaning |
|---|
| 200 | OK | Request successful |
| 201 | Created | Resource created successfully |
| 400 | Bad Request | Invalid request data |
| 401 | Unauthorized | Missing or invalid authentication |
| 403 | Forbidden | Access denied to resource |
| 404 | Not Found | Resource doesn’t exist |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error |
Most error responses follow this format:
{
"success": false,
"errors": [
{
"field": "field_name",
"code": "ERROR_CODE",
"message": "Human-readable error message"
}
]
}
Authentication Errors (401)
Missing Token
{
"error": "Invalid or missing token"
}
Invalid Token
{
"error": "Invalid or missing token"
}
Handling Authentication Errors
async function handleAuthError(response) {
if (response.status === 401) {
// Token is invalid or expired
console.error('Authentication failed');
// Refresh token or redirect to login
await refreshToken();
// Retry the request
return retryRequest();
}
}
async function refreshToken() {
// Implement token refresh logic
const newToken = await getNewToken();
localStorage.setItem('api_token', newToken);
}
Validation Errors (400)
Missing Required Fields
{
"success": false,
"errors": [
{
"field": "title",
"code": "REQUIRED",
"message": "Title is required"
},
{
"field": "rent",
"code": "REQUIRED",
"message": "Rental price is required"
}
]
}
Invalid Data Types
{
"success": false,
"errors": [
{
"field": "rent",
"code": "INVALID_TYPE",
"message": "Rental price must be a number"
}
]
}
Value Constraints
{
"success": false,
"errors": [
{
"field": "rent",
"code": "MIN_VALUE",
"message": "Rental price must be at least 0.01"
},
{
"field": "quantity",
"code": "MIN_VALUE",
"message": "Quantity must be at least 1"
}
]
}
String Length Limits
{
"success": false,
"errors": [
{
"field": "title",
"code": "MAX_LENGTH",
"message": "Title must be 255 characters or less"
}
]
}
Handling Validation Errors
async function handleValidationErrors(response) {
if (response.status === 400) {
const errorData = await response.json();
if (errorData.errors) {
// Display field-specific errors
errorData.errors.forEach(error => {
displayFieldError(error.field, error.message);
});
} else {
// Display general error
displayGeneralError(errorData.error || 'Validation failed');
}
}
}
function displayFieldError(field, message) {
const fieldElement = document.querySelector(`[name="${field}"]`);
if (fieldElement) {
fieldElement.classList.add('error');
fieldElement.nextElementSibling.textContent = message;
}
}
Access Control Errors (403)
Resource Access Denied
{
"error": "Access denied to this resource"
}
Handling Access Errors
async function handleAccessError(response) {
if (response.status === 403) {
console.error('Access denied to this resource');
// Check if user has proper permissions
await checkUserPermissions();
// Show appropriate message to user
showAccessDeniedMessage();
}
}
Not Found Errors (404)
Resource Not Found
{
"error": "Resource not found"
}
Handling Not Found Errors
async function handleNotFoundError(response) {
if (response.status === 404) {
console.error('Resource not found');
// Show 404 page or message
showNotFoundMessage();
// Optionally redirect to list page
// window.location.href = '/products';
}
}
Rate Limiting Errors (429)
Rate Limit Exceeded
{
"error": "Request limit exceeded"
}
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640995200
Retry-After: 60
Handling Rate Limit Errors
async function handleRateLimitError(response) {
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : 60000;
console.log(`Rate limited. Waiting ${waitTime}ms before retry...`);
// Show user-friendly message
showRateLimitMessage(waitTime);
// Wait and retry
await delay(waitTime);
return retryRequest();
}
}
function showRateLimitMessage(waitTime) {
const seconds = Math.ceil(waitTime / 1000);
const message = `Too many requests. Please wait ${seconds} seconds before trying again.`;
// Display message to user
displayNotification(message, 'warning');
}
Comprehensive Error Handler
Here’s a complete error handling function:
class APIErrorHandler {
constructor() {
this.retryAttempts = 0;
this.maxRetries = 3;
}
async handleResponse(response, requestData = null) {
if (response.ok) {
return await response.json();
}
switch (response.status) {
case 400:
return this.handleValidationError(response);
case 401:
return this.handleAuthError(response);
case 403:
return this.handleAccessError(response);
case 404:
return this.handleNotFoundError(response);
case 429:
return this.handleRateLimitError(response);
case 500:
return this.handleServerError(response);
default:
return this.handleUnknownError(response);
}
}
async handleValidationError(response) {
const errorData = await response.json();
if (errorData.errors) {
const fieldErrors = {};
errorData.errors.forEach(error => {
fieldErrors[error.field] = error.message;
});
throw new ValidationError('Validation failed', fieldErrors);
} else {
throw new APIError('Bad request', errorData.error || 'Invalid request data');
}
}
async handleAuthError(response) {
const errorData = await response.json();
// Clear invalid token
localStorage.removeItem('api_token');
// Redirect to login
window.location.href = '/login';
throw new AuthError('Authentication failed', errorData.error);
}
async handleAccessError(response) {
const errorData = await response.json();
// Show access denied message
this.showNotification('Access denied to this resource', 'error');
throw new AccessError('Access denied', errorData.error);
}
async handleNotFoundError(response) {
const errorData = await response.json();
// Show 404 message
this.showNotification('Resource not found', 'error');
throw new NotFoundError('Resource not found', errorData.error);
}
async handleRateLimitError(response) {
const retryAfter = response.headers.get('Retry-After');
const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : 60000;
if (this.retryAttempts < this.maxRetries) {
this.retryAttempts++;
// Wait and retry
await this.delay(waitTime);
// Retry the request
return this.retryRequest();
} else {
this.showNotification('Rate limit exceeded. Please try again later.', 'error');
throw new RateLimitError('Rate limit exceeded');
}
}
async handleServerError(response) {
this.showNotification('Server error. Please try again later.', 'error');
throw new ServerError('Internal server error');
}
async handleUnknownError(response) {
this.showNotification('An unexpected error occurred.', 'error');
throw new APIError('Unknown error', `HTTP ${response.status}`);
}
showNotification(message, type = 'info') {
// Implement your notification system
console.log(`${type.toUpperCase()}: ${message}`);
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Custom error classes
class APIError extends Error {
constructor(message, details = null) {
super(message);
this.name = 'APIError';
this.details = details;
}
}
class ValidationError extends APIError {
constructor(message, fieldErrors = {}) {
super(message);
this.name = 'ValidationError';
this.fieldErrors = fieldErrors;
}
}
class AuthError extends APIError {
constructor(message, details = null) {
super(message);
this.name = 'AuthError';
this.details = details;
}
}
class AccessError extends APIError {
constructor(message, details = null) {
super(message);
this.name = 'AccessError';
this.details = details;
}
}
class NotFoundError extends APIError {
constructor(message, details = null) {
super(message);
this.name = 'NotFoundError';
this.details = details;
}
}
class RateLimitError extends APIError {
constructor(message, details = null) {
super(message);
this.name = 'RateLimitError';
this.details = details;
}
}
class ServerError extends APIError {
constructor(message, details = null) {
super(message);
this.name = 'ServerError';
this.details = details;
}
}
Usage Example
const errorHandler = new APIErrorHandler();
async function createProduct(productData) {
try {
const response = await fetch('https://lightyshare.com/api/token-secured/product', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ product: productData })
});
const result = await errorHandler.handleResponse(response, productData);
return result;
} catch (error) {
if (error instanceof ValidationError) {
// Handle validation errors
Object.entries(error.fieldErrors).forEach(([field, message]) => {
displayFieldError(field, message);
});
} else if (error instanceof AuthError) {
// Handle authentication errors
console.error('Authentication failed:', error.message);
} else {
// Handle other errors
console.error('API Error:', error.message);
}
throw error;
}
}
Best Practices
1. Always Handle Errors
Never ignore API errors - always implement proper error handling:
// ❌ Don't do this
fetch('/api/product').then(response => response.json());
// ✅ Do this
fetch('/api/product')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
})
.catch(error => {
console.error('Request failed:', error);
handleError(error);
});
2. Provide User Feedback
Always inform users when errors occur:
function showUserFriendlyError(error) {
let message = 'An error occurred. Please try again.';
if (error instanceof ValidationError) {
message = 'Please check your input and try again.';
} else if (error instanceof AuthError) {
message = 'Please log in again.';
} else if (error instanceof RateLimitError) {
message = 'Too many requests. Please wait a moment.';
}
displayNotification(message, 'error');
}
3. Implement Retry Logic
For transient errors, implement retry logic:
async function retryRequest(fn, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (error instanceof RateLimitError && attempt < maxRetries - 1) {
await delay(Math.pow(2, attempt) * 1000);
continue;
}
throw error;
}
}
}
4. Log Errors Appropriately
Log errors for debugging but don’t expose sensitive information:
function logError(error, context = {}) {
const logData = {
timestamp: new Date().toISOString(),
error: error.name,
message: error.message,
context: {
...context,
// Don't log sensitive data like tokens
hasToken: !!context.token
}
};
console.error('API Error:', logData);
// Send to error tracking service
if (process.env.NODE_ENV === 'production') {
sendToErrorTracking(logData);
}
}
5. Graceful Degradation
Design your application to work even when some API calls fail:
async function loadUserData() {
try {
const user = await fetchUser();
const products = await fetchProducts();
return { user, products };
} catch (error) {
// Show partial data if possible
if (error instanceof AuthError) {
return { user: null, products: [] };
}
// Show cached data if available
const cachedData = getCachedData();
if (cachedData) {
return cachedData;
}
throw error;
}
}