Haskell 将嵌套属性添加到返回的记录

Haskell 将嵌套属性添加到返回的记录,haskell,yesod,Haskell,Yesod,我有一个Yesod路由处理程序,它返回带有对象的JSON { id: 1, title: "foo" content: "bar" } 我想添加一个带有元数据的\u links属性,该属性在实体本身中不存在,例如 { id: 1, title: "foo" content: "bar" _links: {self: http://localhost:3000/events/1} } 如何将\u链接添加到现有实体记录?这是我的处理程序: getEventR :: Event

我有一个Yesod路由处理程序,它返回带有对象的JSON

{ id: 1,
  title: "foo"
  content: "bar"
}
我想添加一个带有元数据的
\u links
属性,该属性在实体本身中不存在,例如

{ id: 1,
  title: "foo"
  content: "bar"
  _links: {self: http://localhost:3000/events/1}
}
如何将
\u链接
添加到现有实体记录?这是我的处理程序:

getEventR :: EventId -> Handler Value
getEventR eid = do
    event <- runDB $ get404 eid

    render <- getUrlRender
    let renderedUrl = render $ EventR eid

    let links = object
          [ "self" .= renderedUrl
          ]

    let returnVal = object
          [ "data" .= (Entity eid event)
          , "_links" .= links
          ]

    return returnVal
getEventR::EventId->Handler值
getEventR eid=do

事件要执行此操作,您必须手动将
实体
转换为
,然后使用
无序容器中的函数:Data.HashMap.Strict
插入
“\u links”
键,然后再次从中构建
。使用适用于
aeson
的镜头兼容软件包可能会大大简化:

buildEntityWithLink :: Entity -> Text -> Maybe Value
buildEntityWithLink entity renderedUrl = case toJSON entity of
    Object obj -> 
        let links = object ["self" .= renderedUrl]
            entityWithLink = HashMap.insert "_links" links obj
        in Just (Object entityWithLink)
    _ -> Nothing
(我假设
renderedUrl
的类型为
Text
,如果需要可以更改)

然后,您只需传入您的
实体
rendereURL
,即可获得包含
“\u links”
键的新
值。我在这里使用了
Maybe
来防止
toJSON::Entity->Value
不使用
对象
构造函数返回
值的情况。如果您更改
实体
类型及其转换为JSON的方式,但忘记更新所有代码库以反映此更改,这将在将来保护您

编辑:如果您要使用
lens aeson
您可以这样写,尽管这需要交换参数顺序以保持整洁:

buildEntityWithLink :: Text -> Entity -> Value
buildEntityWithLink renderedUrl = (
    over _Object $
         HashMap.insert "_links" $
                        object ["self" .= renderedUrl]
    ) . toJSON

这实际上可以让您删除
或者
,您无论如何都想这样做,因为镜头的工作方式意味着,如果
对象
不是顶层,则返回原始值,因此
buildEntityWithLink“testlink”([]:[Entity])
将只返回与
toJSON([]:[Entity])
相同的值,即一个空的
数组
toJSON
必须位于镜头操作的外部,因为为了与
\u对象
组合,它必须能够成为一个setter,并且
toJSON
不能轻易地成为setter。相反,我们只需将
实体
预处理为
,然后将其输入到镜头表达式中。我在每个函数的参数列表中添加了空格,使其在我看来更具可读性,但从技术上讲,这都是一行代码。此实现的一个有用特性是,现在可以轻松地将类型签名放宽为
ToJSON A=>Text->A->Value
,这样您就可以将
\u链接添加到任何想要添加的类型。

要执行此操作,您必须手动将
实体
转换为
值,然后使用无序容器中的函数:Data.HashMap.Strict
插入
“\u links”
键,然后再次从中构建一个
值。使用适用于
aeson
的镜头兼容软件包可能会大大简化:

buildEntityWithLink :: Entity -> Text -> Maybe Value
buildEntityWithLink entity renderedUrl = case toJSON entity of
    Object obj -> 
        let links = object ["self" .= renderedUrl]
            entityWithLink = HashMap.insert "_links" links obj
        in Just (Object entityWithLink)
    _ -> Nothing
(我假设
renderedUrl
的类型为
Text
,如果需要可以更改)

然后,您只需传入您的
实体
rendereURL
,即可获得包含
“\u links”
键的新
值。我在这里使用了
Maybe
来防止
toJSON::Entity->Value
不使用
对象
构造函数返回
值的情况。如果您更改
实体
类型及其转换为JSON的方式,但忘记更新所有代码库以反映此更改,这将在将来保护您

编辑:如果您要使用
lens aeson
您可以这样写,尽管这需要交换参数顺序以保持整洁:

buildEntityWithLink :: Text -> Entity -> Value
buildEntityWithLink renderedUrl = (
    over _Object $
         HashMap.insert "_links" $
                        object ["self" .= renderedUrl]
    ) . toJSON
这实际上可以让您删除
或者
,您无论如何都想这样做,因为镜头的工作方式意味着,如果
对象
不是顶层,则返回原始值,因此
buildEntityWithLink“testlink”([]:[Entity])
将只返回与
toJSON([]:[Entity])
相同的值,即一个空的
数组
toJSON
必须位于镜头操作的外部,因为为了与
\u对象
组合,它必须能够成为一个setter,并且
toJSON
不能轻易地成为setter。相反,我们只需将
实体
预处理为
,然后将其输入到镜头表达式中。我在每个函数的参数列表中添加了空格,使其在我看来更具可读性,但从技术上讲,这都是一行代码。此实现的一个有用特性是,现在可以轻松地将类型签名放宽到
ToJSON A=>Text->A->Value
,这样您就可以将
\u链接添加到任何想要添加的类型。

基于工作注释-这是我现在拥有的最后一个代码:

import Data.HashMap.Strict as HashMap (insert)

getEventR :: EventId -> Handler Value
getEventR eid = do
    event <- runDB $ get404 eid

    render <- getUrlRender
    let renderedUrl = render $ EventR eid

    let returnVal = object
          [ "data" .= [buildEntityWithLink (Entity eid event) renderedUrl]]

    return returnVal


buildEntityWithLink :: Entity Event -> Text -> Maybe Value
buildEntityWithLink entity renderedUrl =
    case toJSON entity of
        Object obj ->
            let links = object ["self" .= renderedUrl]
                entityWithLink = HashMap.insert "_links" links obj
            in Just (Object entityWithLink)
        _ -> Nothing
import Data.HashMap.Strict作为HashMap(插入)
getEventR::EventId->处理程序值
getEventR eid=do
事件可能值
buildEntityWithLink实体呈现URL=
case-toJSON实体
对象obj->
让links=object[“self”。=rendereURL]
entityWithLink=HashMap.insert“\u links”links obj
在Just中(对象entityWithLink)
_->没有
现在,根据工作注释,JSON以
self
链接的形式出现,这是我现在拥有的最后一段代码:

import Data.HashMap.Strict as HashMap (insert)

getEventR :: EventId -> Handler Value
getEventR eid = do
    event <- runDB $ get404 eid

    render <- getUrlRender
    let renderedUrl = render $ EventR eid

    let returnVal = object
          [ "data" .= [buildEntityWithLink (Entity eid event) renderedUrl]]

    return returnVal


buildEntityWithLink :: Entity Event -> Text -> Maybe Value
buildEntityWithLink entity renderedUrl =
    case toJSON entity of
        Object obj ->
            let links = object ["self" .= renderedUrl]
                entityWithLink = HashMap.insert "_links" links obj
            in Just (Object entityWithLink)
        _ -> Nothing
import Data.HashMap.Strict作为HashMap(插入)
getEventR::EventId->处理程序值
getEventR eid=do
事件可能值
buildEntityWithLink实体呈现URL=
case-toJSON实体
对象obj->
让links=object[“self”。=rendereURL]
entityWithLink=HashMap.insert“\u links”links obj
在Just中(对象entityWithLink)
_->没有
事实上,现在JSON与
self
链接一样出现了,谢谢。“使用