Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

validate

import validate

Schema-based input validation for Zuri applications.

The validate module provides a fluent, chainable API for defining field-level validation rules, composing them into schemas, and checking arbitrary data dictionaries against those schemas.


Quick start

import validate

var schema = validate.schema({
  name:     validate.required().string().max_length(100),
  email:    validate.required().string().email(),
  age:      validate.required().integer().between(18, 120),
  website:  validate.string().url().sometimes(),
})

var result = schema.check({
  name:  'Ada Lovelace',
  email: 'ada@example.com',
  age:   36,
})

if result.valid {
  echo 'All good.'
} else {
  for err in result.errors {
    echo '${err.field}: ${err.message}'
  }
}

Rule chaining

Every top-level function returns a Validator instance. Rules are evaluated in the order they are chained. By default, evaluation stops at the first failing rule for each field (bail mode). Pass .bail(false) to collect all errors for a field.

# Collects every error for "password" rather than stopping at the first.
var rules = validate.schema({
  password: validate.required().string()
    .min_length(8)
    .regex('/[A-Z]/')
    .regex('/[0-9]/')
    .bail(false),
})

Optional fields

var rules = validate.schema({
  # bio is optional; when present it must be at most 500 chars.
  bio: validate.string().max_length(500).sometimes(),

  # nickname is optional and may be nil.
  nickname: validate.nullable().string().max_length(30).sometimes(),
})

Cross-field validation

var schema = validate.schema({
  password:              validate.required().string().min_length(8),
  password_confirmation: validate.required().string().confirmed(),
  role:                  validate.required().string().is_in(['user', 'admin']),
  admin_code:            validate.required_if('role', 'admin').string(),
})

required_if() (like the other conditional-requirement functions below) must come before .string() in the chain: see “Sequential Validation” further down for why the order here matters.


Nested fields (dot-notation)

var schema = validate.schema({
  'address.street':  validate.required().string(),
  'address.city':    validate.required().string(),
  'address.country': validate.required().string().length(2).uppercase(),
})

List items (wildcard)

var schema = validate.schema({
  'tags.*': validate.required().string().max_length(32).alpha_dash(),
})

Custom rules

Inline function:

var schema = validate.schema({
  code: validate.required().string().custom(@(value) {
    return value.starts_with('ZURI-') and value.length() == 12
  }, 'Must be a valid Zuri code (ZURI-XXXXXXX).')
})

Subclassing Rule:

import validate { Rule, Validator }

class Slug < Rule {
  validate(value) {
    if !is_string(value) return false
    return !!value.match('/^[a-z0-9]+(?:-[a-z0-9]+)*$/')
  }
  error() { return 'The ${self.name} field must be a valid slug.' }
}

var schema = validate.schema({
  slug: Validator().required().use(Slug),
})

Raising on failure

import validate { ValidationError }

def create_user(req, res) {
  catch {
    schema.check_or_raise(req.body)
  } as e

  if e {
    return res.json({ errors: schema.group_errors(e.errors) }, 422)
  }

  return res.json({ ok: true })
}

HTTP handler pattern

import http
import validate
import validate { ValidationError }

var create_user_schema = validate.schema({
  name:     validate.required().string().max_length(100),
  email:    validate.required().string().email(),
  password: validate.required().string().min_length(8),
  role:     validate.required().string().is_in(['user', 'admin']).sometimes(),
})

server.handle('POST', '/users', @(req, res) {
  catch {
    create_user_schema.check_or_raise(req.body)
  } as e

  if e {
    return res.json({ errors: create_user_schema.group_errors(e.errors) }, 422)
  }
  # ... create user
  res.json({ status: 'created' }, 201)
})

Sequential Validation

The validation mode is sequential, meaning that each field is validated in turn. This is the behavior you expect from a form submission. It is important to keep this in mind when using this module.

Consider the example below:

var schema = validate.schema({
  name: validate.required_if('age', 30).string().max_length(100),
  age:  validate.required().integer().between(18, 120),
})

If the age field is empty, the validation of name will not raise any error. This is because the required_if rule is only applied if the age field is 30 or greater and the entire chain exists before the next rule string().

However, if the validation rules were modified like this:

var schema = validate.schema({
  name: validate.string().required_if('age', 30).max_length(100),
  age:  validate.required().integer().between(18, 120),
})

Even when the age field is empty, the validation of name will raise an error if it is empty. This is because the string rule comes before the required_if rule.

With this behavior in mind, it is advised that optional rules such as sometimes, nullable, *_if, *_unless rules are applied early in the chain unless you absolutely want them to fail irrespective.

The validate API

Every public name in validate, wherever it is declared. Each links to the page that documents it.

NameKindSummary
validate.RuleclassAbstract base class for all validation rules.
validate.SchemaclassBinds a ruleset to data and validates it.
validate.ValidationErrorclassRaised by Schema.check_or_raise() when validation fails.
validate.ValidatorclassFluent rule chain builder for a single field.
validate.acceptedfunctionThe value must be one of the accepted truthy representations: true, "true", "yes", "on", "1", 1.
validate.afterfunctionThe value must be a date string after ref.
validate.after_or_equalfunctionThe value must be a date string after or equal to ref.
validate.alphafunctionThe string must contain only ASCII alphabetic characters (a-z, A-Z).
validate.alpha_dashfunctionThe string must contain only ASCII alphanumeric characters, hyphens, and underscores.
validate.alpha_numfunctionThe string must contain only ASCII alphanumeric characters.
validate.beforefunctionThe value must be a date string before ref.
validate.before_or_equalfunctionThe value must be a date string before or equal to ref.
validate.betweenfunctionThe value’s size must be between min and max (inclusive).
validate.booleanfunctionThe value must be boolean-like: true, false, "true", "false", "1", "0", 1, or 0.
validate.confirmedfunctionThe value must match the ``field_name_confirmation sibling field.
validate.containsfunctionThe string must contain the given substring.
validate.customfunctionValidates with an inline anonymous function.
validate.custom_with_datafunctionValidates with an inline function that also receives the full data dictionary, enabling cross-field logic…
validate.datefunctionThe value must be a valid date string parseable by the date module.
validate.declinedfunctionThe value must be one of the declined falsy representations: false, "false", "no", "off", "0", 0.
validate.dictfunctionThe value must be a dictionary.
validate.differentfunctionThe value must differ from the value of other_field.
validate.distinctfunctionThe list must not contain duplicate values.
validate.doesnt_containfunctionThe string must not contain the given substring.
validate.doesnt_end_withfunctionThe string must not end with any of the given suffixes.
validate.doesnt_start_withfunctionThe string must not start with any of the given prefixes.
validate.eachfunctionEvery item in the list must pass the given Validator chain.
validate.emailfunctionThe value must be a syntactically valid email address.
validate.ends_withfunctionThe string must end with one of the given suffixes.
validate.equalsfunctionThe value must strictly equal expected.
validate.gtfunctionThe numeric value must be greater than n.
validate.gtefunctionThe numeric value must be greater than or equal to n.
validate.in_listfunctionEvery item in the list value must be contained in values.
validate.integerfunctionThe value must be an integer (no fractional part).
validate.ipfunctionThe value must be a valid IPv4 or IPv6 address.
validate.ipv4functionThe value must be a valid IPv4 address.
validate.ipv6functionThe value must be a valid IPv6 address.
validate.is_infunctionThe value must be one of the given allowed values (strict comparison).
validate.is_nilfunctionThe value must be nil.
validate.jsonfunctionThe value must be a valid JSON string.
validate.lengthfunctionThe string’s character count must equal exactly n.
validate.length_betweenfunctionThe string’s length must be between min and max characters (inclusive).
validate.listfunctionThe value must be a list.
validate.lowercasefunctionThe string must be entirely lowercase.
validate.ltfunctionThe numeric value must be less than n.
validate.ltefunctionThe numeric value must be less than or equal to n.
validate.maxfunctionThe value’s size must be at most max.
validate.max_itemsfunctionThe list must have at most max items.
validate.max_lengthfunctionThe string must be at most max characters long.
validate.minfunctionThe value’s size must be at least min.
validate.min_itemsfunctionThe list must have at least min items.
validate.min_lengthfunctionThe string must be at least min characters long.
validate.multiple_offunctionThe numeric value must be a multiple of n.
validate.negativefunctionThe numeric value must be strictly negative (less than zero).
validate.negative_or_zerofunctionThe numeric value must be zero or negative.
validate.not_blankfunctionThe string must not consist entirely of whitespace.
validate.not_equalsfunctionThe value must not equal forbidden.
validate.not_infunctionThe value must not be one of the given forbidden values.
validate.not_nilfunctionThe value must not be nil.
validate.not_regexfunctionThe string must not match the given regular expression pattern.
validate.nullablefunctionA nil value passes all subsequent rules without evaluation.
validate.numberfunctionThe value must be a number (integer or float).
validate.numericfunctionThe value must be numeric: either a number type or a string that converts cleanly to a number.
validate.positivefunctionThe numeric value must be strictly positive (greater than zero).
validate.positive_or_zerofunctionThe numeric value must be zero or positive.
validate.prohibitedfunctionThis field must be absent or nil: it is never permitted.
validate.prohibited_iffunctionThe field must be absent when other_field equals any of other_values.
validate.prohibited_unlessfunctionThe field must be absent unless other_field equals any of other_values.
validate.prohibitsfunctionWhen this field is present, none of the listed sibling fields may also be present.
validate.regexfunctionThe string must match the given regular expression pattern.
validate.requiredfunctionThe field must be present, non-nil, and non-empty.
validate.required_iffunctionThe field becomes required when other_field equals any value in other_values.
validate.required_unlessfunctionThe field becomes required unless other_field equals any value in other_values.
validate.required_withfunctionThe field becomes required when any of the listed sibling fields are present and non-blank.
validate.required_with_allfunctionThe field becomes required when all of the listed sibling fields are present and non-blank.
validate.required_withoutfunctionThe field becomes required when any of the listed sibling fields are absent or blank.
validate.required_without_allfunctionThe field becomes required when all of the listed sibling fields are absent or blank.
validate.rule.instantiate_rulefunctionBuilds one Rule instance from a [rule_class, ...args] entry: the shape Validator._rules stores each…
validate.rules.AcceptedclassPasses when the value equals one of the specified accepted values: true, "true", "yes", "on", "1",…
validate.rules.AfterclassPasses when the value is a date string after the given reference date.
validate.rules.AfterOrEqualclassPasses when the value is a date string after or equal to the given reference date.
validate.rules.AlphaclassPasses when the string contains only ASCII alphabetic characters (a-z, A-Z).
validate.rules.AlphaDashclassPasses when the string contains only ASCII alphanumeric characters, hyphens (-), and underscores (_).
validate.rules.AlphaNumclassPasses when the string contains only ASCII alphanumeric characters.
validate.rules.BeforeclassPasses when the value is a date string before the given reference date.
validate.rules.BeforeOrEqualclassPasses when the value is a date string before or equal to the given reference date.
validate.rules.BetweenclassPasses when the value’s size is between min and max (inclusive).
validate.rules.BooleanRuleclassPasses only when the value is a boolean (true or false).
validate.rules.ConfirmedclassPasses when the field’s value matches ``name_confirmation in the data.
validate.rules.ContainsclassPasses when the string contains the given substring.
validate.rules.CustomRuleclassCustom rule backed by a caller-supplied function.
validate.rules.CustomRuleWithDataclassCustom rule that also receives the full data dictionary.
validate.rules.DateRuleclassPasses when the value is a valid date string parseable by the date module (e.g. "2024-06-15",…
validate.rules.DeclinedclassPasses when the value equals one of the specified declined values: false, "false", "no", "off",…
validate.rules.DictRuleclassPasses only when the value is a dictionary.
validate.rules.DifferentclassPasses when the field’s value does not match the value of another field.
validate.rules.DistinctclassPasses when the list field contains no duplicate values.
validate.rules.DoesntContainclassPasses when the string does not contain the given substring.
validate.rules.DoesntEndWithclassPasses when the string does not end with any of the given suffixes.
validate.rules.DoesntStartWithclassPasses when the string does not start with any of the given prefixes.
validate.rules.EachclassPasses when every item in the list satisfies the given Validator chain.
validate.rules.EmailclassPasses when the value is a syntactically valid email address.
validate.rules.EndsWithclassPasses when the string ends with one of the given suffixes.
validate.rules.EqualsclassPasses when the field value is strictly equal to the given expected value.
validate.rules.GtclassPasses when the numeric value is greater than n.
validate.rules.GteclassPasses when the numeric value is greater than or equal to n.
validate.rules.InclassPasses when the value is contained in the given list of allowed values.
validate.rules.InListclassPasses when every item in the value list is contained in the allowed list.
validate.rules.IntegerRuleclassPasses only when the value is an integer (no fractional part).
validate.rules.IpclassPasses when the value is a valid IPv4 or IPv6 address.
validate.rules.Ipv4classPasses when the value is a valid IPv4 address.
validate.rules.Ipv6classPasses when the value is a valid IPv6 address.
validate.rules.JsonclassPasses when the value is a valid JSON string.
validate.rules.LengthclassPasses when a string’s length is exactly n characters.
validate.rules.LengthBetweenclassPasses when a string’s length is between min and max characters (inclusive).
validate.rules.ListRuleclassPasses only when the value is a list.
validate.rules.LowercaseclassPasses when the string value contains only lowercase characters.
validate.rules.LtclassPasses when the numeric value is less than n.
validate.rules.LteclassPasses when the numeric value is less than or equal to n.
validate.rules.MaxclassPasses when the value’s size is at most max.
validate.rules.MaxItemsclassPasses when the list field has at most max items.
validate.rules.MaxLengthclassPasses when a string’s length is at most max characters.
validate.rules.MinclassPasses when the value’s size is at least min.
validate.rules.MinItemsclassPasses when the list field has at least min items.
validate.rules.MinLengthclassPasses when a string’s length is at least min characters.
validate.rules.MultipleOfclassPasses when the numeric value is a multiple of n.
validate.rules.NegativeclassPasses when the numeric value is negative (strictly less than zero).
validate.rules.NegativeOrZeroclassPasses when the numeric value is negative or zero.
validate.rules.NilclassPasses when the value is nil.
validate.rules.NotBlankclassPasses when the value does not consist solely of whitespace.
validate.rules.NotEqualsclassPasses when the field value is not equal to the given forbidden value.
validate.rules.NotInclassPasses when the value is not contained in the given list of values.
validate.rules.NotNilclassPasses when the value is not nil.
validate.rules.NotRegexclassPasses when the string value does not match the given regular expression.
validate.rules.NullableclassPasses when the field is absent or nil.
validate.rules.NumberRuleclassPasses only when the value is a number (integer or float).
validate.rules.NumericRuleclassPasses only when the value is numeric (a number, or a string that can be losslessly converted to a number).
validate.rules.PositiveclassPasses when the numeric value is positive (strictly greater than zero).
validate.rules.PositiveOrZeroclassPasses when the numeric value is positive or zero.
validate.rules.ProhibitedclassPasses when this field is absent or nil.
validate.rules.ProhibitedIfclassPasses when this field is absent or nil if another field equals one of the given values.
validate.rules.ProhibitedUnlessclassPasses when this field is absent or nil unless another field equals one of the given values.
validate.rules.ProhibitsclassPasses when both this field and the listed sibling fields are either all present (non-nil) or all absent (nil…
validate.rules.RegexclassPasses when the string value matches the given regular expression.
validate.rules.RequiredclassFails when the field is absent, nil, an empty string, or an empty list.
validate.rules.RequiredIfclassPasses when this field is present and non-nil only if another field in the data satisfies a given condition.
validate.rules.RequiredUnlessclassPasses when this field is present and non-nil unless another field equals any of the given values.
validate.rules.RequiredWithclassPasses when this field is present and non-nil if any of the listed sibling fields are also present and…
validate.rules.RequiredWithAllclassPasses when this field is present and non-nil if all of the listed sibling fields are present and non-nil.
validate.rules.RequiredWithoutclassPasses when this field is present and non-nil if any of the listed sibling fields are absent or nil.
validate.rules.RequiredWithoutAllclassPasses when this field is present and non-nil if all of the listed sibling fields are absent or nil.
validate.rules.SameclassPasses when the field’s value matches the value of another field in the same data dictionary.
validate.rules.SizeclassPasses when the value’s size equals n.
validate.rules.StartsWithclassPasses when the string starts with one of the given prefixes.
validate.rules.StringRuleclassPasses only when the value is a string.
validate.rules.TimezoneclassPasses when the value is a real IANA timezone identifier (e.g. "UTC", "Africa/Lagos",…
validate.rules.UppercaseclassPasses when the string value contains only uppercase characters.
validate.rules.UrlclassPasses when the value is a syntactically valid HTTP or HTTPS URL.
validate.rules.UuidclassPasses when the value is a valid canonical UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
validate.samefunctionThe value must match the value of other_field in the same data dictionary.
validate.schemafunctionCreates a new Schema from the given ruleset dictionary.
validate.sizefunctionThe value’s size must equal exactly n.
validate.sometimesfunctionSkips the entire rule chain when the field is absent from the data dictionary or its value is nil / blank.
validate.starts_withfunctionThe string must start with one of the given prefixes.
validate.stringfunctionThe value must be a string.
validate.timezonefunctionThe value must be a valid timezone identifier recognised by the date module (e.g. "UTC",…
validate.uppercasefunctionThe string must be entirely uppercase.
validate.urlfunctionThe value must be a valid HTTP or HTTPS URL.
validate.usefunctionAttaches a pre-defined Rule subclass (the class itself, not an instance) directly.
validate.uuidfunctionThe value must be a valid canonical UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
validate.valuefunctionReturns a bare Validator with no rules pre-applied.

Submodules

ModuleReached asSummary
validate.rulevalidate.rule.*Defines the base Rule class that all built-in and custom validation rules extend.
validate.rulesimport validate.rulesAll built-in validation rule implementations.
validate.schemavalidate.schema.*
validate.validatorvalidate.validator.*
validate.validatorsvalidate.*Top-level convenience functions that create a fresh Validator instance with one rule pre-applied.

Functions

schema()

validate.schema(ruleset) -> Schema

Creates a new Schema from the given ruleset dictionary.

This is the primary entry point for defining a validation schema. Each key is a field name (supports dot-notation and .* wildcards) and each value must be a Validator instance.

import validate

var schema = validate.schema({
  username: validate.required().string().alpha_dash().max_length(30),
  email:    validate.required().string().email(),
})

Parameters

  • ruleset (dict)

Returns Schema

Raises ArgumentError

Raises ValueError


2026, Richard Ore and The Zuri Contributors