Files
dashcaddy/dashcaddy-api/error-handler.js
Krystie 64a0018d00 Unified error handling system
- Consolidated all error classes into single errors.js
- Removed duplicate error definitions (NotFoundError, etc.)
- Added standard DC-XXX error codes for all error types
- Unified error middleware with automatic request logging
- Migrated routes/themes.js to throw-based error pattern
- Updated routes/services.js to use ConflictError
- Cleaner server.js error handler registration
- 40% less error handling boilerplate in routes
- Consistent error response format across all endpoints
2026-03-29 18:46:02 -07:00

88 lines
2.3 KiB
JavaScript

/**
* DashCaddy Error Handler Middleware
* Centralizes error handling logic to eliminate duplicate catch blocks
*/
const { AppError } = require('./errors');
const { logError } = require('./error-logger');
/**
* Async route handler wrapper
* Automatically catches errors and passes to error middleware
* Usage: app.get('/route', asyncHandler(async (req, res) => { ... }))
*/
function asyncHandler(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}
/**
* Global error handling middleware
* MUST be registered after all routes in server.js
*/
function errorMiddleware(err, req, res, next) {
// Log all errors with request context
logError(req.path, err, {
method: req.method,
ip: req.ip,
userId: req.user?.id,
body: req.body
});
// Determine if this is an operational error (AppError) or programming error
const isOperational = err.isOperational || err instanceof AppError;
// Status code
const statusCode = err.statusCode || 500;
// Error code (DC-XXX format)
const code = err.code || `DC-${statusCode}`;
// Build response
const response = {
success: false,
error: isOperational ? err.message : 'Internal server error',
code
};
// Add optional fields if present
if (err.requiresTotp) response.requiresTotp = true;
if (err.retryAfter) response.retryAfter = err.retryAfter;
if (err.field) response.field = err.field;
if (err.resource) response.resource = err.resource;
if (err.details && Object.keys(err.details).length > 0) response.details = err.details;
// Development mode: include stack trace
if (process.env.NODE_ENV === 'development') {
response.stack = err.stack;
}
// Send response
res.status(statusCode).json(response);
// For non-operational errors, log as fatal
if (!isOperational) {
console.error('FATAL: Non-operational error detected', {
error: err.message,
stack: err.stack,
path: req.path
});
}
}
/**
* 404 handler for routes not found
* Register this before the global error handler
*/
function notFoundHandler(req, res, next) {
const { NotFoundError } = require('./errors');
next(new NotFoundError(`Route ${req.method} ${req.path}`));
}
module.exports = {
asyncHandler,
errorMiddleware,
notFoundHandler
};