Tips on JSON decoding

Hi all, I have a couple of questions on the matter:

  1. I have a JSON where some fields are generally numbers (ie 2020) but sometimes they are stored as strings which represent a number (ie “2020”).
    How to silently decode those type of fields into an Elm Int?

  2. Some JSON data comes with different structure. Sometimes it is a simple object which can be decoded as a Elm Record, other times it could be a list of different objects which should be decoded as List of Records. (in the two cases, even the single objects have different formats).

Ie:

{“prop1”: “”, “prop2”: }

or

[{“prop1”: “”, “prop2”: , “prop3”: “”}, …]

I have tried to model this situation with types, but I’m stuck on decoding.

something like the following:

type alias MetadataType1 =
 {  prop1: String
 ,  prop2: Int
 }

type alias MetadataType2 =
 { prop1: String
 ,  prop2: Int
 ,  prop3: String
 }

type Metadata
   = SingleMetadata MetadataType1
   | MultiMetadata (List MetadataType2)

-- the object which should be the result of decoding where metadata can be of different types
type alias JsonData =
  { name: String
  , metadata: Metadata
  }

Thanks in advance

I believe that the oneOf function from Json.Decode is designed to help with this:

Yep oneOf is the way to go:

type alias MetadataType1 =
    { prop1 : String
    , prop2 : Int
    }


type alias MetadataType2 =
    { prop1 : String
    , prop2 : Int
    , prop3 : String
    }


type Metadata
    = SingleMetadata MetadataType1
    | MultiMetadata (List MetadataType2)



-- the object which should be the result of decoding where metadata can be of different types


type alias JsonData =
    { name : String
    , metadata : Metadata
    }


jsondataDecoder : Decoder JsonData
jsondataDecoder =
    D.map2 JsonData
        (D.field "name" D.string)
        (D.field "metadata" metaDecoder)


metaDecoder : Decoder Metadata
metaDecoder =
    D.oneOf
        [ D.map SingleMetadata meta1Decoder
        , D.map MultiMetadata (D.list meta2Decoder)
        ]


meta1Decoder : Decoder MetadataType1
meta1Decoder =
    D.map2 MetadataType1
        (D.field "prop1" D.string)
        (D.field "prop2" D.int)


meta2Decoder : Decoder MetadataType2
meta2Decoder =
    D.map3 MetadataType2
        (D.field "prop1" D.string)
        (D.field "prop2" D.int)
        (D.field "prop3" D.string)

Thanks both for the suggestion. It knew about oneOf but for some reason it has not been the first idea which came to my mind.
I am quite a beginner.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.