I have a couple types, User
and Post
. A Post
is created by a User
.
My database looks the same as my types, which are
data User = { userID :: Integer, name :: String }
data Post = { content :: String, authorID :: Integer } -- authorID is the userID
Assuming I have valid To/FromJSON instances based on those types, how would I go about conditionally including a value in the output of my JSON?
As an example, I may want to look at a users "profile", which would include all Post
s made by the User
. Other times, I may want to search through the various User
s in the system, so there is no point in returning the Post
s that they have made.
I have no problem retrieving the Post
s for a given User
, nor do I have an issue retrieving the User
of a given Post
. I just want to know the best way to conditionally add a key to my JSON.
Someone mentioned to me that I should essentially add a field to User
for posts :: Maybe [Post]
and add an author :: Maybe User
to my Post
type. While this would work for rather small types, I feel that it would make certain types with a lot of relations quite large and potentially hard to maintain.
I've also thought of using a Map Text Data.Aeson.Value
to build / serialize my information, but you lose most (all?) type safety by doing something like that.
EDIT
Based on the data types above, I have defined the following ToJSON instances.
instance ToJSON User where
toJSON (User i n) = object [ "id" .= i, "name" .= n ]
instance ToJSON Post where
toJSON (Post c a) = object [ "content" .= c, "author_id" .= a ]
This would give me "simple" json output, something like User
:
{
"id": 4,
"name": "User Name"
}
Post
:
{
"content": "This is the content of my post",
"author_id": 4
}
These can be useful, especially when searching for items. This allows to only show a limited amount of information.
I could do something along the lines of
instance ToJSON User where
toJSON (User i n) = object [ "id" .= i, "name" .= n, "posts" .= posts i ]
Which would give me the Users information, as well as all posts associated with that user, assuming a valid definition of posts
.
This would give me JSON similar to
{
"id": 4,
"name": "User Name",
"posts": [
{
"content": "This is some content",
"author_id": 4
}
]
}
I do not understand how I would be able to dynamically set which fields I would like to send down to the client. Is it possible to define multiple instances of ToJSON and choose which instance I would like to use for a given request? Or should I just do what was suggested before and include a posts
field in my User
type that can hold a Maybe [Post]
?
Foo -> Value
, they don't have to be namedtoJSON
. – Daniel Wagner