gege251 / elm-validator-pipeline / Validator

Validators work in a pipeline (or applicative functor style), similar to the one used in json-decode-pipeline. Values are checked and applied to a function one by one. If everything goes well, the pipeline returns an Ok result, otherwise it will return all the errors.

Ok ValidatedForm
    |> validate (String.notEmpty "name is required") form.name
    |> validate (String.isEmail "email is invalid") form.email
    |> validateMany
        [ String.hasLetter "password needs to contain letters"
        , String.hasNumber "password needs to contain numbers"
        ]
        form.password
    |> noCheck form.message
    |> checkOnly (Bool.isTrue "you need to approve") form.approved

In the example above, I used Strings as errors, but they can be any type you want. Errors will be accumulated from top to bottom into a List. If you want to know exactly which field had errors, take a look at the Validator.Named module.


type alias Validated error value =
Result (List error) value

Validated is simply an alias for a Result type, with errors as a list of your type, which can be a string, or any custom error type. You will not need to work with some exotic type, this is only here for convenience.


type alias Validator error a b =
a -> Validated error b

Validator is function, that checks a value, and returns a Validated. Some validators can change the type of the value of type a to type b.

Pipeline functions

noCheck : a -> Validated x (a -> b) -> Validated x b

Apply a value to the pipeline without perfoming any checks.

validate : Validator x a b -> a -> Validated x (b -> c) -> Validated x c

Validate a value and apply it to the pipeline.

checkOnly : Validator x a b -> a -> Validated x c -> Validated x c

Validate a value without applying it to the pipeline.

validateMany : List (Validator x a a) -> a -> Validated x (a -> b) -> Validated x b

Validate a value using a list of validators. Checks are performed from left to right, and will stop on the first failure, returning only the first error.

Note: validateMany is a convenience function onver validate << many

validateAll : List (Validator x a a) -> a -> Validated x (a -> b) -> Validated x b

Validate a value using a list of validators. Checks are performed from left to right, and will return all errors.

Note: validateAll is a convenience function onver validate << all

Helpers

map : (b -> c) -> Validator x a b -> a -> Validated x c

Map a function into the happy path.

andThen : Validator x b c -> Validator x a b -> a -> Validated x c

Chain together validators. Only the first error will be returned on failure.

Note: validateMany and validateAll provide a cleaner interface for most use cases.

mapErrors : (x -> y) -> Validator x a b -> a -> Validated y b

Transfrom error values.

many : List (Validator x a a) -> Validator x a a

Compose a list of validators for a single value. Checks are performed from left to right, and will stop on the first failure, returning only the first error.

all : List (Validator x a a) -> Validator x a a

Compose a list of validators for a single value. Checks are performed from left to right, and will return all errors.

customValidator : x -> (a -> Basics.Bool) -> a -> Validated x a

Create a custom validator, using a predicate function.