Decoding into Map key value expects an array instead of an object
pmiddend opened this issue · 2 comments
Is your change request related to a problem? Please describe.
It's more of a question than a change request per se. I was naively trying to decode a JSON object by giving it the type Map String T (for some irrelevant T). This didn't work, because the decodeJson instance for Map expects an Array (of pairs, I guesss).
Isn't it a bit more obvious to expect a JSON object instead of an array of pairs?
The encodeJson and decodeJson instance for Map use an array of key/value pairs. This is done because objects require string keys, but key type used in your Map may not necessarily encode as a string. After all, you can use any key type you like (so long as it has an Ord instance).
The Foreign.Object type does encode and decode as a JSON object as you would expect, because the type represents a JavaScript object and requires string keys. If your type was Object T (for some irrelevant T), then your decodeJson instance would work properly.
If you want to decode from an object to a Map String T then you have two options. First, you can manually write the decoder and convert from the object to a map:
decodeMap json = do
obj :: Object T <- decodeJson json
let
map' :: Map String T
map' = Map.fromFoldable $ Object.toUnfoldable obj
...If you want automatic encoding / decoding for Map String T to a JSON object, then you'll have to put a newtype around the map and write a new instance like the one above. For example:
newtype StrMap a = StrMap (Map String a)
instance encodeJsonStrMap :: EncodeJson a => EncodeJson (StrMap a) where
encodeJson (StrMap m) = encodeJson $ Object.fromFoldable $ Map.toUnfoldable m
...Thanks for the thorough explanation. I was asking the question in an exploratory phase, so to speak. Now I have a better overview and understand the argument.