Error boundaries — catch and handle errors at different levels.
1// Application-level error handler2class AppError extends Error {3 constructor(message, statusCode, code) {4 super(message);5 this.statusCode = statusCode;6 this.code = code;7 }8}910// Async handler wrapper11const asyncHandler = (fn) => (req, res, next) => {12 Promise.resolve(fn(req, res, next)).catch(next);13};1415// Route with error handling16app.get("/users/:id", asyncHandler(async (req, res) => {17 const user = await User.findById(req.params.id);18 if (!user) {19 throw new AppError("User not found", 404, "USER_NOT_FOUND");20 }21 res.json({ data: user });22}));2324// Global error handler25app.use((err, req, res, next) => {26 if (err instanceof AppError) {27 return res.status(err.statusCode).json({28 error: err.message,29 code: err.code,30 });31 }3233 console.error("Unhandled error:", err);34 res.status(500).json({ error: "Internal server error" });35});
Key points: