Configuration: - app.config.js: Centralized configuration (ports, MongoDB, JWT, features) - Feature flags for AI curation, media triage, case submissions Middleware: - auth.middleware.js: JWT authentication, role-based access control - validation.middleware.js: Input validation, sanitization, ObjectId checks - error.middleware.js: Global error handling, async wrapper, 404 handler Express Server (src/server.js): - Security: Helmet, CORS, rate limiting - Request logging with Winston - Health check endpoint - MongoDB connection with graceful shutdown - Static file serving - Temporary homepage showing development status Features: - Production-ready error handling - MongoDB duplicate key detection - JWT token validation - XSS protection via sanitization - Rate limiting (100 req / 15min per IP) - Graceful shutdown (SIGTERM/SIGINT) Status: Server foundation complete, ready for API routes Port: 9000 Database: tractatus_dev (MongoDB 27017)
92 lines
2 KiB
JavaScript
92 lines
2 KiB
JavaScript
/**
|
|
* Error Handling Middleware
|
|
*/
|
|
|
|
const logger = require('../utils/logger.util');
|
|
|
|
/**
|
|
* 404 Not Found handler
|
|
*/
|
|
function notFound(req, res, next) {
|
|
res.status(404).json({
|
|
error: 'Not Found',
|
|
message: `Route ${req.method} ${req.originalUrl} not found`
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Global error handler
|
|
*/
|
|
function errorHandler(err, req, res, next) {
|
|
// Log error
|
|
logger.error('Error:', {
|
|
message: err.message,
|
|
stack: err.stack,
|
|
url: req.originalUrl,
|
|
method: req.method,
|
|
ip: req.ip
|
|
});
|
|
|
|
// Determine status code
|
|
const statusCode = err.statusCode || err.status || 500;
|
|
|
|
// MongoDB errors
|
|
if (err.name === 'MongoError' || err.name === 'MongoServerError') {
|
|
if (err.code === 11000) {
|
|
// Duplicate key error
|
|
return res.status(409).json({
|
|
error: 'Duplicate Entry',
|
|
message: 'A resource with this value already exists'
|
|
});
|
|
}
|
|
}
|
|
|
|
// Validation errors
|
|
if (err.name === 'ValidationError') {
|
|
return res.status(400).json({
|
|
error: 'Validation Error',
|
|
message: err.message,
|
|
details: err.errors
|
|
});
|
|
}
|
|
|
|
// JWT errors
|
|
if (err.name === 'JsonWebTokenError') {
|
|
return res.status(401).json({
|
|
error: 'Invalid Token',
|
|
message: 'Authentication token is invalid'
|
|
});
|
|
}
|
|
|
|
if (err.name === 'TokenExpiredError') {
|
|
return res.status(401).json({
|
|
error: 'Token Expired',
|
|
message: 'Authentication token has expired'
|
|
});
|
|
}
|
|
|
|
// Generic error response
|
|
res.status(statusCode).json({
|
|
error: err.name || 'Internal Server Error',
|
|
message: process.env.NODE_ENV === 'production'
|
|
? 'An error occurred processing your request'
|
|
: err.message,
|
|
...(process.env.NODE_ENV !== 'production' && { stack: err.stack })
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Async error wrapper
|
|
* Wraps async route handlers to catch errors
|
|
*/
|
|
function asyncHandler(fn) {
|
|
return (req, res, next) => {
|
|
Promise.resolve(fn(req, res, next)).catch(next);
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
notFound,
|
|
errorHandler,
|
|
asyncHandler
|
|
};
|