How do I decode JSON dicts to something like Map?

I have an API that returns a JSON dictionary as follows:

{
  "foo": { "bar": 3, "qux": "quux" },
  "bar": {"a": true}
}

Meaning I have a Map String (Map String T) where T is known (it’s a union of int, string or some custom type - the point is, I have a DecodeJson instance for it). How do I decode this best using argonaut-codec? Map has a DecodeJson instance, but it assumes I have a list of tuples.

I guess my real question is, how do I do this without awkward newtypes and explicit DecodeJson instances for that. Is it possible?

I would do something like this

newtype StringMap a = StringMap (Map String a)

instance decodeJsonStringMap :: DecodeJson a => DecodeJson (StringMap a) where
  decodeJson json =
    caseJsonObject (Left ?an_appropriate_error) \obj ->
      traverse decodeJson (Map.fromFoldable (Object.toUnfoldable obj :: Array (Tuple String a))))

Note: I haven’t put this through a compiler, and so it probably doesn’t compile, but hopefully you can figure out how to get it to work.

Doing this without awkward newtypes is probably not possible though, as a result of how typeclasses have to be globally coherent. This is one of the main problems with typeclass-based codecs and I think the most promising solution is to just not use type classes for codecs.

1 Like