Search code examples
jsonelmdecoder

JSON Decoder in Elm 0.18


In Elm 0.18, I would like to build a JSON decoder for the following examples:

case 1:

{"metadata": {"signatures":[{"metadata": {"code": "1234"}},
                            {"metadata": {"code": "5678"}}]}}  

-> { code = Just "1234" }

case 2:

{"metadata": {"signatures":[]}} 

-> { code = Nothing }

case 3:

{"metadata": {"signatures":[{"metadata": null}]}} 

-> { code = Nothing }

This is what I got working, but it fails for case 3.

type alias Code = { code : Maybe String }

let
    js = """{"metadata": {"signatures":[{"metadata": {"code": "1234"}},
                   {"metadata": {"code": "5678"}}]}}"""

    dec1 =
        Decode.at [ "metadata", "code" ] Decode.string

    dec0 =
        Decode.list dec1
            |> Decode.andThen
                (\v ->
                    if List.isEmpty v then
                        Decode.succeed Nothing
                    else
                        Decode.succeed <| List.head v
                )

    dec =
        decode Code
            |> optionalAt [ "metadata", "signatures" ] dec0 Nothing

    expected =
        Ok { code = Just "1234" }
in
    Decode.decodeString dec js
        |> Expect.equal expected

A workaround would be to import all the data to the model and then obtain the info from the model, but I prefer to avoid adding unnecessary data into my model. How can I improve this?


Solution

  • A more simplified approach could use Json.Decode.index to force the decoding at index zero as a string if it exists, which will fail otherwise, so you can use Json.Decode.maybe to return Nothing on failure.

    dec0 =
        Decode.maybe (Decode.index 0 dec1)