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 459b323..81a0197 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, @@ -37,7 +38,7 @@ const messageRouter = express.Router() * 500: * description: Internal server error */ -messageRouter.get("/", protectRoute, getUserForSidebar) +messageRouter.get("/", protectRoute, asyncHandler(getUserForSidebar)) /** * @swagger @@ -62,7 +63,7 @@ messageRouter.get("/", protectRoute, getUserForSidebar) * 500: * description: Internal server error */ -messageRouter.get("/media/:userId", protectRoute, getMediaMessages) +messageRouter.get("/media/:userId", protectRoute, asyncHandler(getMediaMessages)) /** * @swagger @@ -80,7 +81,7 @@ messageRouter.get("/media/:userId", protectRoute, getMediaMessages) * 500: * description: Internal server error */ -messageRouter.get("/sync", protectRoute, syncMessages) +messageRouter.get("/sync", protectRoute, asyncHandler(syncMessages)) /** * @swagger @@ -105,7 +106,7 @@ messageRouter.get("/sync", protectRoute, syncMessages) * 500: * description: Internal server error */ -messageRouter.get("/:userId", protectRoute, getMessages) +messageRouter.get("/:userId", protectRoute, asyncHandler(getMessages)) /** * @swagger @@ -132,8 +133,16 @@ messageRouter.get("/:userId", protectRoute, getMessages) * 500: * description: Internal server error */ -messageRouter.put("/mark-as-seen/:messageId", protectRoute, markMessagesAsSeen) -messageRouter.put("/mark-conversation-seen/:senderId", protectRoute, markConversationSeen) +messageRouter.put( + "/mark-as-seen/:messageId", + protectRoute, + asyncHandler(markMessagesAsSeen), +) +messageRouter.put( + "/mark-conversation-seen/:senderId", + protectRoute, + asyncHandler(markConversationSeen), +) /** * @swagger @@ -171,8 +180,12 @@ messageRouter.put("/mark-conversation-seen/:senderId", protectRoute, markConvers * 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 5944f2e..721b802 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) @@ -357,10 +358,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()