NoRedInk/elm-decode-pipeline/1.1.2

NOTE: this package is not compatible with Elm 0.19.1

Json.Decode.Pipeline

Design Principles

  • Introduce functions that work well with the (|>) operator
  • Don't introduce any custom infix operators
  • Don't introduce any functions that are intended to be called using backticks
required : String -> Decoder a -> Decoder (a -> b) -> Decoder b

Decode a required field.

import Json.Decode exposing (int, string, Decoder)
import Json.Decode.Pipeline exposing (decode, required)




type alias User =
  { id : Int
  , name : String
  , email : String
  }




userDecoder : Decoder User
userDecoder =
  decode User
    |> required "id" int
    |> required "name" string
    |> required "email" string




result : Result String User
result =
  Json.Decode.decodeString
    userDecoder
    """
      {"id": 123, "email": "[email protected]", "name": "Sam"}
    """
-- Ok { id = 123, name = "Sam", email = "[email protected]" }
requiredAt : List String -> Decoder a -> Decoder (a -> b) -> Decoder b

Decode a required nested field.

optional : String -> Decoder a -> a -> Decoder (a -> b) -> Decoder b

Decode a field that may or may not be present. If the field is present, use the specified decoder on it. If the field is not present, successfully decode to the given fallback value.

import Json.Decode exposing (int, string, Decoder)
import Json.Decode.Pipeline exposing (decode, required, optional)




type alias User =
  { id : Int
  , name : String
  , email : String
  }




userDecoder : Decoder User
userDecoder =
  decode User
    |> required "id" int
    |> optional "name" string "blah"
    |> required "email" string




result : Result String User
result =
  Json.Decode.decodeString
    userDecoder
    """
      {"id": 123, "email": "[email protected]" }
    """
-- Ok { id = 123, name = "blah", email = "[email protected]" }
optionalAt : List String -> Decoder a -> a -> Decoder (a -> b) -> Decoder b

Decode an optional nested field.

hardcoded : a -> Decoder (a -> b) -> Decoder b

Rather than decoding anything, use a fixed value for the next step in the pipeline. harcoded does not look at the JSON at all.

import Json.Decode exposing (int, string, Decoder)
import Json.Decode.Pipeline exposing (decode, required)




type alias User =
  { id : Int
  , email : String
  , followers : Int
  }




userDecoder : Decoder User
userDecoder =
  decode User
    |> required "id" int
    |> required "email" string
    |> hardcoded 0




result : Result String User
result =
  Json.Decode.decodeString
    userDecoder
    """
      {"id": 123, "email": "[email protected]"}
    """
-- Ok { id = 123, email = "[email protected]", followers = 0 }
custom : Decoder a -> Decoder (a -> b) -> Decoder b

Run the given decoder and feed its result into the pipeline at this point.

Consider this example.

import Json.Decode exposing (int, string, at, Decoder)
import Json.Decode.Pipeline exposing (decode, required, custom)




type alias User =
  { id : Int
  , name : String
  , email : String
  }




userDecoder : Decoder User
userDecoder =
  decode User
    |> required "id" int
    |> custom (at [ "profile", "name" ])
    |> required "email" string




result : Result String User
result =
  Json.Decode.decodeString
    userDecoder
    """
      {
        "id": 123,
        "email": "[email protected]",
        "profile": {"name": "Sam"}
      }
    """
-- Ok { id = 123, name = "Sam", email = "[email protected]" }
resolveResult : Decoder (Result String a) -> Decoder a

Convert a Decoder (Result x a) into a Decoder a. Useful when you want to perform some custom processing just before completing the decoding operation.

import Json.Decode exposing (int, string, float, Decoder)
import Json.Decode.Pipeline exposing
  (decode, required, resolveResult)




type alias User =
  { id : Int
  , email : String
  }




userDecoder : Decoder User
userDecoder =
  let
    -- asResult gets run *after* all the
    -- (|> required ...) steps are done.
    asResult Int -> String -> Int -> Result String User
    asResult id email version =
      if version > 2 then
        Ok (User id email)
      else
        Err "This JSON is from a deprecated source. Please upgrade!"
  in
    decode asResult
      |> required "id" int
      |> required "email" string
      |> required "version" int -- version is part of asResult,
      |> resolveResult          -- but it is not a part of User




result : Result String User
result =
  Json.Decode.decodeString
    userDecoder
    """
      {"id": 123, "email": "[email protected]", "version": 1}
    """
-- Err "This JSON is from a deprecated source. Please upgrade!"
decode : a -> Decoder a

Begin a decoding pipeline. This is a synonym for Json.Decode.succeed, intended to make things read more clearly.

import Json.Decode exposing (int, string, float, Decoder)
import Json.Decode.Pipeline exposing (decode, required, optional)




type alias User =
  { id : Int
  , email : String
  , name : String
  }




userDecoder : Decoder User
userDecoder =
  decode User
    |> required "id" int
    |> required "email" string
    |> optional "name" string ""