A way to turn Json values into Elm values. A Decoder a represents a
decoding operation that will either produce a value of type a, or fail.
Extract a string.
-- ["John","Doe"]
name : Decoder (String, String)
name =
tuple2 (,) string stringExtract an integer.
-- { ... age: 42 ... }
age : Decoder Int
age =
"age" := intExtract a float.
-- [ 6.022, 3.1415, 1.618 ]
numbers : Decoder (List Float)
numbers =
list floatExtract a boolean.
-- { ... checked: true ... }
checked : Decoder Bool
checked =
"checked" := trueDecode null as the value given, and fail otherwise. Primarily useful for creating other decoders.
numbers : Decoder [Int]
numbers =
list (oneOf [ int, null 0 ])This decoder treats null as Nothing, and otherwise tries to produce a
Just.
nullOr : Decoder a -> Decoder (Maybe a)
nullOr decoder =
oneOf
[ null Nothing
, map Just decoder
]Extract a List from a JS array.
-- [1,2,3,4]
numbers : Decoder [Int]
numbers =
list intExtract an Array from a JS array.
-- [1,2,3,4]
numbers : Decoder (Array Int)
numbers =
array intHandle an array with exactly one element.
authorship : Decoder String
authorship =
oneOf
[ tuple1 (\author -> "Author: " ++ author) string
, list string |> map (\authors -> "Co-authors: " ++ String.join ", " authors)
]Handle an array with exactly two elements. Useful for points and simple pairs.
-- [3,4] or [0,0]
point : Decoder (Float,Float)
point =
tuple2 (,) float float
-- ["John","Doe"] or ["Hermann","Hesse"]
name : Decoder Name
name =
tuple2 Name string string
type alias Name = { first : String, last : String }Handle an array with exactly three elements.
-- [3,4,5] or [0,0,0]
point3D : Decoder (Float,Float,Float)
point3D =
tuple3 (,,) float float floatDecode an object if it has a certain field.
nameAndAge : Decoder (String,Int)
nameAndAge =
object2 (,)
("name" := string)
("age" := int)
optionalProfession : Decoder (Maybe String)
optionalProfession =
maybe ("profession" := string)Access a nested field, making it easy to dive into big structures. This is
really a helper function so you do not need to write (:=) so many times.
-- object.target.value = 'hello'
value : Decoder String
value =
at ["target", "value"] stringIt is defined as
at fields decoder =
List.foldr (:=) decoder fieldsUse two different decoders on a JS value. This is nice for extracting multiple fields from an object.
point : Decoder (Float,Float)
point =
object2 (,)
("x" := float)
("y" := float)Use three different decoders on a JS value. This is nice for extracting multiple fields from an object.
type alias Job = { name : String, id : Int, completed : Bool }
point : Decoder Job
point =
object3 Job
("name" := string)
("id" := int)
("completed" := bool)Turn any object into a list of key-value pairs. Fails if any key can't be decoded with the given decoder.
-- { tom: 89, sue: 92, bill: 97, ... }
grades : Decoder (List (String, Int))
grades =
keyValuePairs intTurn any object into a dictionary of key-value pairs.
-- { mercury: 0.33, venus: 4.87, earth: 5.97, ... }
planetMasses : Decoder (Dict String Int)
planetMasses =
dict floatExtract a Maybe value, wrapping successes with Just and turning any
failure in Nothing. If you are expecting that a field can sometimes be null,
it's better to check for it explictly, as this function will swallow
erros from ill-formed JSON.
The following code decodes JSON objects that may not have a profession field.
-- profession: Just "plumber"
-- { name: "Tom", age: 31, profession: "plumber" }
-- profession: Nothing
-- { name: "Sue", age: 42 }
-- { name: "Amy", age: 27, profession: null }
-- { name: "Joe", age: 36, profession: ["something", "unexpected"] }
type alias Person =
{ name : String
, age : Int
, profession : Maybe String
}
person : Decoder Person
person =
object3 Person
("name" := string)
("age" := int)
(maybe ("profession" := string))Try out multiple different decoders. This is helpful when you are dealing
with something with a very strange shape and when andThen does not help
narrow things down so you can be more targeted.
-- [ [3,4], { x:0, y:0 }, [5,12] ]
points : Decoder (List (Float,Float))
points =
list point
point : Decoder (Float,Float)
point =
oneOf
[ tuple2 (,) float float
, object2 (,) ("x" := float) ("y" := float)
]Transform the value returned by a decoder. Most useful when paired with
the oneOf function.
nullOr : Decoder a -> Decoder (Maybe a)
nullOr decoder =
oneOf
[ null Nothing
, map Just decoder
]
type UserID = OldID Int | NewID String
-- 1234 or "1234abc"
userID : Decoder UserID
userID =
oneOf
[ map OldID int
, map NewID string
]A decoder that always fails. Useful when paired with andThen or oneOf
to improve error messages when things go wrong. For example, the following
decoder is able to provide a much more specific error message when fail is
the last option.
point : Decoder (Float,Float)
point =
oneOf
[ tuple2 (,) float float
, object2 (,) ("x" := float) ("y" := float)
, fail "expecting some kind of point"
]A decoder that always succeeds. Useful when paired with andThen or
oneOf but everything is supposed to work out at the end. For example,
maybe you have an optional field that can have a default value when it is
missing.
-- { x:3, y:4 } or { x:3, y:4, z:5 }
point3D : Decoder (Float,Float,Float)
point3D =
object (,,)
("x" := float)
("y" := float)
(oneOf [ "z" := float, succeed 0 ])Helpful when one field will determine the shape of a bunch of other fields.
type Shape
= Rectangle Float Float
| Circle Float
shape : Decoder Shape
shape =
("tag" := string) `andThen` shapeInfo
shapeInfo : String -> Decoder Shape
shapeInfo tag =
case tag of
"rectangle" ->
object2 Rectangle
("width" := float)
("height" := float)
"circle" ->
object1 Circle
("radius" := float)
_ ->
fail (tag ++ " is not a recognized tag for shapes")Bring in an arbitrary JSON value. Useful if you need to work with crazily formatted data. For example, this lets you create a parser for "variadic" lists where the first few types are different, followed by 0 or more of the same type.
variadic2 : (a -> b -> List c -> value) -> Decoder a -> Decoder b -> Decoder (List c) -> Decoder value
variadic2 f a b cs =
customDecoder (list value) \jsonList ->
case jsonList of
one :: two :: rest ->
Result.map3 f
(decodeValue a one)
(decodeValue b two)
(decodeValue cs rest)
_ -> Result.Err "expecting at least two elements in the array"