JSON处理中的参数化但类型安全的密钥

时间:2016-12-20 09:53:41

标签: haskell aeson

如何在Haskell中表达以​​下想法?虽然语法已完全弥补,但这正是我想要实现的目标:

  • 我的应用程序具有高度嵌套的核心数据类型,每个“级别”具有FromJson / ToJson实例
  • 为UI提供动力的JSON API能够操纵各个“嵌套级别”,例如。要编辑地址,您无需编辑完整的订单。
  • 但是,我想确保除了UI修改的数据外,还会发回完整的订单。这确保了如果编辑导致对象的另一部分中的某个从属字段被改变,则将其传送回UI。

编辑核心问题不在于应用逻辑本身。核心问题是如何以类型安全的方式表示JSON密钥,同时能够对它们进行参数化。简单的解决方案是为每种API返回类型设置不同的具体类型,例如{orderItems :: [OrderItem], order :: Order}{address :: Address, order :: Order}{email :: Email, customer :: Customer}。但这些将很快重复。我希望有一个数据类型,它代表具有主键值对和辅助/支持键值对的JSON的 idea ,其中键名可以轻松更改。

下面给出的伪代码是这个想法的概括:

data IncomingJson rootname payload = (FromJson payload, ToString rootname) => IncomingJson
  {
    rootname :: payload
  }

data OutgoingJson rootname payload sidename sidepayload = (ToJson payload, ToString rootname, ToJson sidepayload, ToString sidename) => IncomingJson
  {
    rootname :: payload
  , sidename :: sidepayload
  }

createOrder :: IncomingJson "order" NewOrder -> OutgoingJson "order" Order Nothing ()

editOrderItems :: IncomingJson "items" [OrderItem] -> OutgoingJson "items" [OrderItem] "order" Order

editOrderAddress :: IncomingJson "address" Address -> OutgoingJson "address" Address "order" Order

1 个答案:

答案 0 :(得分:1)

(编辑:试图全面回答修订后的问题。)

下面的示例代码可能接近您想要的。此示例分别使用自定义OutgoingJSONIncomingJSON实例定义ToJSONFromJSON。 (我也为ToJSON数据类型包含IncomingJSON,但我怀疑你不需要它。)它依赖于通过短{{1}分配JSON密钥的每种数据类型实例。可以使用KeyedJSON或其他替代方法来自动执行此操作,但这看起来既丑陋又不明智。 (你真的 希望你的JSON密钥直接与Haskell数据类型名称绑定,对吗?)

如果您加载它并查看GHC.GenericsinExample1的类型,它们应该符合您的预期。 outExample1inExample2演示了JSON块的类型安全解析 - 如果JSON块中存在期望类型的键,则成功,如果不存在则失败。最后,inExample3显示了如何使用所需的主键和辅助键序列化outExample1AsJSON示例。

OutgoingJSON