dillonkearns / elm-ts-json / TsJson.Decode.Pipeline

Use the (|>) operator to build JSON decoders.

This is a typed fork of NoRedInk/elm-json-decode-pipeline. Thanks to NoRedInk for the original API!

Decoding fields

required : String -> TsJson.Decode.Decoder a -> TsJson.Decode.Decoder (a -> b) -> TsJson.Decode.Decoder b

Decode a required field.

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

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

userDecoder : Decoder User
userDecoder =
    Decode.succeed User
        |> required "id" int
        |> required "name" string
        |> required "email" string

result : Result String User
result =
    Decode.decodeString
        userDecoder
        """
      {"id": 123, "email": "sam@example.com", "name": "Sam"}
    """

-- Ok { id = 123, name = "Sam", email = "sam@example.com" }

requiredAt : List String -> TsJson.Decode.Decoder a -> TsJson.Decode.Decoder (a -> b) -> TsJson.Decode.Decoder b

Decode a required nested field.

optional : String -> TsJson.Decode.Decoder a -> a -> TsJson.Decode.Decoder (a -> b) -> TsJson.Decode.Decoder b

Decode a field that may be missing or have a null value. If the field is missing, then it decodes as the fallback value. If the field is present, then valDecoder is used to decode its value. If valDecoder fails on a null value, then the fallback is used as if the field were missing entirely.

import TsJson.Decode Decode exposing (Decoder, int, null, oneOf, string)
import TsJson.Decode.Pipeline exposing (optional, required)

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

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

result : Result String User
result =
    Decode.decodeString
        userDecoder
        """
      {"id": 123, "email": "sam@example.com" }
    """

-- Ok { id = 123, name = "blah", email = "sam@example.com" }

Because valDecoder is given an opportunity to decode null values before resorting to the fallback, you can distinguish between missing and null values if you need to:

userDecoder2 =
    Decode.succeed User
        |> required "id" int
        |> optional "name" (oneOf [ string, null "NULL" ]) "MISSING"
        |> required "email" string

optionalAt : List String -> TsJson.Decode.Decoder a -> a -> TsJson.Decode.Decoder (a -> b) -> TsJson.Decode.Decoder b

Decode an optional nested field.

hardcoded : a -> TsJson.Decode.Decoder (a -> b) -> TsJson.Decode.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 TsJson.Decode Decode exposing (Decoder, int, string)
import TsJson.Decode.Pipeline exposing (required)

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

userDecoder : Decoder User
userDecoder =
    Decode.succeed User
        |> required "id" int
        |> required "email" string
        |> hardcoded 0

result : Result String User
result =
    Decode.decodeString
        userDecoder
        """
      {"id": 123, "email": "sam@example.com"}
    """

-- Ok { id = 123, email = "sam@example.com", followers = 0 }

custom : TsJson.Decode.Decoder a -> TsJson.Decode.Decoder (a -> b) -> TsJson.Decode.Decoder b

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

Consider this example.

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

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

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

result : Result String User
result =
    Decode.decodeString
        userDecoder
        """
      {
        "id": 123,
        "email": "sam@example.com",
        "profile": {"name": "Sam"}
      }
    """

-- Ok { id = 123, name = "Sam", email = "sam@example.com" }