Skip to main content

Module forms

Module forms 

Source
Expand description

Form parsing, validation, and HTML rendering.

§Two names, two layers (gaps2 #19)

  • FormValidate trait (the primitive, was Form): a struct implements this to provide a validate(&HashMap) method. The #[derive(Form)] macro emits it.
  • Form<T> extractor (the axum entry point): wraps the parsed-and-validated T in a Result<T, FormErrors>. Use in handler signatures: Form<ContactForm>.

The trait used to be called Form too, but that collided with the extractor type in the same module. The name with generics went to the extractor (matches axum::extract::Form<T> / axum::Json<T> shape) and the trait got the more descriptive FormValidate.

The piece that fills out the request-handling story between axum’s Form<T> extractor (raw key/value access) and a typed Rust struct (the application’s view of validated input). umbral’s first cut is the primitive layer richer form abstractions sit on top of.

§v1 shape

  • Field types per HTML input shape (TextField, IntegerField, EmailField, PasswordField, BooleanField, DateField, TimeField).
  • Field-level validators (Required, MinLength, MaxLength, [Pattern]) plus the convenience built-in checks each field type does for its own shape (e.g. EmailField runs Pattern against an email regex by default).
  • ValidationErrors is a map of field-name -> error messages. Forms accumulate every per-field error before returning, so the user sees the whole form’s problems at once.
  • HTML rendering: every field type has Field::render_html that emits a single <input> (or <textarea>) with the right type, name, value, and a required attribute when the field is required.

§v1 caps

  • No #[derive(Form)] macro. Users compose forms by hand: LoginForm::validate(&form_data) is a function that reads each field, accumulates errors, returns either the typed struct or Err(ValidationErrors). The derive lands as a future round.
  • No file uploads (multipart); HTML-only.
  • No localized error messages.

Structs§

EmailFormat
A simple “must look like an email” check. Not RFC 5322 strict — covers the 99% case (one @, non-empty local part, dot in the domain). Users with stricter needs swap in a real regex.
Field
A single form field: name + kind + validators. The field doesn’t own its parsed value; validate reads from the form-data map and pushes errors onto the accumulator.
Form
Axum extractor that validates a form body before the handler runs. On extraction success the wrapped result is Ok(T) (the validated struct); on validation failure the wrapped result is Err(FormErrors). The HTTP layer never rejects — handlers ALWAYS see a Form<T> and decide what to render via Self::into_result.
FormErrors
Form-validation error envelope. Wraps the ORM’s WriteError so every surface (REST 400 bodies, admin form spans, HTML form renders) sees the same structured shape. The template helper as_template_ctx produces the flat single-string-per-field view that most form templates ask for.
MaxLength
The field’s length (in characters) must be at most n.
MinLength
The field’s length (in characters) must be at least n.
RegexFormat
Regex-pattern validator — the catch-all shape for “value must match this format”. Reject the field with a user-supplied message when the pattern doesn’t match.
Required
The field must not be empty.
ValidationErrors
A collection of per-field validation errors. Forms accumulate these and return the whole map at once.

Enums§

InputKind
What HTML <input type> a field renders as. The form module uses this for render_html; it’s the same set the admin’s input_kind produces.
PkKind
How to parse a submitted FK id string. Resolved from the target model’s PK SqlType at render/validate time.

Constants§

PHONE_E164_PATTERN
E.164 international phone-number format — the standard the telecoms industry uses. +<country code><subscriber number> where the country code is 1-3 digits and the subscriber number is up to 14 digits, no spaces or punctuation.
URL_PATTERN
URL validator — http(s) only, requires a host, accepts an optional path/query/fragment. Conservative on purpose: ftp://, mailto:, etc. get rejected so a form that promises “URL” doesn’t end up persisting a non-web scheme.

Traits§

FormValidate
The contract a typed form satisfies. validate reads form data (a HashMap<String, String>, the natural shape after serde_urlencoded or axum’s Form extractor) and produces either the typed struct or a ValidationErrors map describing every problem at once.
Validator
One validator’s verdict.