A way to turn Json values into Elm values.
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" := trueExtract a null value. Primarily useful for creating other decoders.
nullOr : Decoder a -> Decoder (Maybe a)
nullOr decoder =
oneOf
[ null Nothing
, map Just decoder
]
numbers : Decoder [Int]
numbers =
list (oneOf [ int, null 0 ])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 two values. 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 values.
-- [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"] string
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 two different decoders on a JS value. This is nice for extracting multiple fields from an object.
type alias Task = { task : String, id : Int, completed : Bool }
point : Decoder Task
point =
object3 Task
("task" := string)
("id" := int)
("completed" := bool)Turn any object into a list of key-value pairs.
-- { 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 floatGreat for handling optional fields. The following code decodes JSON objects that may not have a profession field.
-- { name: "Tom", age: 31, profession: "plumber" }
-- { name: "Sue", age: 42 }
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 a couple 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 : (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 : (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"