I'm working on a recursive tree of this type
type Node anyType
= Leaf Id (Maybe anyType) Name
| Tree Id (List (Node anyType)) Name
where
type Id
= Id Int
| Root
and I'm trying to decode a json of this kind into it
{
"id": "root",
"entries": [
{
"id": 1,
"value": 0,
"name": "New Entry"
},
{
"id": 2,
"entries": [
{
"id": 4,
"value": 0,
"name": "New Entry"
}
],
"name": "New Entry"
}
],
"name": "Budget"
}
To decode the Id type I'm using these decoders
rootDecoder =
(Decode.field "id" Decode.string)
|> Decode.andThen
(\str ->
if str == "root" then
(Decode.succeed Root)
else
Decode.fail <| "[exactMatch] tgt: " ++ "root" ++ " /= " ++ str
)
intIdDecoder =
Decode.map Id (Decode.field "id" Decode.int)
idDecoder =
Decode.oneOf
[ rootDecoder
, intIdDecoder
]
To decode the tree structure i tried the following, using Json.Decode.Pipeline:
leafDecoder valueDecoder =
Decode.succeed Leaf
|> required "id" idDecoder
|> required "value" valueDecoder
|> required "name" Decode.string
treeDecoder valueDecoder =
Decode.succeed Tree
|> required "id" idDecoder
|> required "entries"
(Decode.list
(Decode.lazy
(\_ ->
Decode.oneOf
[ leafDecoder valueDecoder
, treeDecoder valueDecoder
]
)
)
)
|> required "name" Decode.string
But when I try to decode the structure I get the following error:
The Json.Decode.oneOf at json.budget.entries[0] failed in the following 2 ways: (1) The Json.Decode.oneOf at json.id failed in the following 2 ways: (1) Problem with the given value: 1 Expecting an OBJECT with a field named `id` (2) Problem with the given value: 1 Expecting an OBJECT with a field named `id` (2) Problem with the given value: { "id": 1, "value": 0, "name": "New Entry" } Expecting an OBJECT with a field named `entries`
But I don't understand why since both the field id and entries are there, and yet it complains.
What am I doing wrong?
In your
leafDecoderandtreeDecoderyou have the following lines:These will both pull out the value of the field
idwithin the current object and pass this value on toidDecoder, which callsDecode.oneOfwithrootDecoderandintIdDecoder.However, in your
rootDecoderandintIdDecoderyou have the following:These decoders attempt to pull the value of a field named
idfrom the current object. But you pass these functions the value of theidproperty, not an object containing this property.These decoders would work if your
ids were nested in objects that only containedidproperties, for example:The fix is to remove the calls to
Decode.fieldinrootDecoderandintIdDecoder, as these decoders already get passed the value of theidfield: