Since JSON values are not known until runtime there is no way of checking them at compile time. This means that there is a possibility a decoding operation can not be successfully completed.
In that case there are two possible solutions:
Maybe
valueIn this module these two options are represented by require
, optional
, and
attempt
.
require
fails if either the field is missing or is the wrong type.optional
succeeds with a Nothing
if field is missing, but fails if the
field exists and is the wrong type.attempt
always succeeds with a Maybe
value.require : String -> Json.Decode.Decoder a -> (a -> Json.Decode.Decoder b) -> Json.Decode.Decoder b
Decode required fields.
Example:
import Json.Decode as Decode exposing (Decoder)
user : Decoder User
user =
require "id" Decode.int <| \id ->
require "name" Decode.string <| \name ->
Decode.succeed
{ id = id
, name = name
}
In this example the decoder will fail if:
"id"
or "name"
are missing. If the object contains other fields
they are ignored and will not cause the decoder to fail."id"
is not an Int
."name"
is not a String
.requireAt : List String -> Json.Decode.Decoder a -> (a -> Json.Decode.Decoder b) -> Json.Decode.Decoder b
Decode required nested fields. Works the same as require
but on nested fieds.
import Json.Decode as Decode exposing (Decoder)
blogPost : Decoder BlogPost
blogPost =
require "id" Decode.int <| \id ->
require "title" Decode.string <| \title ->
requireAt ["author", "name"] Decode.string <| \authorName ->
Decode.succeed
{ id = id
, title = title
, author = authorName
}
optional : String -> Json.Decode.Decoder a -> (Maybe a -> Json.Decode.Decoder b) -> Json.Decode.Decoder b
Decode optional fields.
If the decode succeeds you get a Just value
. If the field is missing you get
a Nothing
.
Example:
import Json.Decode as Decode exposing (Decoder)
name : Decoder Name
name =
require "first" Decode.string <| \first ->
optional "middle" Decode.string <| \maybeMiddle ->
require "last" Decode.string <| \last ->
Decode.succeed
{ first = first
, middle = Maybe.withDefault "" middle
, last = last
}
The outcomes of this example are:
"middle"
is a string, maybeMiddle
will be Just string
"middle"
is something else, the decoder will fail."middle"
is missing, maybeMiddle
will be Nothing
Note that optional is not the same as nullable. If a field must exist but can
be null, use require
and
Decode.nullable
instead:
require "field" (Decode.nullable Decode.string) <| \field ->
If a field is both optional and nullable attempt
is a better
option than using optional
with Decode.nullable
, as attempt
gives you a
Maybe a
compared to the Maybe (Maybe a)
that optional
with nullable
would give:
attempt "field" Decode.string <| \maybeField ->
optionalAt : List String -> Json.Decode.Decoder a -> (Maybe a -> Json.Decode.Decoder b) -> Json.Decode.Decoder b
Decode optional nested fields. Works the same was as optional
but on nested fields.
attempt : String -> Json.Decode.Decoder a -> (Maybe a -> Json.Decode.Decoder b) -> Json.Decode.Decoder b
Decode fields that may fail.
Always decodes to a Maybe
value and never fails.
Example:
import Json.Decode as Decode exposing (Decoder)
person : Decoder Person
person =
require "name" Decode.string <| \name ->
attempt "weight" Decode.int <| \maybeWeight ->
Decode.succeed
{ name = name
, weight = maybeWeight
}
In this example the maybeWeight
value will be Nothing
if:
weight
field is missing.weight
field is not an Int
.In this case there is no difference between a field being null
or missing.
attemptAt : List String -> Json.Decode.Decoder a -> (Maybe a -> Json.Decode.Decoder b) -> Json.Decode.Decoder b
Decode nested fields that may fail. Works the same way as attempt
but on nested fields.