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.
Quick start: request.validate
Section titled “Quick start: request.validate”Schema (Pydantic / FormRequest)
Section titled “Schema (Pydantic / FormRequest)”from almasix.http import Controller, Requestfrom 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)Rule strings and Rule objects
Section titled “Rule strings and Rule objects”data = request.validate({ "title": "required|string|min:3", "email": ["required", "email"],})from almasix.validation import Rule
data = request.validate({ "title": [Rule.required(), Rule.min(3)], "email": "required|email|unique:users,email",})FormRequest injection
Section titled “FormRequest injection”Type-hint a FormRequest; the kernel validates before the action:
async def store(self, request: StorePostRequest) -> dict: return {"title": request.data.title}smith make:request StorePostRequestSoft checks
Section titled “Soft checks”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 |
Available validation rules
Section titled “Available validation rules”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.
accepted
Section titled “accepted”The field must be yes, on, 1, or true.
request.validate({"field": "accepted"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.accepted()]})accepted_if
Section titled “accepted_if”The field must be accepted when another field has a given value.
request.validate({"field": "accepted_if"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.accepted_if()]})active_url
Section titled “active_url”The field must be a URL with a resolvable host.
request.validate({"field": "active_url"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.active_url()]})The field must be a date after the given date or field.
request.validate({"field": "after"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.after()]})after_or_equal
Section titled “after_or_equal”The field must be a date after or equal to the given date.
request.validate({"field": "after_or_equal"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.after_or_equal()]})The field must contain only letters.
request.validate({"field": "alpha"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.alpha()]})alpha_dash
Section titled “alpha_dash”The field may contain letters, numbers, dashes, and underscores.
request.validate({"field": "alpha_dash"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.alpha_dash()]})alpha_num
Section titled “alpha_num”The field must contain only letters and numbers.
request.validate({"field": "alpha_num"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.alpha_num()]})any_of
Section titled “any_of”The field must satisfy at least one of the given rule sets.
request.validate({"field": "any_of"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.any_of()]})The field must be a list or mapping.
request.validate({"field": "array"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.array()]})The field must contain only single-byte ASCII characters.
request.validate({"field": "ascii"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.ascii()]})Stop running further rules for this field after the first failure.
request.validate({"field": "bail"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.bail()]})before
Section titled “before”The field must be a date before the given date or field.
request.validate({"field": "before"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.before()]})before_or_equal
Section titled “before_or_equal”The field must be a date before or equal to the given date.
request.validate({"field": "before_or_equal"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.before_or_equal()]})between
Section titled “between”The field size must fall between the given min and max.
request.validate({"field": "between"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.between()]})boolean
Section titled “boolean”The field must be true or false (including 0/1 string forms).
request.validate({"field": "boolean"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.boolean()]})confirmed
Section titled “confirmed”The field must match {field}_confirmation.
request.validate({"field": "confirmed"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.confirmed()]})contains
Section titled “contains”A list field must contain the given values.
request.validate({"field": "contains"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.contains()]})current_password
Section titled “current_password”The field must match the authenticated user’s password.
request.validate({"field": "current_password"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.current_password()]})The field must be a valid date.
request.validate({"field": "date"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.date()]})date_equals
Section titled “date_equals”The field must equal the given date.
request.validate({"field": "date_equals"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.date_equals()]})date_format
Section titled “date_format”The field must match the given date format.
request.validate({"field": "date_format"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.date_format()]})decimal
Section titled “decimal”The field must be numeric with the given decimal places.
request.validate({"field": "decimal"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.decimal()]})declined
Section titled “declined”The field must be no, off, 0, or false.
request.validate({"field": "declined"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.declined()]})declined_if
Section titled “declined_if”The field must be declined when another field has a given value.
request.validate({"field": "declined_if"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.declined_if()]})different
Section titled “different”The field must differ from another field.
request.validate({"field": "different"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.different()]})digits
Section titled “digits”The field must be a number with exactly N digits.
request.validate({"field": "digits"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.digits()]})digits_between
Section titled “digits_between”The field must be a number with a digit count in range.
request.validate({"field": "digits_between"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.digits_between()]})dimensions
Section titled “dimensions”An uploaded image must match the given dimension constraints.
request.validate({"field": "dimensions"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.dimensions()]})distinct
Section titled “distinct”A list field must not contain duplicate values.
request.validate({"field": "distinct"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.distinct()]})doesnt_contain
Section titled “doesnt_contain”A list field must not contain the given values.
request.validate({"field": "doesnt_contain"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.doesnt_contain()]})doesnt_end_with
Section titled “doesnt_end_with”The field must not end with any of the given values.
request.validate({"field": "doesnt_end_with"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.doesnt_end_with()]})doesnt_start_with
Section titled “doesnt_start_with”The field must not start with any of the given values.
request.validate({"field": "doesnt_start_with"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.doesnt_start_with()]})The field must be a valid email address.
request.validate({"field": "email"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.email()]})encoding
Section titled “encoding”The field must be valid in the given character encoding.
request.validate({"field": "encoding"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.encoding()]})ends_with
Section titled “ends_with”The field must end with one of the given values.
request.validate({"field": "ends_with"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.ends_with()]})The field must be one of the listed values.
request.validate({"field": "enum"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.enum()]})exclude
Section titled “exclude”Exclude this field from the validated payload.
request.validate({"field": "exclude"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.exclude()]})exclude_if
Section titled “exclude_if”Exclude this field when another field has a given value.
request.validate({"field": "exclude_if"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.exclude_if()]})exclude_unless
Section titled “exclude_unless”Exclude this field unless another field has a given value.
request.validate({"field": "exclude_unless"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.exclude_unless()]})exclude_with
Section titled “exclude_with”Exclude this field when another field is present.
request.validate({"field": "exclude_with"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.exclude_with()]})exclude_without
Section titled “exclude_without”Exclude this field when another field is missing.
request.validate({"field": "exclude_without"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.exclude_without()]})exists
Section titled “exists”The value must exist in the given database table/column.
request.validate({"field": "exists"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.exists()]})extensions
Section titled “extensions”An upload must have one of the given file extensions.
request.validate({"field": "extensions"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.extensions()]})The field must be an uploaded file.
request.validate({"field": "file"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.file()]})filled
Section titled “filled”If the field is present, it must not be empty.
request.validate({"field": "filled"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.filled()]})The field must be greater than the given value or field.
request.validate({"field": "gt"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.gt()]})The field must be greater than or equal to the given value or field.
request.validate({"field": "gte"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.gte()]})hex_color
Section titled “hex_color”The field must be a valid hexadecimal color.
request.validate({"field": "hex_color"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.hex_color()]})The field must be an image upload.
request.validate({"field": "image"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.image()]})The field must be one of the listed values.
request.validate({"field": "in:a,b,c"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.in_("a", "b", "c")]})in_array
Section titled “in_array”The field value must exist in another field’s list.
request.validate({"field": "in_array"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.in_array()]})in_array_keys
Section titled “in_array_keys”A mapping field must contain at least one of the given keys.
request.validate({"field": "in_array_keys"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.in_array_keys()]})integer
Section titled “integer”The field must be an integer.
request.validate({"field": "integer"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.integer()]})The field must be a valid IP address.
request.validate({"field": "ip"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.ip()]})The field must be a valid IPv4 address.
request.validate({"field": "ipv4"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.ipv4()]})The field must be a valid IPv6 address.
request.validate({"field": "ipv6"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.ipv6()]})The field must be a valid JSON string.
request.validate({"field": "json"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.json()]})The field must be a list (not a mapping).
request.validate({"field": "list"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.list()]})lowercase
Section titled “lowercase”The field must be lowercase.
request.validate({"field": "lowercase"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.lowercase()]})The field must be less than the given value or field.
request.validate({"field": "lt"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.lt()]})The field must be less than or equal to the given value or field.
request.validate({"field": "lte"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.lte()]})mac_address
Section titled “mac_address”The field must be a valid MAC address.
request.validate({"field": "mac_address"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.mac_address()]})The field size must be at most the given maximum.
request.validate({"field": "max:10"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.max(10)]})max_digits
Section titled “max_digits”A numeric field may have at most N digits.
request.validate({"field": "max_digits"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.max_digits()]})An upload must match one of the given extensions.
request.validate({"field": "mimes"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.mimes()]})mimetypes
Section titled “mimetypes”An upload must match one of the given MIME types.
request.validate({"field": "mimetypes"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.mimetypes()]})The field size must be at least the given minimum.
request.validate({"field": "min:3"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.min(3)]})min_digits
Section titled “min_digits”A numeric field must have at least N digits.
request.validate({"field": "min_digits"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.min_digits()]})missing
Section titled “missing”The field must not be present.
request.validate({"field": "missing"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.missing()]})missing_if
Section titled “missing_if”The field must be missing when another field has a given value.
request.validate({"field": "missing_if"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.missing_if()]})missing_unless
Section titled “missing_unless”The field must be missing unless another field has a given value.
request.validate({"field": "missing_unless"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.missing_unless()]})missing_with
Section titled “missing_with”The field must be missing when any of the given fields are present.
request.validate({"field": "missing_with"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.missing_with()]})missing_with_all
Section titled “missing_with_all”The field must be missing when all given fields are present.
request.validate({"field": "missing_with_all"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.missing_with_all()]})multiple_of
Section titled “multiple_of”The field must be a multiple of the given value.
request.validate({"field": "multiple_of"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.multiple_of()]})not_in
Section titled “not_in”The field must not be one of the listed values.
request.validate({"field": "not_in"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.not_in()]})not_regex
Section titled “not_regex”The field must not match the given pattern.
request.validate({"field": "not_regex"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.not_regex()]})nullable
Section titled “nullable”Empty values are allowed; other rules are skipped when empty.
request.validate({"field": "nullable"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.nullable()]})numeric
Section titled “numeric”The field must be numeric.
request.validate({"field": "numeric"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.numeric()]})present
Section titled “present”The field must be present (may be empty).
request.validate({"field": "present"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.present()]})present_if
Section titled “present_if”The field must be present when another field has a given value.
request.validate({"field": "present_if"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.present_if()]})present_unless
Section titled “present_unless”The field must be present unless another field has a given value.
request.validate({"field": "present_unless"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.present_unless()]})present_with
Section titled “present_with”The field must be present when any of the given fields are present.
request.validate({"field": "present_with"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.present_with()]})present_with_all
Section titled “present_with_all”The field must be present when all given fields are present.
request.validate({"field": "present_with_all"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.present_with_all()]})prohibited
Section titled “prohibited”The field must not be present.
request.validate({"field": "prohibited"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.prohibited()]})prohibited_if
Section titled “prohibited_if”The field is prohibited when another field has a given value.
request.validate({"field": "prohibited_if"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.prohibited_if()]})prohibited_if_accepted
Section titled “prohibited_if_accepted”The field is prohibited when another field is accepted.
request.validate({"field": "prohibited_if_accepted"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.prohibited_if_accepted()]})prohibited_if_declined
Section titled “prohibited_if_declined”The field is prohibited when another field is declined.
request.validate({"field": "prohibited_if_declined"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.prohibited_if_declined()]})prohibited_unless
Section titled “prohibited_unless”The field is prohibited unless another field has a given value.
request.validate({"field": "prohibited_unless"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.prohibited_unless()]})prohibits
Section titled “prohibits”When this field is present, the listed fields must be missing.
request.validate({"field": "prohibits"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.prohibits()]})The field must match the given pattern.
request.validate({"field": r"regex:/^[a-z]+$/"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.regex("^[a-z]+$")]})required
Section titled “required”The field must be present and not empty.
request.validate({"field": "required"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.required()]})required_array_keys
Section titled “required_array_keys”A mapping must contain the listed keys.
request.validate({"field": "required_array_keys"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.required_array_keys()]})required_if
Section titled “required_if”The field is required when another field has a given value.
request.validate({"field": "required_if"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.required_if()]})required_if_accepted
Section titled “required_if_accepted”The field is required when another field is accepted.
request.validate({"field": "required_if_accepted"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.required_if_accepted()]})required_if_declined
Section titled “required_if_declined”The field is required when another field is declined.
request.validate({"field": "required_if_declined"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.required_if_declined()]})required_unless
Section titled “required_unless”The field is required unless another field has a given value.
request.validate({"field": "required_unless"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.required_unless()]})required_with
Section titled “required_with”The field is required when any of the given fields are present.
request.validate({"field": "required_with"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.required_with()]})required_with_all
Section titled “required_with_all”The field is required when all given fields are present.
request.validate({"field": "required_with_all"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.required_with_all()]})required_without
Section titled “required_without”The field is required when any of the given fields are missing.
request.validate({"field": "required_without"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.required_without()]})required_without_all
Section titled “required_without_all”The field is required when all given fields are missing.
request.validate({"field": "required_without_all"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.required_without_all()]})The field must match another field.
request.validate({"field": "same"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.same()]})The field size must equal the given value.
request.validate({"field": "size"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.size()]})sometimes
Section titled “sometimes”Only validate this field when it is present on the payload.
request.validate({"field": "sometimes"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.sometimes()]})starts_with
Section titled “starts_with”The field must start with one of the given values.
request.validate({"field": "starts_with"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.starts_with()]})string
Section titled “string”The field must be a string.
request.validate({"field": "string"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.string()]})timezone
Section titled “timezone”The field must be a valid timezone identifier.
request.validate({"field": "timezone"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.timezone()]})The field must be a valid ULID.
request.validate({"field": "ulid"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.ulid()]})unique
Section titled “unique”The value must be unique in the given database table/column.
request.validate({"field": "unique"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.unique()]})uppercase
Section titled “uppercase”The field must be uppercase.
request.validate({"field": "uppercase"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.uppercase()]})The field must be a valid URL.
request.validate({"field": "url"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.url()]})The field must be a valid UUID.
request.validate({"field": "uuid"})# orfrom almasix.validation import Rulerequest.validate({"field": [Rule.uuid()]})Custom rules
Section titled “Custom rules”smith make:rule UppercaseAttach with AfterValidator on a FormRequest field, or raise ValueError from
@field_validator.
Messages
Section titled “Messages”Override per call with messages= / attributes=, via FormRequest
messages() / attributes(), or publish the catalog:
smith lang:publishFailure envelope
Section titled “Failure envelope”{ "message": "The given data was invalid.", "status": 422, "errors": { "email": ["The email field must be a valid email address."] }}