monnef monnef - 4 years ago 146
JSON Question

How to automatically convert a record in "makeFields" lens format to JSON with fields matching lenses?

data ArticlePreview = ArticlePreview
{ _articlePreviewName :: T.Text
, _articlePreviewPerex :: T.Text
, _articlePreviewAuthorName :: T.Text
, _articlePreviewAuthorUrl :: T.Text
, _articlePreviewDate :: T.Text
, _articlePreviewCategoryName :: T.Text
, _articlePreviewCategoryUrl :: T.Text
, _articlePreviewCommentsCount :: Maybe Integer
} deriving (Show, Eq, Generic)

makeFields ''ArticlePreview


I tried Aeson:

instance ToJSON ArticlePreview
instance FromJSON ArticlePreview

encodeToString :: ToJSON a => a -> String
encodeToString = CL.unpack . encode


Outputs:

{"_articlePreviewCommentsCount":17,"_articlePreviewAuthorName":"x","_articlePreviewName":"x","_articlePreviewCategoryName":"x","_articlePreviewAuthorUrl":"x","_articlePreviewCategoryUrl":"x","_articlePreviewDate":"x","_articlePreviewPerex":"x"}


Desired output:

{"commentsCount":17,"authorName":"x","name":"x","categoryName":"x","authorUrl":"x","categoryUrl":"x","date":"x","perex":"x"}


I don't insist on Aeson, but it must be automatic (without manual definition that e.g.
_articlePreviewCommentsCount
maps to
commentsCount
).

Answer Source

You can derive FromJSON/ToJSON using template Haskell from Data.Aeson.TH which allows for some modifications:

import Data.Aeson.TH
import Data.Char

deriveJSON
  defaultOptions {fieldLabelModifier = (_head %~ toLower) . drop 15}
  ''ArticlePreview

t :: ArticlePreview
t = ArticlePreview "" "" "" "" "" "" "" (Just 12)

Then you get:

GHCI> encode t
"{\"name\":\"\",\"perex\":\"\",\"authorName\":\"\",\"authorUrl\":\"\",\"date\":\"\",\"categoryName\":\"\",\"categoryUrl\":\"\",\"commentsCount\":12}"
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download