dataval/form

Compose a form from multiple fields.

A form is a function that takes a raw dictionary of strings and returns either a successfully built value or a map of field errors.

Example

import dataval/field
import dataval/form
import dataval/parser
import dataval/validator
import gleam/dict

pub type CreateUser {
  CreateUser(age: Int, name: String)
}

fn age_field() {
  field.new("age")
  |> field.with_parser(parser.int)
  |> field.add_validator(validator.int_min(18))
}

fn name_field() {
  field.new("name")
  |> field.add_validator(validator.str_min(2))
}

pub fn create_user_form() {
  use age <- form.field(age_field())
  use name <- form.field(name_field())
  form.create(CreateUser(age:, name:))
}

pub fn main() {
  let user_form = create_user_form()

  assert Ok(CreateUser(20, "Toto"))
    == form.validate(user_form, [#("age", "20"), #("name", "Toto")])

  assert Error(
      dict.from_list([
        #("age", [field.IntTooSmall(18)]),
        #("name", [field.StringLengthTooShort(2)]),
      ]),
    )
    == form.validate(user_form, [#("age", "16"), #("name", "a")])
}

Details

Each form.field looks up the field name in the raw input, runs its validators and parser, and passes the parsed value to the continuation.

Missing fields are treated as empty strings. If any field has errors, validate returns Error with a dictionary of field names to errors.

Types

pub type Form(a, custom) =
  fn(dict.Dict(String, String)) -> FormState(a, custom)
pub type FormState(a, custom) {
  FormState(
    value: a,
    errors: dict.Dict(String, List(field.FieldError(custom))),
  )
}

Constructors

Values

pub fn create(
  value: a,
) -> fn(dict.Dict(String, String)) -> FormState(a, custom)
pub fn field(
  form_field: field.Field(a, custom),
  continuation: fn(a) -> fn(dict.Dict(String, String)) -> FormState(
    b,
    custom,
  ),
) -> fn(dict.Dict(String, String)) -> FormState(b, custom)

Attach a field to the form. Missing fields in the raw input are treated as empty strings.

pub fn validate(
  form: fn(dict.Dict(String, String)) -> FormState(a, custom),
  raw: List(#(String, String)),
) -> Result(a, dict.Dict(String, List(field.FieldError(custom))))

Run the form against raw input. Returns Ok(value) only if every field is valid.

Search Document