繁体   English   中英

有条件地将字段添加到JSON输出

[英]Conditionally add fields to JSON output

我有几种类型, UserPost PostUser创建。

我的数据库看起来与我的类型相同

data User = { userID :: Integer, name :: String }
data Post = { content :: String, authorID :: Integer } -- authorID is the userID

假设我有基于这些类型的有效To / FromJSON实例,我将如何有条件地在我的JSON输出中包含一个值?

作为一个例子,我可能想看一下用户“个人资料”,其中包括User制作的所有Post 其他时候,我可能想要搜索系统中的各个User ,因此返回他们所做的Post是没有意义的。

我没有问题,检索Post ■对于给定的User ,也没有得到检索问题User给定的Post 我只是想知道有条件地为我的JSON添加密钥的最佳方法。

有人向我提到我本应该为User添加一个字段来posts :: Maybe [Post]并添加一个author :: Maybe User to my Post type。 虽然这适用于相当小的类型,但我觉得它会使某些类型的关系很多很大并且可能难以维护。

我还想过使用Map Text Data.Aeson.Value来构建/序列化我的信息,但是通过做类似的事情,你失去了大多数(全部?)类型的安全性。

编辑

根据上面的数据类型,我定义了以下ToJSON实例。

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 ]

这会给我“简单”的json输出,比如User

{
  "id": 4,
  "name": "User Name"
}

Post

{
  "content": "This is the content of my post",
  "author_id": 4
}

这些可能很有用,尤其是在搜索项目时。 这允许仅显示有限量的信息。

我可以做一些事情

instance ToJSON User where
  toJSON (User i n) = object [ "id" .= i, "name" .= n, "posts" .= posts i ]

假设有效的posts定义,这将给我提供用户信息,以及与该用户相关的所有posts 这会给我类似的JSON

{
  "id": 4,
  "name": "User Name",
  "posts": [
    {
      "content": "This is some content",
      "author_id": 4
    }
  ]
}

我不明白我将如何动态设置我想发送给客户端的字段。 是否可以定义ToJSON的多个实例并选择我想用于给定请求的实例? 或者我应该只做我之前建议的内容,并在我的User类型中包含一个可以保存Maybe [Post]posts字段?

我不认为您是否应该使用动态JSON或坚持修复ToJSON实例,但您可以轻松地将两者混合并将额外字段添加到从您的实例生成的JSON值。

根据你所写的,我猜你知道Aeson将一个对象表示为Map Text Value吗? 对于数组,它使用Vector Value

因此,您可以在UserPosts列表上调用toJSON ,如果需要,只需将post数组作为附加条目插入地图中:

{-# LANGUAGE OverloadedStrings #-}

import qualified Data.ByteString.Lazy.Char8 as B
import Data.Aeson
import Data.Aeson.Types
import qualified Data.HashMap.Strict as M

data User = User { userID :: Integer, name :: String }

data Post = Post { content :: String, authorID :: Integer }

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 ]

babs = User { userID = 5, name = "babs" }

posts = [ Post { content = "blah", authorID = 5 } ]

userWithPosts = Object (M.insert "posts" v o)
  where
    Object o = toJSON babs
    v        = toJSON posts

main = B.putStrLn (encode userWithPosts)

encode调用为您提供组合的JSON:

*Main B> main
{"name":"babs","id":5,"posts":[{"author_id":5,"content":"blah"}]}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM