Express

Lesson 05

Async route error forwarding

Let async route failures reach the Express error pipeline instead of becoming unhandled work.

Good Code

src/reviews/router.ts
import { Router } from "express";
import { NotFoundError } from "../errors";

export function createReviewsRouter(service: ReviewsService) {
  const router = Router();

  router.get("/:id", async (req, res) => {
    const review = await service.getReview(req.params.id);

    if (!review) {
      throw new NotFoundError("Review not found.");
    }

    res.json({ data: review });
  });

  return router;
}

Bad Code

src/reviews/router.ts
import { Router } from "express";

export function createReviewsRouter(service: ReviewsService) {
  const router = Router();

  router.get("/:id", (req, res) => {
    service.getReview(req.params.id).then((review) => {
      if (!review) {
        res.status(404).json({ error: "Review not found." });
        return;
      }

      res.json({ data: review });
    });
  });

  return router;
}

Review Notes

What to review

Good Code

The good version uses an async handler and lets thrown errors move to the central error handler.

Bad Code

The bad version starts promise work without returning or catching it, so service failures can become unhandled while the request remains unfinished.

Takeaways

  • Async routes should either be awaited by Express or explicitly forwarded to next.