elm-form-decoder
                                
                                
                                
                                    elm-form-decoder copied to clipboard
                            
                            
                            
                        Scalable way to decode user inputs into neat structure.
elm-form-decoder

Summary
Do you need form validation libraries? Wait! What you actually need would be form decoding library.
This library provides a scalable way to decode user inputs into neat structure. In the process, it also does validations.
What's form decoding?
Here is a blog post about form decoding and brief introduction to elm-form-decoder.
Example codes
Say that you are building an SNS for goats. (exclude the problem how they use keyboards by their two-fingered hands.)
First thing to do is declaring Goat type bellow representing a goat profile.
type alias Goat =
    { name : String
    , age : Int
    , horns : Int
    , contact : Contact
    , memo : Maybe String
    }
{-| Users (goats) can choose email or phone number for their contact info.
-}
type Contact
    = ContactEmail Email
    | ContactPhone PhoneNumber
Next, let's declare a special type for profile forms.
type alias Form
    { name : String
    , age : String
    , horns : String
    , contact : SelectContact
    , email : String
    , phone : String
    , memo : String
    }
{-| Represents active tab
-}
type SelectContact
    = SelectEmail
    | SelectPhone
Okay, it's time to decode the Form type into Goat type.
First thing to decode is declaring Error type.
type Error
    = NameRequired
    | AgeInvalidInt
    | AgeNegative
    | AgeRequired
    ...
Then make decoders for each field.
import Form.Decoder as Decoder
{-| Decoder for name field.
    import Form.Decoder as Decoder
    Decoder.run name ""
    --> Err [ NameRequired ]
    Decoder.run name "foo"
    --> Ok "foo"
-}
name : Decoder String Error String
name =
    Decoder.identity
        |> Decoder.assert (Decoder.minLength NameRequired 1)
{-| Decoder for name field.
    import Form.Decoder as Decoder
    Decoder.run age ""
    --> Err [ AgeRequired ]
    Decoder.run age "foo"
    --> Err [ AgeInvalidInt ]
    Decoder.run age "-30"
    --> Err [ AgeNegative ]
    Decoder.run age "30"
    --> Ok 30
-}
age : Decoder String Error Int
age =
    Decoder.identity
        |> Decoder.assert (Decoder.minLength AgeRequired 1)
        |> Decoder.pass (Decoder.int AgeInvalidInt)
        |> Decoder.assert (Decoder.minBound AgeNegative 0)
Decoder input err out indicates that the decoder consumes inputs of type input and converts it into out, while raising errors of type err.
These decoders also can be used to show errors on each input field.
ageErrorField : String -> Html msg
ageErrorField input =
    div
        [ class "errorField"
        ]
        <| List.map errorText
            (Decoder.errors age input)
errorText : String -> Html msg
errorText err =
    p
        [ class "errorText"
        ]
        [ text err
        ]
Next, lift decoders to consume Form type instead of String.
name_ : Decoder Form Error String
name_ =
    Decoder.lift .name name
age_ : Decoder Form Error Int
age_ =
    Decoder.lift .age age
Finally, build up decoder for Form.
form : Decoder Form Error Goat
form =
    Decoder.top Goat
        |> Decoder.field name_
        |> Decoder.field age_
        |> Decoder.field horns_
        |> Decoder.field contact_
        |> Decoder.field memo_
Wow, it's amazing!
This decoder enables you to:
- Validate user inputs
 - Create 
Goattype from user inputs 
Real world examples
Here's real world examples using elm-form-decoder in sample directory (demo).