Search docs

Jump between documentation pages.

Validation with Zod

Zod is the default validator most DaloyJS apps reach for: chainable schemas, mature ecosystem, and a huge community. It implements Standard Schema, so DaloyJS picks it up without any adapter.

Prefer a more modular, tree-shakeable API? See Validation with Valibot. Both work the same way at the framework level.

Install

ts
pnpm add @daloyjs/core zod

What gets validated

For each route you can declare schemas for:

  • request.params — path parameters (always strings; coerce in your schema if needed).
  • request.query — query string.
  • request.headers — request headers.
  • request.body — parsed JSON body. Only read when declared (no overhead otherwise).
  • responses[status].body — typed responses.

A complete route

ts
import { z } from "zod";

app.route({
  method: "POST",
  path: "/orders",
  operationId: "createOrder",
  request: {
    body: z.object({
      sku: z.string(),
      qty: z.number().int().positive(),
    }),
  },
  responses: {
    201: {
      description: "Created",
      body: z.object({ id: z.string().uuid(), sku: z.string(), qty: z.number() }),
    },
    422: { description: "Validation failed" },
  },
  handler: async ({ body }) => ({
    status: 201,
    body: { id: crypto.randomUUID(), sku: body.sku, qty: body.qty },
  }),
});

On invalid input, DaloyJS returns 422 Unprocessable Entity as RFC 9457 problem+json with the per-issue path and message array.

Body limits and content types

When a route declares request.body, DaloyJS will also enforce:

  • Content-Length / streamed size against app.bodyLimitBytes413.
  • Content-Type against app.allowedContentTypes (default application/json) → 415.
  • Prototype-pollution-safe JSON parsing (__proto__, constructor, prototype stripped).

Type inference

The handler context is fully typed: body, params, query, and headers are inferred from your schemas. The return value is also typed — TypeScript yells if you return a status not declared in responses.

ts
import { z } from "zod";

const Book = z.object({
  id: z.string().uuid(),
  title: z.string(),
  author: z.string(),
});

export type Book = z.infer<typeof Book>;

See also