EcoTracker-II / backend /src /middleware /errorHandler.js
Akash-Dragon's picture
refactor: restructure project as a monorepo and implement backend API
7e49c4d
Raw
History Blame Contribute Delete
2.13 kB
import { ZodError } from 'zod';
import logger from '../utils/logger.js';
/**
* Centralized error handling middleware
* Must be registered LAST in the Express middleware chain
*/
export const errorHandler = (err, req, res, _next) => {
// Log the error
logger.error('Unhandled error', {
message: err.message,
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined,
method: req.method,
url: req.url,
ip: req.ip,
});
// Handle Zod validation errors
if (err instanceof ZodError) {
return res.status(400).json({
success: false,
error: 'Validation failed',
details: err.errors.map((e) => ({
field: e.path.join('.'),
message: e.message,
})),
});
}
// Prisma known errors
if (err.code === 'P2002') {
return res.status(409).json({
success: false,
error: 'A record with this information already exists.',
field: err.meta?.target?.[0],
});
}
if (err.code === 'P2025') {
return res.status(404).json({
success: false,
error: 'Record not found.',
});
}
if (err.code === 'P2003') {
return res.status(400).json({
success: false,
error: 'Invalid reference. The related record does not exist.',
});
}
// Generic HTTP errors
const statusCode = err.statusCode || err.status || 500;
const message =
statusCode < 500 || process.env.NODE_ENV === 'development'
? err.message
: 'An internal server error occurred. Please try again later.';
res.status(statusCode).json({
success: false,
error: message,
...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
});
};
/**
* 404 Not Found handler
*/
export const notFoundHandler = (req, res) => {
res.status(404).json({
success: false,
error: `Route not found: ${req.method} ${req.path}`,
});
};
/**
* Create a custom HTTP error
*/
export class AppError extends Error {
constructor(message, statusCode = 500) {
super(message);
this.statusCode = statusCode;
this.name = 'AppError';
Error.captureStackTrace(this, this.constructor);
}
}