dataval/form
Compose a form from multiple fields.
A form is a function that takes values as a list of tuples
#(field_name, value) 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
State produced while validating a form.
valueis built incrementallyerrorsmaps field names to their errors
pub type FormState(a, custom) {
FormState(
value: a,
errors: dict.Dict(String, List(field.FieldError(custom))),
)
}
Constructors
-
FormState( value: a, errors: dict.Dict(String, List(field.FieldError(custom))), )
Values
pub fn create(
value: a,
) -> fn(dict.Dict(String, String)) -> FormState(a, custom)
Finish a form pipeline by returning a successfully built value.
This is the last step of a form. It produces a form with no errors and no remaining fields to validate.
Example
pub type CreateUser {
CreateUser(age: Int, name: String)
}
fn create_user_form() {
use age <- form.field(
field.new("age")
|> field.with_parser(parser.int)
)
use name <- form.field(
field.new("name")
|> field.add_validator(validator.str_min(2))
)
form.create(CreateUser(age:, name:))
}
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.