Appearance
REST API - Error Handling
Comprehensive guide to understanding and handling API errors, including error codes, messages, and best practices.
📋 Table of Contents
- Overview
- Error Response Format
- HTTP Status Codes
- Common Error Scenarios
- Validation Errors
- Error Handling Examples
- Best Practices
- Troubleshooting
Overview
The HelpDesk Pro API uses standard HTTP status codes and provides detailed error messages to help you understand and resolve issues quickly.
Error Response Structure
All error responses follow a consistent format:
json
{
"success": false,
"message": "Error description",
"errors": {
"field_name": ["Error message for this field"]
},
"meta": {
"timestamp": "2025-01-15T10:30:00.000000Z",
"version": "v1"
}
}Error Response Format
Standard Error Response
json
{
"success": false,
"message": "The given data was invalid.",
"errors": {
"email": ["The email field is required."],
"password": ["The password must be at least 8 characters."]
},
"meta": {
"timestamp": "2025-01-15T10:30:00.000000Z",
"version": "v1"
}
}Simple Error Response
For errors without field-specific issues:
json
{
"success": false,
"message": "Resource not found",
"meta": {
"timestamp": "2025-01-15T10:30:00.000000Z",
"version": "v1"
}
}HTTP Status Codes
2xx Success
| Code | Meaning | Description |
|---|---|---|
| 200 | OK | Request successful |
| 201 | Created | Resource created successfully |
| 204 | No Content | Request successful, no content to return |
4xx Client Errors
| Code | Meaning | Description |
|---|---|---|
| 400 | Bad Request | Invalid request format or parameters |
| 401 | Unauthorized | Authentication required or token invalid |
| 403 | Forbidden | User lacks permission for this resource |
| 404 | Not Found | Requested resource doesn't exist |
| 422 | Unprocessable Entity | Validation failed |
| 429 | Too Many Requests | Rate limit exceeded |
5xx Server Errors
| Code | Meaning | Description |
|---|---|---|
| 500 | Internal Server Error | Unexpected server error |
| 503 | Service Unavailable | Service temporarily unavailable |
Common Error Scenarios
401 Unauthorized
Cause: Missing or invalid authentication token.
Response:
json
{
"success": false,
"message": "Unauthenticated",
"meta": {
"timestamp": "2025-01-15T10:30:00.000000Z",
"version": "v1"
}
}Solution:
- Verify token is included in
Authorizationheader - Check token format:
Bearer {token} - Re-authenticate to get a new token
- Ensure token hasn't been revoked
Example Handling:
javascript
if (response.status === 401) {
// Clear stored token
localStorage.removeItem('api_token');
// Redirect to login
window.location.href = '/login';
}403 Forbidden
Cause: User doesn't have permission to access the resource.
Response:
json
{
"success": false,
"message": "This action is unauthorized.",
"meta": {
"timestamp": "2025-01-15T10:30:00.000000Z",
"version": "v1"
}
}Solution:
- Verify user role has required permissions
- Check resource ownership (for user-specific resources)
- Contact administrator for permission changes
Example Handling:
javascript
if (response.status === 403) {
showError('You do not have permission to perform this action.');
}404 Not Found
Cause: Requested resource doesn't exist.
Response:
json
{
"success": false,
"message": "Ticket not found",
"meta": {
"timestamp": "2025-01-15T10:30:00.000000Z",
"version": "v1"
}
}Solution:
- Verify resource ID is correct
- Check if resource was deleted
- Ensure you're using the correct endpoint
Example Handling:
javascript
if (response.status === 404) {
showError('The requested resource was not found.');
}422 Validation Error
Cause: Request data failed validation.
Response:
json
{
"success": false,
"message": "The given data was invalid.",
"errors": {
"email": [
"The email field is required.",
"The email must be a valid email address."
],
"password": [
"The password must be at least 8 characters.",
"The password confirmation does not match."
]
},
"meta": {
"timestamp": "2025-01-15T10:30:00.000000Z",
"version": "v1"
}
}Solution:
- Review error messages for each field
- Ensure all required fields are provided
- Verify data types match expected format
- Check field-specific validation rules
Example Handling:
javascript
if (response.status === 422) {
const errors = response.data.errors;
// Display field-specific errors
Object.keys(errors).forEach(field => {
showFieldError(field, errors[field][0]);
});
}429 Too Many Requests
Cause: Rate limit exceeded.
Response Headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
Retry-After: 15Response:
json
{
"success": false,
"message": "Too Many Requests",
"meta": {
"timestamp": "2025-01-15T10:30:00.000000Z",
"version": "v1"
}
}Solution:
- Wait for rate limit window to reset
- Check
Retry-Afterheader for wait time - Implement request throttling
- Reduce request frequency
Example Handling:
javascript
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
const waitTime = parseInt(retryAfter) * 1000;
setTimeout(() => {
// Retry request
retryRequest();
}, waitTime);
}500 Internal Server Error
Cause: Unexpected server error.
Response:
json
{
"success": false,
"message": "Internal server error",
"meta": {
"timestamp": "2025-01-15T10:30:00.000000Z",
"version": "v1"
}
}Solution:
- Retry request after a short delay
- Check API status page
- Contact support if issue persists
- Report the error with request details
Validation Errors
Validation errors provide detailed information about what went wrong with your request data.
Field-Level Errors
Each field can have multiple error messages:
json
{
"errors": {
"email": [
"The email field is required.",
"The email must be a valid email address."
],
"password": [
"The password must be at least 8 characters."
]
}
}Common Validation Rules
| Field | Rules | Example Error |
|---|---|---|
email | required, email format | "The email must be a valid email address." |
password | required, min:8 | "The password must be at least 8 characters." |
subject | required, max:255 | "The subject may not be greater than 255 characters." |
priority_id | exists in priorities table | "The selected priority id is invalid." |
status_id | exists in status table | "The selected status id is invalid." |
Handling Validation Errors
JavaScript Example:
javascript
function handleValidationErrors(errors) {
const errorMessages = {};
Object.keys(errors).forEach(field => {
errorMessages[field] = errors[field][0]; // Get first error message
});
return errorMessages;
}
// Usage
try {
const response = await api.createTicket(ticketData);
} catch (error) {
if (error.response?.status === 422) {
const fieldErrors = handleValidationErrors(error.response.data.errors);
// Display errors in form
displayFormErrors(fieldErrors);
}
}React Example:
jsx
const [errors, setErrors] = useState({});
const handleSubmit = async (formData) => {
try {
await api.createTicket(formData);
setErrors({});
} catch (error) {
if (error.response?.status === 422) {
const fieldErrors = {};
Object.keys(error.response.data.errors).forEach(field => {
fieldErrors[field] = error.response.data.errors[field][0];
});
setErrors(fieldErrors);
}
}
};
// In JSX
{errors.email && <div className="error">{errors.email}</div>}Error Handling Examples
JavaScript/TypeScript
javascript
class APIError extends Error {
constructor(message, status, errors = {}) {
super(message);
this.name = 'APIError';
this.status = status;
this.errors = errors;
}
}
async function handleAPIRequest(requestFn) {
try {
const response = await requestFn();
return response.data;
} catch (error) {
if (error.response) {
// Server responded with error
const { status, data } = error.response;
switch (status) {
case 401:
// Unauthorized
localStorage.removeItem('api_token');
window.location.href = '/login';
throw new APIError('Please log in again', 401);
case 403:
// Forbidden
throw new APIError('You do not have permission', 403);
case 404:
// Not Found
throw new APIError(data.message || 'Resource not found', 404);
case 422:
// Validation Error
throw new APIError(
data.message || 'Validation failed',
422,
data.errors || {}
);
case 429:
// Rate Limited
const retryAfter = error.response.headers['retry-after'];
throw new APIError(
`Rate limit exceeded. Retry after ${retryAfter} seconds`,
429
);
default:
throw new APIError(
data.message || 'An error occurred',
status
);
}
} else if (error.request) {
// Request made but no response
throw new APIError('Network error. Please check your connection.', 0);
} else {
// Error setting up request
throw new APIError('Request setup error', 0);
}
}
}
// Usage
try {
const tickets = await handleAPIRequest(() =>
api.get('/tickets')
);
} catch (error) {
if (error instanceof APIError) {
console.error(`API Error (${error.status}):`, error.message);
if (error.errors) {
console.error('Field errors:', error.errors);
}
}
}PHP
php
class APIException extends Exception {
public $statusCode;
public $errors;
public function __construct($message, $statusCode = 400, $errors = []) {
parent::__construct($message);
$this->statusCode = $statusCode;
$this->errors = $errors;
}
}
function handleAPIRequest($requestFn) {
try {
$response = $requestFn();
return $response;
} catch (Exception $e) {
if ($e instanceof APIException) {
throw $e;
}
// Handle HTTP errors
if (method_exists($e, 'getResponse')) {
$response = $e->getResponse();
$statusCode = $response->getStatusCode();
$data = json_decode($response->getBody(), true);
switch ($statusCode) {
case 401:
// Unauthorized
throw new APIException('Please log in again', 401);
case 403:
// Forbidden
throw new APIException('You do not have permission', 403);
case 404:
// Not Found
throw new APIException(
$data['message'] ?? 'Resource not found',
404
);
case 422:
// Validation Error
throw new APIException(
$data['message'] ?? 'Validation failed',
422,
$data['errors'] ?? []
);
default:
throw new APIException(
$data['message'] ?? 'An error occurred',
$statusCode
);
}
}
throw new APIException('Network error', 0);
}
}Python
python
class APIError(Exception):
def __init__(self, message, status_code=400, errors=None):
self.message = message
self.status_code = status_code
self.errors = errors or {}
super().__init__(self.message)
def handle_api_request(request_fn):
try:
response = request_fn()
return response.json()
except requests.exceptions.HTTPError as e:
status_code = e.response.status_code
data = e.response.json()
if status_code == 401:
# Unauthorized
raise APIError('Please log in again', 401)
elif status_code == 403:
# Forbidden
raise APIError('You do not have permission', 403)
elif status_code == 404:
# Not Found
raise APIError(
data.get('message', 'Resource not found'),
404
)
elif status_code == 422:
# Validation Error
raise APIError(
data.get('message', 'Validation failed'),
422,
data.get('errors', {})
)
elif status_code == 429:
# Rate Limited
retry_after = e.response.headers.get('Retry-After', '60')
raise APIError(
f'Rate limit exceeded. Retry after {retry_after} seconds',
429
)
else:
raise APIError(
data.get('message', 'An error occurred'),
status_code
)
except requests.exceptions.RequestException as e:
raise APIError('Network error', 0)Best Practices
1. Always Check Response Status
javascript
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}2. Provide User-Friendly Messages
javascript
const errorMessages = {
401: 'Please log in to continue',
403: 'You do not have permission for 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: 'Server error. Please try again later',
};
function getUserFriendlyMessage(statusCode) {
return errorMessages[statusCode] || 'An error occurred';
}3. Log Errors for Debugging
javascript
function logError(error, context) {
console.error('API Error:', {
message: error.message,
status: error.status,
context: context,
timestamp: new Date().toISOString(),
});
// Send to error tracking service
// errorTrackingService.log(error, context);
}4. Implement Retry Logic
javascript
async function requestWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
if (response.ok) return response;
// Don't retry client errors (4xx)
if (response.status >= 400 && response.status < 500) {
throw new Error(`Client error: ${response.status}`);
}
// Retry server errors (5xx)
if (i < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
continue;
}
throw new Error(`Server error: ${response.status}`);
} catch (error) {
if (i === maxRetries - 1) throw error;
}
}
}Troubleshooting
Common Issues
"Unauthenticated" Error
Problem: Token is missing or invalid.
Solution:
- Verify token is included in Authorization header
- Check token format:
Bearer {token} - Re-authenticate to get a new token
"Validation Failed" Error
Problem: Request data doesn't meet validation requirements.
Solution:
- Check error messages for each field
- Verify required fields are provided
- Ensure data types are correct
- Review validation rules in documentation
"Too Many Requests" Error
Problem: Rate limit exceeded.
Solution:
- Wait for rate limit window to reset
- Check
Retry-Afterheader - Implement request throttling
- Reduce request frequency
Network Errors
Problem: Request fails before reaching server.
Solution:
- Check internet connection
- Verify API base URL is correct
- Check firewall/proxy settings
- Test with cURL to isolate issue
Next Steps
- Code Examples - See error handling in action
- Rate Limiting - Understand API limits
- Authentication - Handle auth errors
For additional support with error handling, contact our API support team.