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.
Represents a JavaScript value.
Using a certain decoder, attempt to parse a JSON string. If the decoder fails, you will get a string message telling you why.
decodeString (tuple2 (,) float float) "[3,4]" -- Ok (3,4)
decodeString (tuple2 (,) float float) "{ \"x\": 3, \"y\": 4 }" -- Err ""Using a certain decoder, attempt to parse a raw Json.Value. You can pass
a Json.Value into Elm through a port, so this can let you handle data with
extra weird shapes or stuff that currently is not allowed through ports
automatically.
port jsonValues : Signal Json.Value
shapes : Signal (Result String Shape)
shapes =
Signal.map (decodeValue shape) jsonValues
type Shape
= Rectangle Float Float
| Circle Float
shape : Decoder Shape -- see definition in `andThen` docsExtract 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" := boolDecode 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 (List 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.
extractString : Decoder String
extractString =
tuple1 identity string
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 floatApplies the decoder to the field with the given name. Fails if the JSON object has no such 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 fieldsApply a function to a decoder. You can use this function as map if you
must (which can be done with any objectN function actually).
object1 sqrt ("x" := float)Use 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 }
job : Decoder Job
job =
object3 Job
("name" := string)
("id" := int)
("completed" := bool)Turn any object into a list of key-value pairs, including inherited enumerable properties. Fails if any value 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, including inherited enumerable properties. Fails if any value can't be decoded with the given decoder.
-- { "mercury": 0.33, "venus": 4.87, "earth": 5.97, ... }
planetMasses : Decoder (Dict String Float)
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 explicitly, as this function will swallow
errors 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 =
object3 (,,)
("x" := float)
("y" := float)
(oneOf [ "z" := float, succeed 0 ])Helpful when a field tells you about the overall structure of the JSON you are dealing with. For example, imagine we are getting JSON representing different shapes. Data like this:
{ "tag": "rectangle", "width": 2, "height": 3 }
{ "tag": "circle", "radius": 2 }The following shape decoder looks at the tag to know what other fields to
expect and then it extracts the relevant information.
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 c -> Decoder value
variadic2 f a b c =
let
combineResults = List.foldr (Result.map2 (::)) (Ok [])
in
customDecoder (list value) (\jsonList ->
case jsonList of
one :: two :: rest ->
Result.map3 f
(decodeValue a one)
(decodeValue b two)
(combineResults (List.map (decodeValue c) rest))
_ -> Result.Err "expecting at least two elements in the array")Create a custom decoder that may do some fancy computation. See the value
documentation for an example usage.
Represents a way of decoding JSON values. If you have a
(Decoder (List String))it will attempt to take some JSON value and turn it into a list of strings. These decoders are easy to put together so you can create more and more complex decoders.