Reputation: 15746
Yet another question on how to decode things with Elm...
So the problem is that I need to decode a value which can be either a string, for example
"price_unknown"
or it can be an array of 2 elements, where first one is a string and the second is a float:
["price", 50.5]
And for the eventual value I have a type:
type Something
= PriceUnknown
= Price Float
into which I need to convert the value from the json response.
I tried to use a bunch of things using somewhat between the lines of:
decode MyString
|> required "other_value" Json.Decode.string
|> required "price" JD.oneOf [JD.string, JD.list (JD.oneOf [JD.string, JD.float])] |> JD.map mapper
( I use json_decode_pipeline
package here )
But obviously it complains about different values in the lists and whatnot so I am stuck.
Thank you in advance.
Upvotes: 1
Views: 261
Reputation: 46
You are pretty close, but all of the Decoder
s in oneOf
have to have the same type. Also, destructuring mixed lists can be a pain. This uses elm-community/json-extra to make a manual decoding step easier.
myDecoder : Decoder SomethingElse
myDecoder =
decode MyString
|> required "other_value" Json.Decode.string
|> required "price" priceDecoder
priceDecoder : Decoder Something
priceDecoder =
JD.oneOf
[ priceUnknownDecoder
, priceKnownDecoder
]
priceUnknownDecoder : Decoder Something
priceUnknownDecoder =
JD.string
|> JD.andThen
(\string ->
if string == "price_unknown" then
JD.succeed PriceUnknown
else
JD.fail "Invalid unknown price string."
)
priceKnownDecoder : Decoder Something
priceKnownDecoder =
listTupleDecoder
JD.string
JD.float
|> JD.andThen
(\(tag, price) ->
if tag == "price" then
JD.succeed (Price price)
else
JD.fail "Invalid tag string."
)
listTupleDecoder : Decoder a -> Decoder b -> Decoder (a, b)
listTupleDecoder firstD secondD =
JD.list JD.value
|> JD.andThen
(\values ->
case values of
[first, second] ->
Result.map2
(,)
JD.decodeValue firstD first
JD.decodeValue secondD second
|> JD.Extra.fromResult
_ ->
JD.fail "There aren't two values in the list."
)
Upvotes: 3