[JSON Decoder Pipeline] Decoding a model attribute from either one of two JSON fields

90 views
Skip to first unread message

Mehdi Elaoufir

unread,
Jun 14, 2017, 9:25:32 AM6/14/17
to Elm Discuss
Hi,

I have the following json that i want to Decode :

{
...
"otherAttr" : 123,
"city1" : "",
"city2" : "Cupertino",
"yetAnotherAttr" : 123,
...

}

Here's my target model  :


type
alias User =
{...
, otherAttr : Int,
, city : String      
, yetAnotherAttr : Int,
...

}



I want city to be decoded from city1 if present and fallback to city2, do you have any clue?

So far i've tried using Decoder.oneOf then Decoder.at without success


userDecoder
: Decoder User
userDecoder
=
    decode user
       
|> ...
        |> required "otherAttr" int
       
|> cityDecoder
        |> required "yetAnotherAttr" int
       
|> ...

cityDecoder
: Decoder String
cityDecoder
=
   
Decode.at [ "city1", "city2" ] Decode.string        -- Not working !!




Any help appreciated!

Cheers,
Mehdi

Matthew Cheely

unread,
Jun 14, 2017, 10:55:59 AM6/14/17
to Elm Discuss
It sounds like you were on the right track with using Decode.oneOf to create a cityDecoder. It's hard to tell from the samples above, but one issue you might have run into is that for Decode.oneOf to fall back to the second decoder, the first decoder must fail. In your sample data, "city1" is an empty string, which the default string decoder will happily decode to an empty string. So you'd also need a string decoder that rejected empty strings. Something like this, perhaps:


userDecoder
: Decoder User
userDecoder
=

    decode
User
       
|> required "otherAttr" int
       
|> custom cityDecoder
       
|> required "yetAnotherAttr" int



cityDecoder
: Decoder String
cityDecoder
=

   
Decode.oneOf
       
[ Decode.field "city1" notEmptyStr
       
, Decode.field "city2" notEmptyStr
       
]


notEmptyStr
: Decoder String
notEmptyStr
=
   
Decode.string
       
|> Decode.andThen
           
(\str ->
               
if String.isEmpty str then
                   
Decode.fail "string length 0"
               
else
                   
Decode.succeed str
           
)

Fiddle with it here: https://ellie-app.com/3ttLP8cPmfLa1/1


Also worth noting is that

Decode.at [ "city1", "city2" ] ...

would be for decoding a structure like:

{
 
"city1": {
   
"city2": "value"
 
}
}
 



On Wednesday, June 14, 2017 at 9:25:32 AM UTC-4, Mehdi Elaoufir wrote:
Hi,

I have the following json that i want to Decode :

{
Enter code here...


Mehdi Elaoufir

unread,
Jun 14, 2017, 1:22:23 PM6/14/17
to Elm Discuss
It works like a charm, overwhelming!

Thanks a lot, really !
Reply all
Reply to author
Forward
0 new messages