qerrors
Version:
Intelligent error handling middleware with AI-powered analysis, environment validation, caching, and production-ready logging. Provides OpenAI-based error suggestions, queue management, retry mechanisms, and comprehensive configuration options for Node.js
346 lines (321 loc) • 11.5 kB
Plain Text
/**
* Centralized Error Handling Utility
*
* This module provides standardized error handling patterns across the application,
* ensuring consistent error responses, proper logging, and appropriate error
* classification. It implements error handling best practices including:
*
* 1. Standardized error response format for API consistency
* 2. Error classification for appropriate handling strategies
* 3. Context-aware logging for debugging and monitoring
* 4. Request ID tracking for error correlation
* 5. Severity-based error routing and alerting
*
* Design Rationale:
* - Centralizes error handling logic to reduce code duplication
* - Provides consistent user experience across all endpoints
* - Enables comprehensive error monitoring and debugging
* - Supports multiple error handling strategies based on error type
* - Maintains backward compatibility with existing error patterns
*/
const { qerrors } = require('qerrors');
const { sendJsonResponse } = require('./responseUtils');
const { getRequestId } = require('./requestUtils');
/**
* Error type classification for appropriate handling strategies
*
* Rationale: Different error types require different handling approaches.
* This classification enables appropriate response codes, user messages,
* logging levels, and recovery strategies.
*/
const ErrorTypes = {
VALIDATION: 'validation', // User input errors (400)
AUTHENTICATION: 'authentication', // Auth failures (401)
AUTHORIZATION: 'authorization', // Permission errors (403)
NOT_FOUND: 'not_found', // Resource not found (404)
RATE_LIMIT: 'rate_limit', // Rate limiting (429)
NETWORK: 'network', // External service errors (502/503)
DATABASE: 'database', // Database errors (500)
SYSTEM: 'system', // Internal system errors (500)
CONFIGURATION: 'configuration' // Config/setup errors (500)
};
/**
* Error severity levels for logging and alerting
*
* Rationale: Different error severities require different response strategies.
* This classification enables appropriate logging, alerting, and escalation.
*/
const ErrorSeverity = {
LOW: 'low', // Expected errors, user mistakes
MEDIUM: 'medium', // Operational issues, recoverable
HIGH: 'high', // Service degradation, requires attention
CRITICAL: 'critical' // Service disruption, immediate response needed
};
/**
* Maps error types to appropriate HTTP status codes
*
* Rationale: Consistent HTTP status code mapping ensures proper client
* behavior and follows REST API conventions.
*/
const ERROR_STATUS_MAP = {
[ErrorTypes.VALIDATION]: 400,
[ErrorTypes.AUTHENTICATION]: 401,
[ErrorTypes.AUTHORIZATION]: 403,
[ErrorTypes.NOT_FOUND]: 404,
[ErrorTypes.RATE_LIMIT]: 429,
[ErrorTypes.NETWORK]: 502,
[ErrorTypes.DATABASE]: 500,
[ErrorTypes.SYSTEM]: 500,
[ErrorTypes.CONFIGURATION]: 500
};
/**
* Maps error types to severity levels for monitoring
*
* Rationale: Automatic severity classification enables appropriate
* alerting and escalation without manual intervention.
*/
const ERROR_SEVERITY_MAP = {
[ErrorTypes.VALIDATION]: ErrorSeverity.LOW,
[ErrorTypes.AUTHENTICATION]: ErrorSeverity.LOW,
[ErrorTypes.AUTHORIZATION]: ErrorSeverity.MEDIUM,
[ErrorTypes.NOT_FOUND]: ErrorSeverity.LOW,
[ErrorTypes.RATE_LIMIT]: ErrorSeverity.MEDIUM,
[ErrorTypes.NETWORK]: ErrorSeverity.MEDIUM,
[ErrorTypes.DATABASE]: ErrorSeverity.HIGH,
[ErrorTypes.SYSTEM]: ErrorSeverity.HIGH,
[ErrorTypes.CONFIGURATION]: ErrorSeverity.CRITICAL
};
/**
* Creates a standardized error object with consistent format
*
* Rationale: Standardized error format ensures consistent API responses
* and enables proper error handling on the client side. Includes all
* necessary information for debugging and user feedback.
*
* @param {string} code - Error code for programmatic handling
* @param {string} message - Human-readable error message
* @param {string} type - Error type from ErrorTypes enum
* @param {Object} context - Additional context for debugging
* @returns {Object} Standardized error object
*/
function createError(code, message, type, context = {}) { // build standard error object
return {
code,
message,
type,
timestamp: new Date().toISOString(),
requestId: context.requestId || getRequestId(context.req),
context: {
...context,
req: undefined, // Remove req object to prevent circular references
res: undefined // Remove res object to prevent circular references
}
};
}
/**
* Logs error with appropriate severity and context
*
* Rationale: Centralized error logging ensures consistent log format
* and enables proper monitoring and alerting. Different severities
* can be routed to different logging destinations.
*
* @param {Object} error - Error object or Error instance
* @param {string} functionName - Name of function where error occurred
* @param {Object} context - Request context and additional information
* @param {string} severity - Error severity level
*/
function logError(error, functionName, context = {}, severity = ErrorSeverity.MEDIUM) { // log with severity context
const logContext = {
...context,
severity,
timestamp: new Date().toISOString(),
requestId: context.requestId || getRequestId(context.req)
};
// Use existing qerrors for consistent logging
qerrors(error, functionName, logContext);
// Additional logging based on severity
if (severity === ErrorSeverity.CRITICAL) {
console.error(`CRITICAL ERROR in ${functionName}:`, {
error: error.message || error,
context: logContext
});
} else if (severity === ErrorSeverity.HIGH) {
console.error(`HIGH SEVERITY ERROR in ${functionName}:`, {
error: error.message || error,
context: logContext
});
}
}
/**
* Handles controller errors with standardized response
*
* Rationale: Provides consistent error handling across all controllers
* while maintaining existing responseUtils integration. Automatically
* determines appropriate status codes and response format.
*
* @param {Object} res - Express response object
* @param {Object} error - Error object or Error instance
* @param {string} functionName - Name of function where error occurred
* @param {Object} context - Request context
* @param {string} userMessage - Optional user-friendly message override
*/
function handleControllerError(res, error, functionName, context = {}, userMessage = null) { // send standardized error response
const errorType = error.type || ErrorTypes.SYSTEM;
const severity = ERROR_SEVERITY_MAP[errorType];
const statusCode = ERROR_STATUS_MAP[errorType];
// Log the error with appropriate severity
logError(error, functionName, context, severity);
// Create standardized error response
const errorResponse = createError(
error.code || 'INTERNAL_ERROR',
userMessage || error.message || 'An internal error occurred',
errorType,
context
);
// Send standardized JSON response
sendJsonResponse(res, statusCode, { error: errorResponse });
}
/**
* Wraps async operations with standardized error handling
*
* Rationale: Reduces boilerplate code in controllers while ensuring
* consistent error handling. Automatically catches and handles errors
* according to their type and severity.
*
* @param {Function} operation - Async operation to execute
* @param {string} functionName - Name for logging purposes
* @param {Object} context - Request context
* @param {*} fallback - Fallback value on error (optional)
* @returns {*} Operation result or fallback value
*/
async function withErrorHandling(operation, functionName, context = {}, fallback = null) { // execute operation with safety net
try {
const result = await operation();
console.log(`${functionName} is returning result`);
return result;
} catch (error) {
logError(error, functionName, context);
return fallback;
}
}
/**
* Creates specific error types with predefined configurations
*
* Rationale: Provides convenient error creation functions for common
* error scenarios, ensuring consistent error codes and messages.
*/
const ErrorFactory = {
/**
* Creates validation error for user input issues
*/
validation(message, field = null, context = {}) {
return createError(
'VALIDATION_ERROR',
message,
ErrorTypes.VALIDATION,
{ ...context, field }
);
},
/**
* Creates authentication error for login/auth issues
*/
authentication(message = 'Authentication required', context = {}) {
return createError(
'AUTHENTICATION_ERROR',
message,
ErrorTypes.AUTHENTICATION,
context
);
},
/**
* Creates authorization error for permission issues
*/
authorization(message = 'Insufficient permissions', context = {}) {
return createError(
'AUTHORIZATION_ERROR',
message,
ErrorTypes.AUTHORIZATION,
context
);
},
/**
* Creates not found error for missing resources
*/
notFound(resource, context = {}) {
return createError(
'NOT_FOUND',
`${resource} not found`,
ErrorTypes.NOT_FOUND,
context
);
},
/**
* Creates rate limit error for quota violations
*/
rateLimit(message = 'Rate limit exceeded', context = {}) {
return createError(
'RATE_LIMIT_EXCEEDED',
message,
ErrorTypes.RATE_LIMIT,
context
);
},
/**
* Creates network error for external service issues
*/
network(message, service = null, context = {}) {
return createError(
'NETWORK_ERROR',
message,
ErrorTypes.NETWORK,
{ ...context, service }
);
},
/**
* Creates database error for data persistence issues
*/
database(message, operation = null, context = {}) {
return createError(
'DATABASE_ERROR',
message,
ErrorTypes.DATABASE,
{ ...context, operation }
);
},
/**
* Creates system error for internal issues
*/
system(message, component = null, context = {}) {
return createError(
'SYSTEM_ERROR',
message,
ErrorTypes.SYSTEM,
{ ...context, component }
);
}
};
/**
* Middleware for global error handling
*
* Rationale: Catches any unhandled errors in the Express middleware chain
* and ensures they are properly logged and responded to with consistent format.
*/
function errorMiddleware(error, req, res, next) {
const context = {
req,
url: req.url,
method: req.method,
ip: req.ip
};
handleControllerError(res, error, 'errorMiddleware', context);
}
module.exports = {
ErrorTypes,
ErrorSeverity,
createError,
logError,
handleControllerError,
withErrorHandling,
ErrorFactory,
errorMiddleware
};