I am trying to encode a data type into JSON:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
import Data.Aeson
data Trend = Trend
{ period :: String
, africa :: String
, americas :: String
, asia :: String
} deriving Show
instance ToJSON Trend where
toJSON Trend{..} =
object [ "Period" .= period
, "Africa" .= africa
, "Americas" .= americas
, "Asia" .= asia
]
test = Trend {period = "2013", africa = "1", americas = "2", asia = "3"}
Which gives:
λ: encode test
λ: "{\"Asia\":\"3\",\"Period\":\"2013\",\"Africa\":\"1\",\"Americas\":\"2\"}"
I don't understand why the generated JSON does not have the fields in the same order as my data type.
I am expecting the output to be {period, africa, americas, asia} and I am getting {asia, period, africa, americas)
I understand that in passing information across, the order is not important but I am curious as to why this is happening.
You can use toEncoding
method which is available since aeson-0.10
(use aeson-0.11
though, if only possible). In that case you have more control over the generated structure:
instance ToJSON Trend where
toJSON Trend{..} =
object [ "Period" .= period
, "Africa" .= africa
, "Americas" .= americas
, "Asia" .= asia
]
toEncoding Trend {..} =
pairs $ "Period" .= period
<> "Africa" .= africa
<> "Americas" .= americas
<> "Asia" .= asia
Or in case as simple is this, is worth using Generic
derivation
instance ToJSON Trend where
toJSON = genericToJSON defaultOptions { fieldLabelModifier = capitaliseFirst }
where
capitaliseFirst (x:xs) = toUpper x : xs
capitaliseFirst [] = []
The reason it is happening is because an Aeson Object is just a HashMap, and when aeson converts the HashMap to text it just serializes the key-value pairs in the order that the HashMap returns them - which probably has no relationship to the order in which the keys were inserted.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With