Express

Lesson 06

Central error handler

Use one Express error handler to map application errors into HTTP responses.

Good Code

src/errors.ts
import type { ErrorRequestHandler } from "express";

export const errorHandler: ErrorRequestHandler = (error, _req, res, next) => {
  if (res.headersSent) {
    next(error);
    return;
  }

  if (error.name === "ValidationError") {
    res.status(400).json({ error: error.message });
    return;
  }

  console.error({ error }, "Unhandled request error");
  res.status(500).json({ error: "Internal server error." });
};

Bad Code

src/reviews/router.ts
router.post("/", async (req, res) => {
  try {
    const review = await service.createReview(req.body);
    res.json(review);
  } catch (error) {
    console.error(error);
    res.status(500).send("Something broke");
  }
});

router.get("/:id", async (req, res) => {
  try {
    res.json(await service.getReview(req.params.id));
  } catch {
    res.status(400).json({ message: "Bad request" });
  }
});

Review Notes

What to review

Good Code

The good version centralizes error mapping, checks headersSent, and keeps unexpected error output generic.

Bad Code

The bad version repeats catch blocks in routes and returns different shapes and status codes for similar failures.

Takeaways

  • A central error handler keeps status codes, logging, and response bodies consistent.