Files
Zumri-Backend/app/middleware/error.middleware.js
Sathira Sri Sathara 267e80e2ec feat: stabilize API startup and lifecycle management
- Refactor server initialization to separate concerns and improve error handling.
- Implement centralized environment validation using Zod.
- Introduce database, Redis, and queue lifecycle management.
- Add health check endpoints for liveness and readiness.
- Enhance error handling middleware for better response structure.
- Implement rate limiting for API endpoints.
- Add request ID middleware for traceability.
- Create Sequelize CLI configuration and baseline migration for schema management.
- Establish CI workflow with Gitea for testing and syntax checks.
- Document foundational changes and migration strategy in PHASE_0_FOUNDATION_STABILIZATION.md.
- Add Docker Compose configuration for local development and testing.
- Implement unit and integration tests for critical functionality.
2026-09-03 13:33:26 +05:30

47 lines
2.1 KiB
JavaScript

const { ValidationError, UniqueConstraintError } = require("sequelize");
const { ZodError } = require("zod");
class AppError extends Error {
constructor(status, code, message, details) {
super(message);
this.status = status;
this.code = code;
this.details = details;
}
}
const notFound = (req, _res, next) => next(new AppError(404, "NOT_FOUND", "Route not found"));
const errorHandler = (error, req, res, _next) => {
let status = error.status || error.statusCode || 500;
let code = error.code || "INTERNAL_ERROR";
let message = error.message || "An unexpected error occurred";
let details = error.details;
if (error instanceof ZodError) {
status = 400; code = "VALIDATION_ERROR"; message = "Invalid request data";
details = error.issues.map(({ path, message: detailMessage }) => ({ field: path.join("."), message: detailMessage }));
} else if (error instanceof UniqueConstraintError) {
status = 409; code = "CONFLICT"; message = "A record with these values already exists";
details = error.errors?.map(({ path, message: detailMessage }) => ({ field: path, message: detailMessage }));
} else if (error instanceof ValidationError) {
status = 400; code = "VALIDATION_ERROR"; message = "Invalid request data";
details = error.errors?.map(({ path, message: detailMessage }) => ({ field: path, message: detailMessage }));
} else if (error.type === "entity.too.large") {
status = 413; code = "PAYLOAD_TOO_LARGE"; message = "Request body is too large";
} else if (error.name === "UnauthorizedError" || error.name === "JsonWebTokenError") {
status = 401; code = "UNAUTHORIZED"; message = "Authentication failed";
}
if (status >= 500) {
console.error(`[${req.id || "no-request-id"}] Request failed`, { name: error.name, message: error.message });
if (process.env.NODE_ENV === "production") message = "An unexpected error occurred";
}
const payload = { success: false, error: { code, message }, requestId: req.id };
if (details && status < 500) payload.error.details = details;
res.status(status).json(payload);
};
module.exports = { AppError, notFound, errorHandler };