Jos*_*h.F 7 haskell yesod aeson
编辑:对于有类似疾病的人,我发现这与"可扩展记录问题"有关,我将亲自研究这些问题.
编辑2:我已经开始通过非常明确地了解数据类型以及每个语义数据单元具有多种数据类型来解决这个问题(几周后).例如,如果数据库包含一个X,我的代码有一个XAction用于表示我想用a做的事情X,以及XResponse用于将Xs 中继到http客户端的代码.然后我需要构建支持代码来在实例之间穿梭.不理想,但是,我喜欢它是明确的,并且希望当我的模型结晶时,它不应该真的需要太多保持,并且应该非常可靠.
我不确定解决这个问题的正确抽象级别是什么(即记录?还是Yesod?)所以我将只列出一个简单的案例.
我想将请求主体解码为一个类型
data Comment = Comment {userid :: ..., comment :: ...}
但实际上我不希望请求体包含userid,服务器将根据其Auth Headers(或者我想要将数据默认填充字段的任何地方)提供.
所以他们实际上传给我的是:
data SimpleComment = SimpleComment {comment :: ...} deriving (Generic, FromJSON)
我把它变成了一个Comment.但同时保持两种几乎相同的类型是麻烦,而不是干.
我该如何解决这个问题?
我有一个记录类型:
data Comment = Comment {userid :: ..., comment :: ...}
我有一个POST路线:
postCommentR :: Handler Value
postCommentR = do
c <- requireJsonBody :: (Handler Comment)
insertedComment <- runDB ...
returnJson insertedComment
Run Code Online (Sandbox Code Playgroud)
请注意,Route要求用户提供userid(在Comment类型中,至少是冗余的,因为他们的id与其auth头相关联.最坏的情况是,这意味着我需要检查用户是否正在添加自己的ID,或者丢弃他们提供的id,在这种情况下他们为什么在第一种情况下提供它.
所以,我想要一个Comment减去的记录类型userid,但我不知道如何智能地做到这一点.
所以我创建了一个带派生的自定义类型FromJSON(对于请求体),它几乎完全是Comment类型的冗余.
data SimpleComment = SimpleComment {comment :: ...} deriving (Generic, FromJSON)
然后我的新路由需要根据此解码请求主体,然后将a SimpleComment与userid字段合并以使其成为Comment:
postComment2R :: Handler Value
postComment2R = do
c <- requireJsonBody :: (Handler SimpleComment)
(uid, _) requireAuthPair
insertedComment <- runDB $ insertEntity (Comment { commentUserid = uid
, commentComment = comment c})
returnJson ...
Run Code Online (Sandbox Code Playgroud)
谈论样板.我的用例比这种简单Comment类型更复杂.
如果它是因素,你可能会说,我正在使用Yesod脚手架.
我喜欢的一个解决方案是对来自/去往数据库的事物使用包装器:
data Authenticated a = Authenticated
{ uid :: Uid
, thing :: a
} deriving (Show)
Run Code Online (Sandbox Code Playgroud)
然后你就可以Comment把SimpleComment它变成Authenticated Comment一旦你知道用户ID。