GET / HTTP/1.1
<html>
<head>...</head>
<body>
<h1>Wonderfull site!</h1>
<p>Hello</p>
</body>
</html>
GET / HTTP/1.1
<html>
<head>...</head>
<body>
<h1>Wonderfull site!</h1>
<p>Hello</p>
</body>
</html>
GET /users/ HTTP/1.1
<html>
<head>...</head>
<body>
<h1>Wonderfull site!</h1>
<ul>
<li>Arthur</li>
<li>Ford</li>
</ul>
</body>
</html>
GET /userlist/ HTTP/1.1
Accept: application/json
HTTP/1.1 200 OK
Content-Length: 130
[ { "name": "Marvin",
"kind": "Robot" },
{ "name": "Zaphod",
"kind": "ET"},
{ "name": "Arthur",
"kind": "human"}
]
GET /userlist/ HTTP/1.1
Accept: application/json
HTTP/1.1 200 OK
Content-Length: 130
[ { "name": "Marvin",
"kind": "Robot" },
{ "name": "Zaphod",
"kind": "ET"},
{ "name": "Arthur",
"kind": "human"}
]
Display those data with JS (via Elm).
"AJAX"
GET /userlist/ HTTP/1.1
Accept: application/json
A
B
C
D
E
F
G
H
I
Only data, not tied to JavaScript
15
15.2
-54
5e10
""
"Hello world"
"😊"
15
15.2
-54
5e10
15
15.2
-54
5e10
true
false
""
"Hello world"
"😊"
15
15.2
-54
5e10
""
"Hello world"
"😊"
true
false
null
[5, 42, "hello", null]
[5, 42, "hello", null]
{ "name": "Arthur",
"kind": "human"
}
[5, 42, "hello", null]
[ { "name": "Marvin",
"kind": "Robot" },
{ "name": "Zaphod",
"kind": "ET"},
{ "name": "Arthur",
"kind": "human"}
]
{ "name": "Arthur",
"kind": "human"
}
{ "server": "Heart-of-gold",
"arenas": [
{ "game": "pong",
"players": [
{ "name": "Arthur",
"score": 5 },
{ "name": "Zaphod",
"score": 2 }
]
}
]
}
getDay : Int -> Maybe String
getDay dayNumber = case dayNumber of
0 -> Just "Monday"
1 -> Just "Tuesday"
...
6 -> Just "Sunday"
_ -> Nothing
res : Int
res = case (String.toInt "42") of
Just x ->
2 * x
Nothing ->
0
type Result error value
= Err error
| Ok value
type Result error value
= Err error
| Ok value
Can be any type
type Result error value
= Err error
| Ok value
type Maybe a
= Nothing
| Just a
type Result error value
= Err error
| Ok value
type Maybe a
= Nothing
| Just a
type Result error value
= Err error
| Ok value
toBool : String -> Result String Bool
toBool s = case s of
"true" -> Ok True
"false" -> Ok False
"42" -> Err "Nice try!"
_ -> Err ("not a bool: " ++ s)
type Result error value
= Err error
| Ok value
toBool : String -> Result String Bool
toBool s = case s of
"true" -> Ok True
"false" -> Ok False
"42" -> Err "Nice try!"
_ -> Err ("not a bool: " ++ s)
Error messages,
impossible with Maybe
type Result error value
= Err error
| Ok value
toBool : String -> Result String Bool
toBool s = case s of
"true" -> Ok True
"false" -> Ok False
"42" -> Err "Nice try!"
_ -> Err ("not a bool: " ++ s)
type Result error value
= Err error
| Ok value
toBool : String -> Result String Bool
toBool s = case s of
"true" -> Ok True
"false" -> Ok False
"42" -> Err "Nice try!"
_ -> Err ("not a bool: " ++ s)
kineticE : Float -> Float -> Result String Float
kineticE mass speed =
...
import Json.Decode as Decode exposing (int)
Decode.decodeString int "4" == Ok 4
Decode.decodeString int "hello" == Err ...
Decode.decodeString int "1 + 2" == Err ...
Decode.decodeString :
Decoder val
-> String
-> Result Error val
Decode.decodeString :
Decoder val
-> String
-> Result Error val
import Json.Decode as Decode exposing (int)
Decode.decodeString int "4" == Ok 4
Decode.decodeString int "hello" == Err ...
Decode.decodeString int "1 + 2" == Err ...
Decode.decodeString :
Decoder val
-> String
-> Result Error val
The type we want to decode to
import Json.Decode as Decode exposing (int)
Decode.decodeString int "4" == Ok 4
Decode.decodeString int "hello" == Err ...
Decode.decodeString int "1 + 2" == Err ...
Decode.decodeString :
Decoder val
-> String
-> Result Error val
The decoder, describing how to transform a JSON value into
an Elm value of type "val"
import Json.Decode as Decode exposing (int)
Decode.decodeString int "4" == Ok 4
Decode.decodeString int "hello" == Err ...
Decode.decodeString int "1 + 2" == Err ...
Decode.decodeString :
Decoder val
-> String
-> Result Error val
The JSON we want to decode:
import Json.Decode as Decode exposing (int)
Decode.decodeString int "4" == Ok 4
Decode.decodeString int "hello" == Err ...
Decode.decodeString int "1 + 2" == Err ...
Decode.decodeString :
Decoder val
-> String
-> Result Error val
Either:
import Json.Decode as Decode exposing (int)
Decode.decodeString int "4" == Ok 4
Decode.decodeString int "hello" == Err ...
Decode.decodeString int "1 + 2" == Err ...
import Json.Decode as Decode exposing (Decoder, int)
Decode.decodeString int "4" == Ok 4
Decode.decodeString int "hello" == Err ...
Decode.decodeString int "1 + 2" == Err ...
int : Decoder Int
Decode.decodeString :
Decoder val
-> String
-> Result Error val
import Json.Decode as Decode exposing (Decoder, int)
Decode.decodeString int "4" == Ok 4
Decode.decodeString int "hello" == Err ...
Decode.decodeString int "1 + 2" == Err ...
int : Decoder Int
Decode.decodeString :
Decoder Int
-> String
-> Result Error Int
import Json.Decode as Decode exposing
(Decoder, decodeString)
Decode.int : Decoder Int
decodeString Decode.int "4" == Ok 4
Decode.string : Decoder String
decodeString Decode.string "\"hey\"" == Ok "hey"
decodeString Decode.string "3.14" == Err ...
decodeString Decode.string "{ \"hello\": 42 }" == Err ...
Decode.bool : Decoder Bool
decodeString bool "true" == Ok True
decodeString bool "42" == Err ...
import Json.Decode as Decode exposing
(Decoder, decodeString, list, int, bool)
Decode.list : Decoder a -> Decoder (List a)
decodeString (list int) "[1,2,3]" == Ok [1,2,3]
decodeString (list bool) "[true,false]" == Ok [True,False]
decodeString (list int) "[true,false]" == Err ...
decodeString (list bool) "[1,2,3]" == Err ...
decodeString (list int) "42" == Err ...
42
Starting point :
https://ellie-app.com/6H9QpXpnJXka1
[42, 10, 52]
Starting point :
https://ellie-app.com/6H9Ry2yg45Wa1
[[1, 2, 3], [42, 6, 9], [5,1]]
Starting point :
https://ellie-app.com/6H9PfrTdj3ka1
import Json.Decode as Decode exposing
(Decoder, decodeString, field, int, string)
json = "{ \"username\": \"Tom\", \"age\": 42 }"
Decode.field : String -> Decoder a -> Decoder a
decodeString (field "username" string) json == Ok "Tom"
decodeString (field "age" int) json == Ok 42
decodeString (field "age" string) json == Err ...
decodeString (field "username" int) json == Err ...
{ "name": "Ford", "score": 42 }
Starting point :
https://ellie-app.com/6KKSDtSCM6Ma1
import Json.Decode as Decode exposing
(Decoder, decodeString, field, int, string, map2)
json = "{ \"username\": \"Tom\", \"age\": 42 }"
type alias User = { name : String, age : Int }
userDecoder : Decoder User
userDecoder =
map2 User
(field "username" string)
(field "age" int)
decodeString userDecoder json
== Ok { name = "Tom", age = 42 }
import Json.Decode as Decode exposing
(Decoder, decodeString, field, int, string, map2)
json = "{ \"username\": \"Tom\", \"age\": 42 }"
type alias User = { name : String, age : Int }
userDecoder : Decoder User
userDecoder =
map2 User
(field "username" string)
(field "age" int)
decodeString userDecoder json
== Ok { name = "Tom", age = 42 }
Order of the fields matters!
import Json.Decode as Decode
Decode.decodeString userDecoder
"""{ "username": "Tom", "age": 42, "city": "NY" }"""
type alias User =
{ name : String
, age : Int
}
userDecoder: Decoder User
-- produces:
Ok { name : "Tom", age : 42 }
import Json.Decode as Decode
Decode.decodeString userDecoder
"""{ "username": "Tom", "age": 42, "city": "NY" }"""
Decode.decodeString userDecoder
"""{ "username": "Tom", "nbYears": 42, "city": "NY" }"""
-- produces:
Ok { name : "Tom", age : 42 }
-- produces:
Err ...
{
"name": "Ford",
"score": 42,
"favorite_color": "red",
"from": "Betelgeuse"
}
Starting point :
type alias Player =
{ name : String
, score: Int
, origin: String
}
{
"players": [{
"name": "Ford",
"score": 42,
"favorite_color": "red",
"from": "Betelgeuse"
}],
"games": ["pong", "tetris"]
}
Starting point :
type alias Board =
{ players: List Player
, games : List String
}
-- Player is the same
-- as previously
initialModel : Model
initialModel =
{ count = 0 }
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
{ model | count = model.count + 1 }
view : Model -> Html Msg
view model =
div []
[ button [ onClick Increment ] [ text "+1" ]
, text <| String.fromInt model.count
]
init : Model
view : Model -> Html Msg
update : Msg -> Model -> Model
GET /userlist/ HTTP/1.1
Accept: application/json
HTTP/1.1 200 OK
Content-Length: 130
[ { "name": "Marvin",
"kind": "Robot" },
{ "name": "Zaphod",
"kind": "ET"},
{ "name": "Arthur",
"kind": "human"}
]
init : Model
view : Model -> Html Msg
update : Msg -> Model -> Model
init : flags -> (Model, Cmd Msg)
view : Model -> Html Msg
update : Msg -> Model -> (Model, Cmd Msg)
1. Hey Runtime,
please perform an HTTP request!
3. Ok, here is the response
2.
1. A new model indicating "Loading"
4. A new model with loaded data
type Result error value
= Err error
| Ok value
-- in the module Http
type Error
= BadUrl String
| Timeout
| NetworkError
| BadStatus Int
| BadBody String
showResp : Result Http.Error (List User)
-> String
showResp resp =
case resp of
Ok users ->
showUsers users
Err _ ->
"An error occured, I'm sory!"
showResp : Result Http.Error (List User)
-> String
showResp resp =
case resp of
Ok users ->
showUsers users
Err _ ->
"An error occured, I'm sory!"
showResp : Result Http.Error (List User)
-> String
showResp resp =
case resp of
Ok users ->
showUsers users
Err _ ->
"An error occured, I'm sory!"
The lazy way...
showResp : Result Http.Error (List User)
-> String
showResp resp =
case resp of
Ok users ->
showUsers users
Err Http.NetworkError ->
"You seem disconnected."
Err Http.Timeout ->
"The server is too slow."
Err _ ->
"An error occured, I'm sory!"
GET /userlist/ HTTP/1.1
Accept: application/json
HTTP/1.1 200 OK
Content-Length: 130
[ { "name": "Marvin",
"kind": "Robot" },
{ "name": "Zaphod",
"kind": "ET"},
{ "name": "Arthur",
"kind": "human"}
]
type Msg
= LoadUserClicked
| GotUsers (Result Http.Error (List User))
<<Hey Runtime! Fetch data from "/userlist/" and
when you are done, issue a 'GotUsers'
message with the result and convert the data
with 'usersDecoder'!>>
type Msg
= LoadUserClicked
| GotUsers (Result Http.Error (List User))
Cmd Msg
<<Hey Runtime! Fetch data from "/userlist/" and
when you are done, issue a 'GotUsers'
message with the result and convert the data
with 'usersDecoder'!>>
type Msg
= LoadUserClicked
| GotUsers (Result Http.Error (List User))
Cmd Msg
Msg
Json decoder
<<Hey Runtime! Fetch data from "/userlist/" and
when you are done, issue a 'GotUsers'
message with the result and convert the data
with 'usersDecoder'!>>
type Msg
= LoadUserClicked
| GotUsers (Result Http.Error (List User))
init : flags -> (Model, Cmd Msg)
view : Model -> Html Msg
update : Msg -> Model -> (Model, Cmd Msg)
Cmd Msg
Msg
Http.get { url = "/userlist/"
, expect = Http.expectJson
GotUsers
usersDecoder
}
Json decoder
type Msg
= LoadUserClicked
| GotUsers (Result Http.Error (List User))
type Msg
= GotUsers (Result Http.Error (List User))
| LoadUserClicked
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
LoadUserClicked ->
( model -- model not changed
, Http.get
{ url = "/userlist/"
, expect = Http.expectJson GotUsers usersDecoder
}
)
GotUsers result ->
( { model | users = result }
, Cmd.none -- no command to perform!
)