From 76a42e09f23cd6eec69e91d37e8c4a4f20b3488e Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Bajpai <157192462+saurabhhhcodes@users.noreply.github.com> Date: Thu, 28 May 2026 06:05:53 +0530 Subject: [PATCH] fix: add centralized backend error handling --- backend/middleware/errorHandler.js | 30 ++++++++++++++++++++++++++++++ backend/routes/message.routes.js | 23 ++++++++++++++++------- backend/routes/user.routes.js | 27 ++++++++++++++++----------- backend/server.js | 6 +++++- 4 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 backend/middleware/errorHandler.js diff --git a/backend/middleware/errorHandler.js b/backend/middleware/errorHandler.js new file mode 100644 index 0000000..880d2fa --- /dev/null +++ b/backend/middleware/errorHandler.js @@ -0,0 +1,30 @@ +export const asyncHandler = (handler) => (req, res, next) => { + Promise.resolve(handler(req, res, next)).catch(next) +} + +export const notFoundHandler = (req, res, next) => { + if (res.headersSent) return next() + + res.status(404).json({ + message: `Route not found: ${req.method} ${req.originalUrl}`, + }) +} + +export const globalErrorHandler = (err, req, res, next) => { + if (res.headersSent) return next(err) + + const statusCode = err.statusCode || err.status || 500 + const isServerError = statusCode >= 500 + + if (isServerError) { + console.error("Unhandled API error:", err) + } + + res.status(statusCode).json({ + message: isServerError ? "Internal server error." : err.message, + ...(process.env.NODE_ENV === "development" && { + error: err.message, + stack: err.stack, + }), + }) +} diff --git a/backend/routes/message.routes.js b/backend/routes/message.routes.js index 5103314..97d1cb8 100644 --- a/backend/routes/message.routes.js +++ b/backend/routes/message.routes.js @@ -1,5 +1,6 @@ import express from "express" import { protectRoute } from "../middleware/auth.js" +import { asyncHandler } from "../middleware/errorHandler.js" import { getMessages, getMediaMessages, @@ -35,7 +36,7 @@ const messageRouter = express.Router() * 500: * description: Internal server error */ -messageRouter.get("/", protectRoute, getUserForSidebar) +messageRouter.get("/", protectRoute, asyncHandler(getUserForSidebar)) /** * @swagger @@ -60,7 +61,7 @@ messageRouter.get("/", protectRoute, getUserForSidebar) * 500: * description: Internal server error */ -messageRouter.get("/media/:userId", protectRoute, getMediaMessages) +messageRouter.get("/media/:userId", protectRoute, asyncHandler(getMediaMessages)) /** * @swagger @@ -85,7 +86,7 @@ messageRouter.get("/media/:userId", protectRoute, getMediaMessages) * 500: * description: Internal server error */ -messageRouter.get("/:userId", protectRoute, getMessages) +messageRouter.get("/:userId", protectRoute, asyncHandler(getMessages)) /** * @swagger @@ -112,7 +113,11 @@ messageRouter.get("/:userId", protectRoute, getMessages) * 500: * description: Internal server error */ -messageRouter.put("/mark-as-seen/:messageId", protectRoute, markMessagesAsSeen) +messageRouter.put( + "/mark-as-seen/:messageId", + protectRoute, + asyncHandler(markMessagesAsSeen), +) /** * @swagger @@ -150,8 +155,12 @@ messageRouter.put("/mark-as-seen/:messageId", protectRoute, markMessagesAsSeen) * 500: * description: Internal server error */ -messageRouter.post("/send/:receiverId", protectRoute, sendMessage) -messageRouter.put("/edit/:messageId", protectRoute, editMessage) -messageRouter.delete("/delete/:messageId", protectRoute, deleteMessage) +messageRouter.post("/send/:receiverId", protectRoute, asyncHandler(sendMessage)) +messageRouter.put("/edit/:messageId", protectRoute, asyncHandler(editMessage)) +messageRouter.delete( + "/delete/:messageId", + protectRoute, + asyncHandler(deleteMessage), +) export default messageRouter diff --git a/backend/routes/user.routes.js b/backend/routes/user.routes.js index c811479..46694f9 100644 --- a/backend/routes/user.routes.js +++ b/backend/routes/user.routes.js @@ -13,6 +13,7 @@ import { loginGuest, } from "../controllers/user.controller.js" import { protectRoute } from "../middleware/auth.js" +import { asyncHandler } from "../middleware/errorHandler.js" import { validateBody } from "../middleware/validate.middleware.js" import { signupSchema, @@ -79,7 +80,7 @@ const userRouter = express.Router() * 500: * description: Internal server error */ -userRouter.post("/signup", validateBody(signupSchema), signup) +userRouter.post("/signup", validateBody(signupSchema), asyncHandler(signup)) /** * @swagger @@ -117,7 +118,7 @@ userRouter.post("/signup", validateBody(signupSchema), signup) * 500: * description: Internal server error */ -userRouter.post("/login", validateBody(loginSchema), login) +userRouter.post("/login", validateBody(loginSchema), asyncHandler(login)) /** * @swagger @@ -135,10 +136,14 @@ userRouter.post("/login", validateBody(loginSchema), login) * 500: * description: Internal server error */ -userRouter.post("/refresh", refresh) -userRouter.post("/logout", logout) -userRouter.post("/send-otp", validateBody(sendOTPSchema), sendOTP) -userRouter.post("/verify-otp", validateBody(verifyOTPSchema), verifyOTP) +userRouter.post("/refresh", asyncHandler(refresh)) +userRouter.post("/logout", asyncHandler(logout)) +userRouter.post("/send-otp", validateBody(sendOTPSchema), asyncHandler(sendOTP)) +userRouter.post( + "/verify-otp", + validateBody(verifyOTPSchema), + asyncHandler(verifyOTP), +) /** * @swagger * /api/v1/auth/guest-login: @@ -169,18 +174,18 @@ userRouter.post("/verify-otp", validateBody(verifyOTPSchema), verifyOTP) * 500: * description: Internal server error */ -userRouter.post("/guest-login", loginGuest) +userRouter.post("/guest-login", asyncHandler(loginGuest)) userRouter.post( "/forgot-password", validateBody(forgotPasswordSchema), - forgotPassword, + asyncHandler(forgotPassword), ) userRouter.post( "/reset-password", validateBody(resetPasswordSchema), - resetPassword, + asyncHandler(resetPassword), ) -userRouter.get("/check-auth", protectRoute, checkAuth) +userRouter.get("/check-auth", protectRoute, asyncHandler(checkAuth)) /** * @swagger @@ -218,7 +223,7 @@ userRouter.put( "/update-profile", protectRoute, validateBody(updateProfileSchema), - updateProfile, + asyncHandler(updateProfile), ) export default userRouter diff --git a/backend/server.js b/backend/server.js index ca2fc08..2522f07 100644 --- a/backend/server.js +++ b/backend/server.js @@ -16,6 +16,7 @@ import ChallengeRoom from "./models/ChallengeRoom.js" import { Server } from "socket.io" import { isVercel, parsePort, getPlatform } from "./lib/runtime.js" import { registerTypingHandlers } from "./typingHandler.js" +import { globalErrorHandler, notFoundHandler } from "./middleware/errorHandler.js" const app = express() const server = http.createServer(app) @@ -319,10 +320,13 @@ app.use("/api/v1/messages", standardLimiter, messageRouter) app.use("/api/v1/problems", standardLimiter, problemRouter) app.use("/api/v1/challenges", standardLimiter, challengeRouter) -app.use("/", (req, res) => { +app.get("/", (req, res) => { res.send("NPMChat API is running") }) +app.use(notFoundHandler) +app.use(globalErrorHandler) + // 5. Database Connection if (process.env.NODE_ENV !== "test") { connectDB()