Real World Example

An Orders Endpoint, End to End

A typical Node.js backend at a startup: validated input, a typed service layer, typed responses and one error handler. The HTTP part is Express; the service is plain TypeScript and fully testable.

// src/routes/orders.ts
import { Router } from "express";
import { z } from "zod";
import { asyncHandler, HttpError } from "../middleware";
import { orderService } from "../services/order.service";
import type { Order } from "../types";

const CreateOrder = z.object({
  items: z.array(z.object({ productId: z.number().int(), qty: z.number().int().min(1).max(10) })).min(1),
  couponCode: z.string().optional(),
});

export const ordersRouter = Router();

ordersRouter.post(
  "/",
  asyncHandler<{}, Order, unknown>(async (req, res) => {
    const parsed = CreateOrder.safeParse(req.body);
    if (!parsed.success) throw new HttpError(400, parsed.error.issues[0]?.message ?? "Invalid body");
    const order = await orderService.create(req.user!.id, parsed.data);
    res.status(201).json(order);
  }),
);

Example

curl -X POST localhost:3000/orders -H "Authorization: Bearer t0k3n" -H "Content-Type: application/json" \
  -d '{"items":[{"productId":42,"qty":20}]}'

Example output

HTTP/1.1 400 Bad Request
{"message":"Number must be less than or equal to 10"}