Skip to content

dwayne/elm-validation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

elm-validation

Composable data validation with error accumulation.

An example

It shows how you might validate form data for a user.

type alias User =
    { name : Name
    , email : Email
    , age : Age
    , password : Password
    }


type alias UserForm =
    { name : String
    , email : String
    , age : String
    , password : String
    }


toUser : UserForm -> Validation String User
toUser { name, email, age, password } =
    V.map4 User
        (validateName name)
        (validateEmail email)
        (validateAge age)
        (validatePassword password)


validateName : String -> Validation String Name
validateName =
    Name.fromString
        >> V.fromMaybe "A name is required"


validateEmail : String -> Validation String Email
validateEmail =
    Email.fromString
        >> Result.mapError
            (\e ->
                case e of
                    Email.Required ->
                        "An email is required"

                    Email.Invalid s ->
                        "\"" ++ s ++ "\"" ++ " is not a valid email"
            )
        >> V.fromResult


validateAge : String -> Validation String Age
validateAge =
    Age.fromString
        >> Result.mapError
            (\e ->
                case e of
                    Age.Required ->
                        "An age is required"

                    Age.InvalidString s ->
                        "\"" ++ s ++ "\"" ++ " is not a positive integer"

                    Age.InvalidInt n ->
                        String.fromInt n ++ " is not a valid age"

                    Age.TooYoung n ->
                        "You're too young: " ++ String.fromInt n

                    Age.TooOld n ->
                        "You're too old: " ++ String.fromInt n
            )
        >> V.fromResult


validatePassword : String -> Validation String Password
validatePassword =
    Password.fromString
        >> Result.mapError
            (\e ->
                case e of
                    Password.Required ->
                        "A password is required"

                    Password.TooShort n ->
                        "The password must be at least 8 characters: " ++ String.fromInt n

                    Password.TooLong n ->
                        "The password must be at most 20 characters: " ++ String.fromInt n

                    Password.MissingRequiredChars ->
                        "The password MUST contain at least one of each of the following: lower case ASCII character, upper case ASCII character, digit, and a special character ($ or %)"
            )
        >> V.fromResult

You can find the full source code for the example in the example/ directory.

validateName

validateName "" == fail "A name is required"

validateName "Dave MacQueen"
-- Success (Name "Dave MacQueen")

validateEmail

validateEmail "" == fail "An email is required"
validateEmail "cs.uchicago.edu" == fail "\"cs.uchicago.edu\" is not a valid email"

validateEmail "macqueen@cs.uchicago.edu"
-- Success (Email "macqueen@cs.uchicago.edu")

validateAge

validateAge "" == fail "An age is required"
validateAge "forty" == fail "\"forty\" is not a positive integer"
validateAge "-1" == fail "-1 is not a valid age"
validateAge "10" == fail "You're too young: 10"
validateAge "65" == fail "You're too old: 65"

validateAge "49"
-- Success (Age 49)

validatePassword

validatePassword "" == fail "A password is required"
validatePassword "1234567" == fail "The password must be at least 8 characters: 7"
validatePassword "123456789012345678901" == fail "The password must be at most 20 characters: 21"
validatePassword "12345678" == fail "The password MUST contain at least one of each of the following: lower case ASCII character, upper case ASCII character, digit, and a special character ($ or %)"

validatePassword "12345aB$"
-- Success (Password "12345aB$")

toUser

toUser
    { name = ""
    , email = "macqueen@cs.uchicago.edu"
    , age = "10"
    , password = "1234567"
    }
    == failWithErrors "A name is required" [ "You're too young: 10", "The password must be at least 8 characters: 7" ]

Public API

A high-level overview of the public API.

type Validation

-- Construct

succeed : a -> Validation e a
fail : e -> Validation e a
failWithErrors : e -> List e -> Validation e a
fromResult : Result e a -> Validation e a
fromMaybe : e -> Maybe a -> Validation e a

-- Query

isValid : Validation e a -> Bool
isInvalid : Validation e a -> Bool

-- Map

map : (a -> value) -> Validation x a -> Validation x value
map2 : (a -> b -> value) -> Validation x a -> Validation x b -> Validation x value
map3 : (a -> b -> c -> value) -> Validation x a -> Validation x b -> Validation x c -> Validation x value
map4 : (a -> b -> c -> d -> value) -> Validation x a -> Validation x b -> Validation x c -> Validation x d -> Validation x value
map5 : (a -> b -> c -> d -> e -> value) -> Validation x a -> Validation x b -> Validation x c -> Validation x d -> Validation x e -> Validation x value
mapError : (x -> y) -> Validation x a -> Validation y a

-- Apply

apply : Validation x a -> Validation x (a -> b) -> Validation x b

-- Chain

andThen : (a -> Validation x b) -> Validation x a -> Validation x b

-- Convert

withDefault : a -> Validation e a -> a
toResult : Validation e a -> Result (List e) a
toMaybe : Validation e a -> Maybe a

-- Handle Errors

firstError : Validation e a -> Maybe e
lastError : Validation e a -> Maybe e
allErrors : Validation e a -> List e

About

Composable data validation with error accumulation.

Topics

Resources

License

Stars

Watchers

Forks