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

标签 json haskell aeson

我有几个类型,UserPost . PostUser 创建.

我的数据库看起来和我的类型一样,都是

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

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

例如,我可能想查看一个用户“个人资料”,其中包括所有 PostUser 制造.其他时候,我可能想搜索各种 User s 在系统中,所以没有必要返回 Post这是他们所做的。

我可以毫无问题地检索 Post s 对于给定的 User ,我在检索 User 时也没有问题给定的 Post .我只想知道有条件地向我的 JSON 添加 key 的最佳方法。

有人向我提到我应该在 User 中添加一个字段对于 posts :: Maybe [Post]并添加 author :: Maybe User到我的Post类型。虽然这适用于相当小的类型,但我认为它会使具有大量关系的某些类型变得非常大并且可能难以维护。

我也考虑过使用 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 的有效定义,这会给我用户信息以及与该用户关联的所有帖子. 这会给我类似的 JSON

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

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

最佳答案

对于是应该使用动态 JSON 还是坚持使用固定的 ToJSON 实例,我认为没有一个通用的答案,但是您可以轻松地将两者混合并向生成的 JSON 值添加额外的字段来自您的实例。

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

因此,您可以在您的用户帖子 列表上调用toJSON,并将帖子数组作为附加条目插入到如果需要,请映射:

{-# 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"}]}

关于json - 有条件地将字段添加到 JSON 输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34339367/

相关文章:

java - 从 JSON 字符串创建 BSON 对象

jquery - backbone.js JSON解析错误

haskell - 在默认的 Haskell Stack 项目中构建多个可执行文件

json - Haskell-Aeson : Getting "Nothing" when trying to decode JSON URL Req

json - 使用 Aeson 的 `genericToJSON` 将产品类型编码为对象,而不是列表

json - 将 JSON 数据转换为 data.frame

json - NodeJS 异步 JSON 解析导致 Buffer.toString() 失败

parsing - 使用替代方案的纯应用解析器

haskell - 有没有一种简单的方法可以阻止 GHC 显示加载/链接的包?

haskell - 使用 Aeson 解析带有嵌套列表的列表