I am new to Haskell, coming from an imperative programming background. I would like to be able to serialize an object to JSON in the "Haskell way", but not quite sure how to do that yet.
I have read Chapter 5 of RealWorldHaskell which talks about JSON a bit, and played around with Aeson. I have also looked at a few JSON API libraries written in Haskell, such as:
That got me to the point of being able to create very basic JSON strings from objects (also thanks to this blog post):
{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}
import Data.Aeson
import GHC.Generics
data User = User {
email :: String,
name :: String
} deriving (Show, Generic)
instance ToJSON User
main = do
let user = User "foo@example.com" "Hello World"
let json = encode user
putStrLn $ show json
That will print out:
"{\"email\":\"foo@example.com",\"name\":\"Hello World\"}"
Now the goal is, add another field to a User
instance that can have arbitrary fields. The Facebook Graph API has a field called data
, which is a JSON object with any property you want. For example, you may make requests like this to Facebook's API (pseudocode, not familiar with the Facebook API exactly):
POST api.facebook.com/actions
{
"name": "read",
"object": "book",
"data": {
"favoriteChapter": 10,
"hardcover": true
}
}
The first two fields, name
, and object
are type String
, while the data
field is a map of arbitrary properties.
The question is, what is the "Haskell way" to accomplish that on the User
model above?
I can understand how to do the simple case:
data User = User {
email :: String,
name :: String,
data :: CustomData
} deriving (Show, Generic)
data CustomData = CustomData {
favoriteColor :: String
}
But that isn't quite what I'm looking for. That means the User
type, when serialized to JSON, will always look like this:
{
"email": "",
"name": "",
"data": {
"favoriteColor": ""
}
}
The question is, how do you make it so you only have to define that User
type once, and then can have arbitrary fields attached to that data
property, while still benefitting from static typing (or whatever is close to that, not super familiar with the details of types yet).