Skip to content

Validation

Almasix validates incoming data with a rule engine and optional Pydantic FormRequest schemas. Invalid input becomes a 422 with a field → messages map; valid input is ready for your controller.

app/http/controllers/post_controller.py
from almasix.http import Controller, Request
from almasix.validation import Field, FormRequest
class StorePostRules(FormRequest):
title: str = Field(min_length=3)
class PostController(Controller):
async def store(self, request: Request) -> dict:
return request.validate(StorePostRules)
app/http/controllers/post_controller.py
data = request.validate({
"title": "required|string|min:3",
"email": ["required", "email"],
})
app/http/controllers/post_controller.py
from almasix.validation import Rule
data = request.validate({
"title": [Rule.required(), Rule.min(3)],
"email": "required|email|unique:users,email",
})

Type-hint a FormRequest; the kernel validates before the action:

app/http/controllers/post_controller.py
async def store(self, request: StorePostRequest) -> dict:
return {"title": request.data.title}
terminal
smith make:request StorePostRequest
app/http/controllers/post_controller.py
from almasix.validation import validator
check = validator(request.all(), {"email": "required|email"})
if check.fails():
return {"errors": check.errors()}
return check.validated()
Method Purpose
passes() / fails() Boolean outcome
errors() dict[str, list[str]]
validated() / validate() Cleaned dict or raise ValidationException

Pipe syntax (required|email) and Rule.* both work unless a rule is cross-field only (required_if, confirmed, exclude_*, and similar) — those belong on the rule-string / Rule list path.

The field must be yes, on, 1, or true.

app/http/controllers/example_controller.py
request.validate({"field": "accepted"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.accepted()]})

The field must be accepted when another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "accepted_if"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.accepted_if()]})

The field must be a URL with a resolvable host.

app/http/controllers/example_controller.py
request.validate({"field": "active_url"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.active_url()]})

The field must be a date after the given date or field.

app/http/controllers/example_controller.py
request.validate({"field": "after"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.after()]})

The field must be a date after or equal to the given date.

app/http/controllers/example_controller.py
request.validate({"field": "after_or_equal"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.after_or_equal()]})

The field must contain only letters.

app/http/controllers/example_controller.py
request.validate({"field": "alpha"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.alpha()]})

The field may contain letters, numbers, dashes, and underscores.

app/http/controllers/example_controller.py
request.validate({"field": "alpha_dash"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.alpha_dash()]})

The field must contain only letters and numbers.

app/http/controllers/example_controller.py
request.validate({"field": "alpha_num"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.alpha_num()]})

The field must satisfy at least one of the given rule sets.

app/http/controllers/example_controller.py
request.validate({"field": "any_of"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.any_of()]})

The field must be a list or mapping.

app/http/controllers/example_controller.py
request.validate({"field": "array"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.array()]})

The field must contain only single-byte ASCII characters.

app/http/controllers/example_controller.py
request.validate({"field": "ascii"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.ascii()]})

Stop running further rules for this field after the first failure.

app/http/controllers/example_controller.py
request.validate({"field": "bail"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.bail()]})

The field must be a date before the given date or field.

app/http/controllers/example_controller.py
request.validate({"field": "before"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.before()]})

The field must be a date before or equal to the given date.

app/http/controllers/example_controller.py
request.validate({"field": "before_or_equal"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.before_or_equal()]})

The field size must fall between the given min and max.

app/http/controllers/example_controller.py
request.validate({"field": "between"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.between()]})

The field must be true or false (including 0/1 string forms).

app/http/controllers/example_controller.py
request.validate({"field": "boolean"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.boolean()]})

The field must match {field}_confirmation.

app/http/controllers/example_controller.py
request.validate({"field": "confirmed"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.confirmed()]})

A list field must contain the given values.

app/http/controllers/example_controller.py
request.validate({"field": "contains"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.contains()]})

The field must match the authenticated user’s password.

app/http/controllers/example_controller.py
request.validate({"field": "current_password"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.current_password()]})

The field must be a valid date.

app/http/controllers/example_controller.py
request.validate({"field": "date"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.date()]})

The field must equal the given date.

app/http/controllers/example_controller.py
request.validate({"field": "date_equals"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.date_equals()]})

The field must match the given date format.

app/http/controllers/example_controller.py
request.validate({"field": "date_format"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.date_format()]})

The field must be numeric with the given decimal places.

app/http/controllers/example_controller.py
request.validate({"field": "decimal"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.decimal()]})

The field must be no, off, 0, or false.

app/http/controllers/example_controller.py
request.validate({"field": "declined"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.declined()]})

The field must be declined when another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "declined_if"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.declined_if()]})

The field must differ from another field.

app/http/controllers/example_controller.py
request.validate({"field": "different"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.different()]})

The field must be a number with exactly N digits.

app/http/controllers/example_controller.py
request.validate({"field": "digits"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.digits()]})

The field must be a number with a digit count in range.

app/http/controllers/example_controller.py
request.validate({"field": "digits_between"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.digits_between()]})

An uploaded image must match the given dimension constraints.

app/http/controllers/example_controller.py
request.validate({"field": "dimensions"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.dimensions()]})

A list field must not contain duplicate values.

app/http/controllers/example_controller.py
request.validate({"field": "distinct"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.distinct()]})

A list field must not contain the given values.

app/http/controllers/example_controller.py
request.validate({"field": "doesnt_contain"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.doesnt_contain()]})

The field must not end with any of the given values.

app/http/controllers/example_controller.py
request.validate({"field": "doesnt_end_with"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.doesnt_end_with()]})

The field must not start with any of the given values.

app/http/controllers/example_controller.py
request.validate({"field": "doesnt_start_with"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.doesnt_start_with()]})

The field must be a valid email address.

app/http/controllers/example_controller.py
request.validate({"field": "email"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.email()]})

The field must be valid in the given character encoding.

app/http/controllers/example_controller.py
request.validate({"field": "encoding"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.encoding()]})

The field must end with one of the given values.

app/http/controllers/example_controller.py
request.validate({"field": "ends_with"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.ends_with()]})

The field must be one of the listed values.

app/http/controllers/example_controller.py
request.validate({"field": "enum"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.enum()]})

Exclude this field from the validated payload.

app/http/controllers/example_controller.py
request.validate({"field": "exclude"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.exclude()]})

Exclude this field when another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "exclude_if"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.exclude_if()]})

Exclude this field unless another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "exclude_unless"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.exclude_unless()]})

Exclude this field when another field is present.

app/http/controllers/example_controller.py
request.validate({"field": "exclude_with"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.exclude_with()]})

Exclude this field when another field is missing.

app/http/controllers/example_controller.py
request.validate({"field": "exclude_without"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.exclude_without()]})

The value must exist in the given database table/column.

app/http/controllers/example_controller.py
request.validate({"field": "exists"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.exists()]})

An upload must have one of the given file extensions.

app/http/controllers/example_controller.py
request.validate({"field": "extensions"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.extensions()]})

The field must be an uploaded file.

app/http/controllers/example_controller.py
request.validate({"field": "file"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.file()]})

If the field is present, it must not be empty.

app/http/controllers/example_controller.py
request.validate({"field": "filled"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.filled()]})

The field must be greater than the given value or field.

app/http/controllers/example_controller.py
request.validate({"field": "gt"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.gt()]})

The field must be greater than or equal to the given value or field.

app/http/controllers/example_controller.py
request.validate({"field": "gte"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.gte()]})

The field must be a valid hexadecimal color.

app/http/controllers/example_controller.py
request.validate({"field": "hex_color"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.hex_color()]})

The field must be an image upload.

app/http/controllers/example_controller.py
request.validate({"field": "image"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.image()]})

The field must be one of the listed values.

app/http/controllers/example_controller.py
request.validate({"field": "in:a,b,c"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.in_("a", "b", "c")]})

The field value must exist in another field’s list.

app/http/controllers/example_controller.py
request.validate({"field": "in_array"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.in_array()]})

A mapping field must contain at least one of the given keys.

app/http/controllers/example_controller.py
request.validate({"field": "in_array_keys"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.in_array_keys()]})

The field must be an integer.

app/http/controllers/example_controller.py
request.validate({"field": "integer"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.integer()]})

The field must be a valid IP address.

app/http/controllers/example_controller.py
request.validate({"field": "ip"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.ip()]})

The field must be a valid IPv4 address.

app/http/controllers/example_controller.py
request.validate({"field": "ipv4"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.ipv4()]})

The field must be a valid IPv6 address.

app/http/controllers/example_controller.py
request.validate({"field": "ipv6"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.ipv6()]})

The field must be a valid JSON string.

app/http/controllers/example_controller.py
request.validate({"field": "json"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.json()]})

The field must be a list (not a mapping).

app/http/controllers/example_controller.py
request.validate({"field": "list"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.list()]})

The field must be lowercase.

app/http/controllers/example_controller.py
request.validate({"field": "lowercase"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.lowercase()]})

The field must be less than the given value or field.

app/http/controllers/example_controller.py
request.validate({"field": "lt"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.lt()]})

The field must be less than or equal to the given value or field.

app/http/controllers/example_controller.py
request.validate({"field": "lte"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.lte()]})

The field must be a valid MAC address.

app/http/controllers/example_controller.py
request.validate({"field": "mac_address"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.mac_address()]})

The field size must be at most the given maximum.

app/http/controllers/example_controller.py
request.validate({"field": "max:10"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.max(10)]})

A numeric field may have at most N digits.

app/http/controllers/example_controller.py
request.validate({"field": "max_digits"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.max_digits()]})

An upload must match one of the given extensions.

app/http/controllers/example_controller.py
request.validate({"field": "mimes"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.mimes()]})

An upload must match one of the given MIME types.

app/http/controllers/example_controller.py
request.validate({"field": "mimetypes"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.mimetypes()]})

The field size must be at least the given minimum.

app/http/controllers/example_controller.py
request.validate({"field": "min:3"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.min(3)]})

A numeric field must have at least N digits.

app/http/controllers/example_controller.py
request.validate({"field": "min_digits"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.min_digits()]})

The field must not be present.

app/http/controllers/example_controller.py
request.validate({"field": "missing"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.missing()]})

The field must be missing when another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "missing_if"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.missing_if()]})

The field must be missing unless another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "missing_unless"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.missing_unless()]})

The field must be missing when any of the given fields are present.

app/http/controllers/example_controller.py
request.validate({"field": "missing_with"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.missing_with()]})

The field must be missing when all given fields are present.

app/http/controllers/example_controller.py
request.validate({"field": "missing_with_all"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.missing_with_all()]})

The field must be a multiple of the given value.

app/http/controllers/example_controller.py
request.validate({"field": "multiple_of"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.multiple_of()]})

The field must not be one of the listed values.

app/http/controllers/example_controller.py
request.validate({"field": "not_in"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.not_in()]})

The field must not match the given pattern.

app/http/controllers/example_controller.py
request.validate({"field": "not_regex"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.not_regex()]})

Empty values are allowed; other rules are skipped when empty.

app/http/controllers/example_controller.py
request.validate({"field": "nullable"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.nullable()]})

The field must be numeric.

app/http/controllers/example_controller.py
request.validate({"field": "numeric"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.numeric()]})

The field must be present (may be empty).

app/http/controllers/example_controller.py
request.validate({"field": "present"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.present()]})

The field must be present when another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "present_if"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.present_if()]})

The field must be present unless another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "present_unless"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.present_unless()]})

The field must be present when any of the given fields are present.

app/http/controllers/example_controller.py
request.validate({"field": "present_with"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.present_with()]})

The field must be present when all given fields are present.

app/http/controllers/example_controller.py
request.validate({"field": "present_with_all"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.present_with_all()]})

The field must not be present.

app/http/controllers/example_controller.py
request.validate({"field": "prohibited"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.prohibited()]})

The field is prohibited when another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "prohibited_if"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.prohibited_if()]})

The field is prohibited when another field is accepted.

app/http/controllers/example_controller.py
request.validate({"field": "prohibited_if_accepted"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.prohibited_if_accepted()]})

The field is prohibited when another field is declined.

app/http/controllers/example_controller.py
request.validate({"field": "prohibited_if_declined"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.prohibited_if_declined()]})

The field is prohibited unless another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "prohibited_unless"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.prohibited_unless()]})

When this field is present, the listed fields must be missing.

app/http/controllers/example_controller.py
request.validate({"field": "prohibits"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.prohibits()]})

The field must match the given pattern.

app/http/controllers/example_controller.py
request.validate({"field": r"regex:/^[a-z]+$/"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.regex("^[a-z]+$")]})

The field must be present and not empty.

app/http/controllers/example_controller.py
request.validate({"field": "required"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.required()]})

A mapping must contain the listed keys.

app/http/controllers/example_controller.py
request.validate({"field": "required_array_keys"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.required_array_keys()]})

The field is required when another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "required_if"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.required_if()]})

The field is required when another field is accepted.

app/http/controllers/example_controller.py
request.validate({"field": "required_if_accepted"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.required_if_accepted()]})

The field is required when another field is declined.

app/http/controllers/example_controller.py
request.validate({"field": "required_if_declined"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.required_if_declined()]})

The field is required unless another field has a given value.

app/http/controllers/example_controller.py
request.validate({"field": "required_unless"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.required_unless()]})

The field is required when any of the given fields are present.

app/http/controllers/example_controller.py
request.validate({"field": "required_with"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.required_with()]})

The field is required when all given fields are present.

app/http/controllers/example_controller.py
request.validate({"field": "required_with_all"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.required_with_all()]})

The field is required when any of the given fields are missing.

app/http/controllers/example_controller.py
request.validate({"field": "required_without"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.required_without()]})

The field is required when all given fields are missing.

app/http/controllers/example_controller.py
request.validate({"field": "required_without_all"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.required_without_all()]})

The field must match another field.

app/http/controllers/example_controller.py
request.validate({"field": "same"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.same()]})

The field size must equal the given value.

app/http/controllers/example_controller.py
request.validate({"field": "size"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.size()]})

Only validate this field when it is present on the payload.

app/http/controllers/example_controller.py
request.validate({"field": "sometimes"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.sometimes()]})

The field must start with one of the given values.

app/http/controllers/example_controller.py
request.validate({"field": "starts_with"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.starts_with()]})

The field must be a string.

app/http/controllers/example_controller.py
request.validate({"field": "string"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.string()]})

The field must be a valid timezone identifier.

app/http/controllers/example_controller.py
request.validate({"field": "timezone"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.timezone()]})

The field must be a valid ULID.

app/http/controllers/example_controller.py
request.validate({"field": "ulid"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.ulid()]})

The value must be unique in the given database table/column.

app/http/controllers/example_controller.py
request.validate({"field": "unique"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.unique()]})

The field must be uppercase.

app/http/controllers/example_controller.py
request.validate({"field": "uppercase"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.uppercase()]})

The field must be a valid URL.

app/http/controllers/example_controller.py
request.validate({"field": "url"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.url()]})

The field must be a valid UUID.

app/http/controllers/example_controller.py
request.validate({"field": "uuid"})
# or
from almasix.validation import Rule
request.validate({"field": [Rule.uuid()]})
terminal
smith make:rule Uppercase

Attach with AfterValidator on a FormRequest field, or raise ValueError from @field_validator.

Override per call with messages= / attributes=, via FormRequest messages() / attributes(), or publish the catalog:

terminal
smith lang:publish
response
{
"message": "The given data was invalid.",
"status": 422,
"errors": {
"email": ["The email field must be a valid email address."]
}
}