Reputation: 25
There is the type
type User
= Anonymous
| Named {name : String, email : String}
Json.Decode.object2
doesn't fit here because its first arguments type is (a -> b -> c)
but Named
has { email : String, name : String } -> User
type.
How to decode to User?
Upvotes: 1
Views: 369
Reputation: 36385
Another way of doing this could be to define a function that accepts a name and email and returns your Named
constructor:
userDecoder : Decoder User
userDecoder =
let
named =
object2
(\n e -> Named { name = n, email = e })
("name" := string)
("email" := string)
in
oneOf [ null Anonymous, named ]
Upvotes: 3
Reputation: 36385
Since your Named
constructor takes a record as a parameter, it might be a little cleaner to create a type alias for the name and email record.
type alias NamedUserInfo =
{ name : String
, email : String
}
You could then redefine User
to use the alias:
type User
= Anonymous
| Named NamedUserInfo
While the above isn't strictly necessary, I find that aliasing record types proves useful in many ways down the road. Here it is useful because it gives us a constructor NamedUserInfo
that lets us clearly define a decoder:
import Json.Decode exposing (..)
namedUserInfoDecoder : Decoder NamedUserInfo
namedUserInfoDecoder =
object2
NamedUserInfo
("name" := string)
("email" := string)
And finally, your user decoder could be constructed like this:
userDecoder : Decoder User
userDecoder =
oneOf
[ null Anonymous
, object1 Named namedUserInfoDecoder
]
You can run your example through a quick test like this:
exampleJson =
"""
[{"user":null}, {"user": {"name": "John Doe", "email": "[email protected]"}}]
"""
main =
text <| toString <| decodeString (list ("user" := userDecoder)) exampleJson
-- Ouputs:
-- Ok ([Anonymous,Named { name = "John Doe", email = "[email protected]" }])
Upvotes: 3