The Safest Headless Drupal 8 with Elm

Amitai Burtein // @amitaibu

Elm

Generate JavaScript with great performance and no runtime exceptions

module Counter exposing (..)

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)

-- MODEL

type alias Model =
    Int

emptyModel : Model
emptyModel =
    0

-- UPDATE

type Msg
    = Decrement
    | Increment


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Decrement ->
            ( model - 1
            , Cmd.none
            )

        Increment ->
            ( model + 1
            , Cmd.none
            )

-- VIEW

view : Model -> Html Msg
view model =
    div []
        [ button [ onClick Decrement ] [ text "-" ]
        , div [] [ text (toString model) ]
        , button [ onClick Increment ] [ text "+" ]
        ]

            


type alias Recipe =
    { title: String
    , image : String
    , preparationTime: Int
    }

            

Types 101

              
type Bool = False | True
              
        
                
type DifficultyLevel
    = Easy
    | Normal
    | Hard

type alias Recipe =
    { title: String
    , image : String
    , preparationTime: Int
    , difficultyLevel : DifficultyLevel
    }

                
            
If something can go wrong, it will
Murphy's law
              
type alias Recipe =
    { title: String
    , ..
    , isCarnivore : Bool
    , isVegetarian : Bool
    , isVegan : Bool
    }

iAmConfused : Recipe
iAmConfused =
    { title = "A vegan steak?!"
    , ..
    , isCarnivore = True
    , isVegetarian = False
    , isVegan = True
    }

              
        
              
type DietaryRestriction
    = Carnivore
    | Vegetarian
    | Vegan

type alias Recipe =
    { title: String
    , ..
    , dietaryRestriction : DietaryRestriction
    }

thatIsBetter : Recipe
thatIsBetter =
    { title = "A vegan steak!"
    , ..
    , dietaryRestriction = Vegan
    }

              
        
                
type alias Recipe =
    { title: String
    , ..
    , preparationTime : Int
    , cookingTime : ?
    }
                

                
{ title: "foo"
, preparationTime: 10,
, cookingTime: null
}
                
            

!empty ?

                
type alias Recipe =
    { title: String
    , ..
    , preparationTime : Int
    , cookingTime : Maybe Int
    }

iceCream : Recipe
iceCream =
    { title = "Ice Cream"
    , ..
    , preparationTime = 10
    , cookingTime = Nothing
    }

pizza : Recipe
pizza =
    { title = "Pizza"
    , ..
    , preparationTime = 10
    , cookingTime = Just 15
    }
                

            
                
type PreparationTimes
    = NoPreparation
    | Preparation Int (Maybe Int)


type alias Recipe =
    { title: String
    , ..
    , preparationTimes : PreparationTimes
    }

iceCreamFromRefrigerator : Recipe
iceCreamFromRefrigerator =
    { title = "Ice Cream for lazy people"
    , ..
    , preparationTimes = NoPreparation
    }

pizza : Recipe
pizza =
    { title = "Pizza"
    , ..
    , preparationTimes = Preparation 10 (Just 15)
    }
                

            
                
type PreparationTimes
    = NoPreparation
    | Preparation Int (Maybe Int)


viewPreparationTimes : Recipe -> Html msg
viewPreparationTimes recipe =
    case recipe.preparationTimes of
        NoPreparation ->
            text "No preparation required"

        Preparation time Nothing ->
            text "Takes " ++ (String.fromInt time) ++
                    "minutes, but no cooking"

        Preparation time (Just cookingTime) ->
            text "Takes " ++ (String.fromInt time) ++
                    " minutes and " ++ (String.fromInt cookingTime) ++
                    " minutes for cooking"
                

            
How to model the states of an HTTP request?
                
type WebData a
    = NotAsked
    | Loading
    | Failure Http.Error
    | Success a

type alias Recipe =
    { title: String
    , ..
    , preparationTimes : WebData PreparationTimes
    }


viewPreparationTimes : Recipe -> Html msg
viewPreparationTimes recipe =
    case recipe.preparationTimes of
        Failure error ->
            text "Error loading"

        Success preparationTimes ->
            case preparationTimes of
                NoPreparation ->
                    text "No preparation required"

                -- ..
        _ ->
            text "Loading ..."

                
            
                

type alias Ingredient =
    { name: String
    , price : Int
    }

type alias Recipe =
    { title: String
    , ..
    , ingredients : List Ingredient
    }

                
            
map & fold
                

viewIngredients : Recipe -> Html msg
viewIngredients recipe =
    ul
        []
        [ List.map
              ( \ingredient -> li [] [ text ingredient.name ] )
              recipe.ingredients
        ]

viewTotalPrice : Recipe -> Html msg
viewTotalPrice recipe =
    List.foldl
        ( \ingredient accum -> accum + ingredient.price )
        0
        recipe.ingredients