errorHandler.js•3.32 kB
/**
* Global error handling middleware
* Catches all errors and formats responses
*/
const { formatError } = require('../utils/responseFormatter');
const logger = require('../utils/logger');
const config = require('../config');
/**
* Handle MongoDB duplicate key errors
* @param {Error} err - MongoDB error
* @returns {Object} - Formatted error
*/
const handleDuplicateKeyError = (err) => {
const field = Object.keys(err.keyValue)[0];
const value = err.keyValue[field];
const message = `Duplicate field value: ${value}. Please use another value for ${field}.`;
return formatError(message, 400);
};
/**
* Handle MongoDB validation errors
* @param {Error} err - MongoDB validation error
* @returns {Object} - Formatted error
*/
const handleValidationError = (err) => {
const errors = Object.values(err.errors).map(val => val.message);
const message = `Invalid input data: ${errors.join('. ')}`;
return formatError(message, 400, err.errors);
};
/**
* Handle JWT errors
* @param {Error} err - JWT error
* @returns {Object} - Formatted error
*/
const handleJWTError = () => {
return formatError('Invalid token. Please log in again.', 401);
};
/**
* Handle JWT expired error
* @returns {Object} - Formatted error
*/
const handleJWTExpiredError = () => {
return formatError('Your token has expired. Please log in again.', 401);
};
/**
* Handle Facebook API errors
* @param {Error} err - Facebook API error
* @returns {Object} - Formatted error
*/
const handleFacebookApiError = (err) => {
let message = 'Facebook API error';
let statusCode = 500;
// Check for specific Facebook error codes
if (err.fbErrorCode) {
switch (err.fbErrorCode) {
case 190:
message = 'Facebook session expired. Please log in again.';
statusCode = 401;
break;
case 4:
case 17:
case 341:
message = 'Rate limit exceeded. Please try again later.';
statusCode = 429;
break;
case 200:
case 294:
message = 'Permission error. The app does not have the required permissions.';
statusCode = 403;
break;
default:
message = `Facebook API error: ${err.message}`;
}
}
return formatError(message, statusCode);
};
/**
* Global error handler middleware
*/
module.exports = (err, req, res, next) => {
// Log error
logger.error(`Error: ${err.message}`);
logger.debug(err.stack);
// Default error
let formattedError = formatError(
err.message || 'Something went wrong',
err.statusCode || 500,
err.errors
);
// Handle specific error types
if (err.name === 'ValidationError') {
formattedError = handleValidationError(err);
} else if (err.code === 11000) {
formattedError = handleDuplicateKeyError(err);
} else if (err.name === 'JsonWebTokenError') {
formattedError = handleJWTError();
} else if (err.name === 'TokenExpiredError') {
formattedError = handleJWTExpiredError();
} else if (err.name === 'FacebookApiError') {
formattedError = handleFacebookApiError(err);
}
// Send error response
// In development, include the stack trace
if (config.NODE_ENV === 'development' && err.stack) {
formattedError.stack = err.stack;
}
res.status(formattedError.statusCode).json(formattedError);
};