Capítulo 47 de 61

Chapter 47: JSON Schema — Registries & Multi-Schema Output

Core Idea

z.toJSONSchema() normally returns one self-contained schema, but passing a registry (instead of a single schema) produces an interlinked set of schemas keyed by id, using $ref to reference each other — the right approach for exporting mutually-referencing schemas as separate .json files or endpoints.

Key Concepts

  • z.globalRegistry.add(schema, { id }): registers a schema with an id used as its key/reference name in multi-schema output. Schemas without a registered id are silently ignored when converting a registry.
  • z.toJSONSchema(registry): returns { schemas: { [id]: JSONSchema } }, with cross-references between registered schemas rendered as $ref pointing at the other schema's id.
  • uri option: by default $refs are relative ("User"); pass uri: (id) => \https://example.com/${id}.json\`` to produce fully-qualified reference URIs, e.g. for serving each schema from its own endpoint.

Code Examples

const User = z.object({
  name: z.string(),
  get posts() { return z.array(Post); },
});
const Post = z.object({
  title: z.string(),
  content: z.string(),
  get author() { return User; },
});

z.globalRegistry.add(User, { id: "User" });
z.globalRegistry.add(Post, { id: "Post" });

z.toJSONSchema(z.globalRegistry);
// => { schemas: {
//   User: { id: "User", type: "object", properties: { name: {...}, posts: { type: "array", items: { $ref: "Post" } } }, ... },
//   Post: { id: "Post", type: "object", properties: { title: {...}, content: {...}, author: { $ref: "User" } }, ... },
// } }

z.toJSONSchema(z.globalRegistry, { uri: (id) => `https://example.com/${id}.json` });
// => same shape, but $refs become "https://example.com/User.json" etc.
  • What it demonstrates: converting mutually-recursive schemas into a set of cross-referencing JSON Schema documents.

Anti-patterns

  • Forgetting to register an id on every schema you expect in the multi-schema output: unregistered schemas are silently dropped — not an error, just absent from the result.

Key Takeaways

  1. Use the single-schema form of z.toJSONSchema() for self-contained output, and the registry form specifically when schemas reference each other and need to become separate, linkable documents.
  2. Every schema meant to appear in registry-based output needs an explicit id — there's no implicit naming from variable names.
  3. The uri option is what turns relative $refs into absolute URLs suitable for a schema actually served over HTTP.

Connects To

  • Recursive Objects: the getter-based mutual recursion pattern used to build User/Post here.
  • Metadata & Registries: the general registry mechanism this JSON Schema feature is built on.