Schema Validator
Hard · Validation
Libraries like zod and joi validate request bodies before a route handler trusts them. Write validate(schema, value) for schemas written as plain objects. It returns { success: true, data } or { success: false, issues }. Every issue is { path, message }, and ALL issues are collected, not just the first one.
Schema types and their messages, checked in this order:
- { type: "string", min, max, email } (options are optional): not a string → "Expected string" and stop. Then collect every failure: shorter than min → "Must have at least <min> character(s)", longer than max → "Must have at most <max> character(s)", email: true and not an email → "Invalid email". An email is one or more characters that are not spaces or @, then @, then two or more labels separated by dots, where each label is one or more characters that are not spaces, @ or dots.
- { type: "number", int, min, max }: not a number, or NaN → "Expected number" and stop. Then collect: int: true and not an integer → "Expected integer", below min → "Must be >= <min>", above max → "Must be <= <max>".
- { type: "boolean" }: anything else → "Expected boolean".
- { type: "enum", values }: the value must be one of values (===), otherwise "Expected one of: <values joined with ', '>".
- { type: "array", of, min, max }: not an array → "Expected array" and stop. Then fewer than min items → "Must have at least <min> item(s)", more than max → "Must have at most <max> item(s)", then every item is validated with of.
- { type: "object", shape }: must be a plain object (not null, not an array), otherwise "Expected object" and stop. Then every key of shape is validated, in the order of shape. Keys that are not in shape are left out of data.
Any schema can also have optional: true or a default value. When the value is undefined: with a default, use the default (no other checks); with optional, it is valid and the key is left out of data; otherwise the issue is "Required".
Paths: the root is "", object keys are joined with . ("user.name"), and array items use brackets ("tags[0]", "items[1].id", or "[2]" for an item of a root array). Issues are listed in the order they are found, walking the value depth-first.
Next: Glob Pattern Matching