Haskell Yesod-在将json内的对象转换为模型之前 [英] Haskell Yesod - extracting a object inside a json before converting it to a model

查看:57
本文介绍了Haskell Yesod-在将json内的对象转换为模型之前的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个像这样的JSON:

Suppose I have a JSON like this:

{
  data: {...}
}

{...} 代表我的模型.怎么可能在这种情况下,在Handler中获取我的模型?例如,以下内容显然不起作用:

and {...} represents a model of mine. How could get my model in this case in the Handler? For instance, the following will not work obviously:

putMyEntityR :: Handler ()
putMyEntityR = do
  (Entity id _) <- (...) -- getting the Key
  e <- requireJsonBody :: Handler MyEntity
  runDB $ replace id e
  sendResponseStatus status204 ("UPDATED" :: Text)

如何读取 JSON ,获取 data 对象,然后对其进行解码?

How can I read the JSON, take the data object, and only then decode it?

推荐答案

There was some more discussion of this question on a Github Issue, which I'm adding as an answer here because it's more fleshed out. Here's what we arrive at for the Handler function using the helper functions defined below:

postDataCommentR :: Handler Value
postDataCommentR = do
  value <- requireJsonBody' -- Parse request body into Value
  commentJson <- requireJsonKey "data" value -- Lookup a key from the Value
  comment <- (requireJsonParse commentJson :: Handler Comment) -- Parse the Value into a comment record

  insertedComment <- runDB $ insertEntity comment
  returnJson insertedComment

这些函数获取请求正文并将其解析为aeson Value :

These functions take the request body and parse it into an aeson Value:

import qualified Data.Aeson as J
import qualified Data.Aeson.Parser as JP
import Data.Conduit.Attoparsec (sinkParser)

-- These two functions were written by @FtheBuilder
parseJsonBody' :: (MonadHandler m) => m (J.Result Value)
parseJsonBody' = do
    eValue <- rawRequestBody $$ runCatchC (sinkParser JP.value')
    return $ case eValue of
        Left e -> J.Error $ show e
        Right value -> J.Success value

-- | Same as 'parseJsonBody', but return an invalid args response on a parse
-- error.
requireJsonBody' :: (MonadHandler m) => m Value
requireJsonBody' = do
    ra <- parseJsonBody'
    case ra of
        J.Error s -> invalidArgs [pack s]
        J.Success a -> return a

这些帮助器函数用于将 Value 解析为一条记录:

These helper functions are used to parse that Value into a record:

requireJsonParse :: (MonadHandler m, FromJSON a) => Value -> m a
requireJsonParse v = case J.fromJSON v of
  J.Error s -> invalidArgs [pack s]
  J.Success a -> return a

requireJsonKey :: (MonadHandler m) => Text -> Value -> m Value
requireJsonKey key jObject@(Object hashMap) = case lookup key hashMap of
                                    Nothing -> invalidArgs ["Couldn't find a value when looking up the key " <> key <> " in the object: " <> (pack (show jObject))]
                                    Just v -> return v
requireJsonKey key invalid = invalidArgs ["When looking up the key " <> key <> ", expected an object but got a " ++ (pack (show invalid))]

评论

aeson-lens

我没有使用 aeson-lens ,但是无论有没有代码,它的代码都非常相似,因为我们只深入一键.如果我们更深入地研究JSON,则 aeson-lens 会使事情变得更好.

Commentary

aeson-lens

I didn't use aeson-lens, but the code is pretty similar with or without it, since we're just going one key deep. aeson-lens would make things nicer if we were traversing deeper into the JSON.

一旦定义了辅助函数,您仍然可以使用几行来解析 Value ,然后查找 data 键,然后创建记录.您可以采取一些措施来缩短它的长度,但是最终@Carsten建议的包装器的长度应该差不多,而且复杂度也要低得多.

Once you get the helper functions defined, you still have a couple lines to parse a Value, then lookup the data key, then create your record. You can do things to make this shorter, but ultimately the wrapper that @Carsten recommended would be of similar length with less complexity, imo.

这篇关于Haskell Yesod-在将json内的对象转换为模型之前的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆