elm-lang/core/2.0.0

NOTE: this package moved to elm/core

NOTE: this package is not compatible with Elm 0.19.1

Json.Decode

A way to turn Json values into Elm values.

Run a Decoder

decodeString : Decoder a -> String -> Result String a
decodeValue : Decoder a -> Value -> Result String a

Primitives

string : Decoder String

Extract a string.

-- ["John","Doe"]


name : Decoder (String, String)
name =
    tuple2 (,) string string
int : Decoder Int

Extract an integer.

-- { ... age: 42 ... }


age : Decoder Int
age =
    "age" := int
float : Decoder Float

Extract a float.

-- [ 6.022, 3.1415, 1.618 ]


numbers : Decoder (List Float)
numbers =
    list float
bool : Decoder Bool

Extract a boolean.

-- { ... checked: true ... }


checked : Decoder Bool
checked =
    "checked" := true
null : a -> Decoder a

Extract 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 ])

Arrays

list : Decoder a -> Decoder (List a)

Extract a list from a JS array.

-- [1,2,3,4]


numbers : Decoder [Int]
numbers =
    list int
array : Decoder a -> Decoder (Array a)

Extract an Array from a JS array.

-- [1,2,3,4]


numbers : Decoder (Array Int)
numbers =
    array int
tuple1 : (a -> value) -> Decoder a -> Decoder value
tuple2 : (a -> b -> value) -> Decoder a -> Decoder b -> Decoder value

Handle 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 }
(a -> b -> c -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder value

Handle an array with exactly three values.

-- [3,4,5] or [0,0,0]
point3D : Decoder (Float,Float,Float)
point3D =
    tuple3 (,,) float float float
(a -> b -> c -> d -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder d
-> Decoder value
(a -> b -> c -> d -> e -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder d
-> Decoder e
-> Decoder value
(a -> b -> c -> d -> e -> f -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder d
-> Decoder e
-> Decoder f
-> Decoder value
(a -> b -> c -> d -> e -> f -> g -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder d
-> Decoder e
-> Decoder f
-> Decoder g
-> Decoder value
(a -> b -> c -> d -> e -> f -> g -> h -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder d
-> Decoder e
-> Decoder f
-> Decoder g
-> Decoder h
-> Decoder value

Objects

(:=) : String -> Decoder a -> Decoder a

Decode 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)
at : List String -> Decoder a -> Decoder a

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 fields
object1 : (a -> value) -> Decoder a -> Decoder value
object2 : (a -> b -> value) -> Decoder a -> Decoder b -> Decoder value

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)
(a -> b -> c -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder value

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)
(a -> b -> c -> d -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder d
-> Decoder value
(a -> b -> c -> d -> e -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder d
-> Decoder e
-> Decoder value
(a -> b -> c -> d -> e -> f -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder d
-> Decoder e
-> Decoder f
-> Decoder value
(a -> b -> c -> d -> e -> f -> g -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder d
-> Decoder e
-> Decoder f
-> Decoder g
-> Decoder value
(a -> b -> c -> d -> e -> f -> g -> h -> value)
-> Decoder a
-> Decoder b
-> Decoder c
-> Decoder d
-> Decoder e
-> Decoder f
-> Decoder g
-> Decoder h
-> Decoder value
keyValuePairs : Decoder a -> Decoder (List ( String, a ))

Turn any object into a list of key-value pairs.

-- { tom: 89, sue: 92, bill: 97, ... }
grades : Decoder (List (String, Int))
grades =
    keyValuePairs int
dict : Decoder a -> Decoder (Dict String a)

Turn 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 float

Oddly Shaped Values

maybe : Decoder a -> Decoder (Maybe a)

Great 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))
oneOf : List (Decoder a) -> Decoder a

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)
    ]
map : (a -> b) -> Decoder a -> Decoder b

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
      ]
fail : String -> Decoder a

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"
    ]
succeed : a -> Decoder a

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 ])
andThen : Decoder a -> (a -> Decoder b) -> Decoder b

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")

"Creative" Values

value : Decoder Value

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"
customDecoder : Decoder a -> (a -> Result String b) -> Decoder b