// Error Handler Middleware // Centralizes error handling logic to eliminate duplicate catch blocks const { HTTP_STATUS } = require('./constants'); /** * Async route handler wrapper - 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); }; } /** * Express error middleware - handles all errors consistently */ function errorMiddleware(err, req, res, next) { const logger = req.app.get('logger'); // Log the error with context logger.error('Request error', { error: err.message, stack: err.stack, path: req.path, method: req.method, ip: req.ip, userId: req.user?.id }); // Determine status code const statusCode = err.statusCode || err.status || HTTP_STATUS.INTERNAL_ERROR; // Send consistent error response res.status(statusCode).json({ success: false, error: err.message || 'Internal server error', ...(process.env.NODE_ENV === 'development' && { stack: err.stack }) }); } /** * Custom error classes for specific scenarios */ class ValidationError extends Error { constructor(message) { super(message); this.name = 'ValidationError'; this.statusCode = HTTP_STATUS.BAD_REQUEST; } } class UnauthorizedError extends Error { constructor(message = 'Unauthorized') { super(message); this.name = 'UnauthorizedError'; this.statusCode = HTTP_STATUS.UNAUTHORIZED; } } class NotFoundError extends Error { constructor(message = 'Not found') { super(message); this.name = 'NotFoundError'; this.statusCode = HTTP_STATUS.NOT_FOUND; } } class ConflictError extends Error { constructor(message) { super(message); this.name = 'ConflictError'; this.statusCode = HTTP_STATUS.CONFLICT; } } module.exports = { asyncHandler, errorMiddleware, ValidationError, UnauthorizedError, NotFoundError, ConflictError };