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": "j.doe@mailg.com"}}]
"""
main =
text <| toString <| decodeString (list ("user" := userDecoder)) exampleJson
-- Ouputs:
-- Ok ([Anonymous,Named { name = "John Doe", email = "j.doe@mailg.com" }])