Understanding and handling errors effectively is crucial for building robust integrations with the InChurch API. This guide covers error response formats, common error scenarios, and best practices for error handling.
Error Response Format
The InChurch API uses standard HTTP status codes and returns detailed error information in a consistent JSON format:
Code
{ "error": { "code": "VALIDATION_ERROR", "message": "The given data was invalid.", "details": { "email": ["The email field is required."], "phone": ["The phone field must be a valid phone number."] } }}
Error Object Structure
Field
Type
Description
code
string
Machine-readable error code for programmatic handling
message
string
Human-readable error description
details
object
Additional error information (optional)
HTTP Status Codes
4xx Client Errors
Status Code
Error Code
Description
400
VALIDATION_ERROR
Request data validation failed
400
INVALID_REQUEST
Request format or structure is invalid
401
UNAUTHORIZED
Missing or invalid authentication credentials
403
FORBIDDEN
Valid credentials but insufficient permissions
404
NOT_FOUND
Requested resource does not exist
409
CONFLICT
Resource conflict (duplicate data, etc.)
422
UNPROCESSABLE_ENTITY
Valid request but business logic error
429
RATE_LIMITED
Too many requests (rate limit exceeded)
5xx Server Errors
Status Code
Error Code
Description
500
INTERNAL_ERROR
Unexpected server error
502
BAD_GATEWAY
Gateway or proxy error
503
SERVICE_UNAVAILABLE
Service temporarily unavailable
504
GATEWAY_TIMEOUT
Request timeout
Common Error Scenarios
Authentication Errors
Invalid API Credentials
Code
HTTP/1.1 401 Unauthorized
Code
{ "error": { "code": "UNAUTHORIZED", "message": "Invalid API credentials", "details": { "reason": "API key not found or API secret mismatch" } }}
Insufficient Permissions
Code
HTTP/1.1 403 Forbidden
Code
{ "error": { "code": "FORBIDDEN", "message": "Insufficient permissions for this resource", "details": { "required_scope": "people:write", "current_scopes": ["people:read", "donations:read"] } }}
Validation Errors
Missing Required Fields
Code
HTTP/1.1 400 Bad Request
Code
{ "error": { "code": "VALIDATION_ERROR", "message": "The given data was invalid.", "details": { "full_name": ["The full name field is required."], "email": ["The email field is required."] } }}
Invalid Data Format
Code
HTTP/1.1 400 Bad Request
Code
{ "error": { "code": "VALIDATION_ERROR", "message": "The given data was invalid.", "details": { "email": ["The email must be a valid email address."], "birthday": ["The birthday must be a valid date in YYYY-MM-DD format."], "mobile_phone": ["The mobile phone must be a valid phone number."] } }}
Always check the HTTP status code before processing the response:
Code
async function handleApiResponse(response) { if (!response.ok) { const errorData = await response.json(); switch (response.status) { case 400: throw new ValidationError(errorData.error); case 401: throw new AuthenticationError(errorData.error); case 403: throw new PermissionError(errorData.error); case 404: throw new NotFoundError(errorData.error); case 429: throw new RateLimitError(errorData.error, response.headers.get('Retry-After')); case 500: throw new ServerError(errorData.error); default: throw new ApiError(errorData.error, response.status); } } return response.json();}
Handle transient errors with appropriate retry strategies:
Code
async function apiRequestWithRetry(url, options, maxRetries = 3) { for (let attempt = 0; attempt <= maxRetries; attempt++) { try { const response = await fetch(url, options); return await handleApiResponse(response); } catch (error) { // Don't retry on client errors (4xx except 429) if (error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) { throw error; } // On last attempt, throw the error if (attempt === maxRetries) { throw error; } // Calculate delay let delay = Math.pow(2, attempt) * 1000; // Exponential backoff if (error instanceof RateLimitError) { delay = error.retryAfter * 1000; } console.log(`Request failed, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`); await new Promise(resolve => setTimeout(resolve, delay)); } }}
Code
import timeimport randomdef api_request_with_retry(url, max_retries=3, **kwargs): for attempt in range(max_retries + 1): try: response = requests.get(url, **kwargs) return handle_api_response(response) except ApiError as error: # Don't retry client errors (except rate limiting) if 400 <= error.status_code < 500 and error.status_code != 429: raise error # On last attempt, raise the error if attempt == max_retries: raise error # Calculate delay if isinstance(error, RateLimitError): delay = error.retry_after else: delay = (2 ** attempt) + random.uniform(0, 1) print(f"Request failed, retrying in {delay}s (attempt {attempt + 1}/{max_retries})") time.sleep(delay)
4. Log Errors Appropriately
Log errors with appropriate detail levels:
Code
function logApiError(error, context = {}) { const logData = { timestamp: new Date().toISOString(), error_type: error.name, error_code: error.code, message: error.message, status_code: error.statusCode, context: context }; // Log validation errors as warnings if (error instanceof ValidationError) { console.warn('Validation error:', logData); } // Log authentication/permission errors as warnings else if (error instanceof AuthenticationError || error instanceof PermissionError) { console.warn('Access error:', logData); } // Log server errors as errors else if (error.statusCode >= 500) { console.error('Server error:', logData); } // Log other errors as info else { console.info('API error:', logData); }}
5. User-Friendly Error Messages
Convert technical errors to user-friendly messages:
Code
function getErrorMessage(error) { const errorMessages = { 'VALIDATION_ERROR': 'Please check your input and try again.', 'UNAUTHORIZED': 'Authentication failed. Please check your credentials.', 'FORBIDDEN': 'You don\'t have permission to perform this action.', 'NOT_FOUND': 'The requested resource was not found.', 'RATE_LIMITED': 'Too many requests. Please wait a moment and try again.', 'INTERNAL_ERROR': 'Something went wrong on our end. Please try again later.' }; return errorMessages[error.code] || 'An unexpected error occurred.';}// Usage in UItry { const result = await createPerson(personData); showSuccess('Person created successfully!');} catch (error) { if (error instanceof ValidationError) { showValidationErrors(error.validationErrors); } else { showError(getErrorMessage(error)); }}
Error Monitoring & Alerting
Track Error Patterns
Monitor error rates and patterns to identify issues: