import { Request, Response, NextFunction } from 'express';
import { AppError } from '@utils/errors';
import { logger } from '@utils/logger';
import { config } from '@config/index';
/**
* Generate request ID for tracking
*/
const generateRequestId = (): string => {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
};
/**
* Error handling middleware
* Must be the last middleware in the chain
*/
export const errorHandler = (
err: Error,
req: Request,
res: Response,
_next: NextFunction
): void => {
const requestId = (req.headers['x-request-id'] as string) || generateRequestId();
// Log error
logger.error('Error occurred', {
error: err.message,
stack: err.stack,
path: req.path,
method: req.method,
requestId,
userId: (req as any).userId,
});
// Handle known application errors
if (err instanceof AppError) {
res.status(err.statusCode).json({
error: {
code: err.code || 'APPLICATION_ERROR',
message: err.message,
details: err.details,
timestamp: new Date().toISOString(),
request_id: requestId,
},
});
return;
}
// Handle unknown errors
const message =
config.nodeEnv === 'production'
? 'Internal server error'
: err.message;
res.status(500).json({
error: {
code: 'INTERNAL_ERROR',
message,
timestamp: new Date().toISOString(),
request_id: requestId,
...(config.nodeEnv === 'development' && { stack: err.stack }),
},
});
};
/**
* 404 Not Found handler
*/
export const notFoundHandler = (
req: Request,
res: Response,
_next: NextFunction
): void => {
res.status(404).json({
error: {
code: 'NOT_FOUND',
message: 'Resource not found',
path: req.path,
method: req.method,
timestamp: new Date().toISOString(),
},
});
};
/**
* Request ID middleware
* Adds request ID to headers for tracking
*/
export const requestIdMiddleware = (
req: Request,
res: Response,
next: NextFunction
): void => {
const requestId =
(req.headers['x-request-id'] as string) || generateRequestId();
req.headers['x-request-id'] = requestId;
res.setHeader('X-Request-ID', requestId);
next();
};