Express

Lesson 04

Request validation

Validate request input at the route boundary before calling business services.

Good Code

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

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

  router.post("/", async (req, res) => {
    const result = parseCreateReviewBody(req.body);

    if (!result.ok) {
      res.status(400).json({ error: result.error });
      return;
    }

    const review = await service.createReview(result.value);
    res.status(201).json({ data: review });
  });

  return router;
}

Bad Code

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

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

  router.post("/", async (req, res) => {
    const review = await service.createReview({
      title: req.body.title,
      reviewerIds: req.body.reviewerIds,
      dueDate: req.body.dueDate,
    });

    res.status(201).json(review);
  });

  return router;
}

Review Notes

What to review

Good Code

The good version validates the body once at the route boundary and only passes trusted values into the service.

Bad Code

The bad version copies raw body fields directly into business logic and leaves missing, malformed, or extra input to fail later.

Takeaways

  • Route handlers should pass validated values to services, not raw request bodies.