【问题标题】:Aeson deriveJSON combined with conduit sinkParserAeson derivedJSON 结合管道 sinkParser
【发布时间】:2012-11-08 14:29:38
【问题描述】:

继续我对管道和 aeson 的探索,我将如何在 Yesod book 的这个(稍作修改的)代码 sn-p 中使用我自己的数据类型而不是 Value

{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}
import Network.Wai (Response, responseLBS, Application, requestBody)
import Network.HTTP.Types (status200, status400)
import Network.Wai.Handler.Warp (run)
import Data.Aeson.Parser (json)
import Data.Conduit.Attoparsec (sinkParser)
import Control.Monad.IO.Class (liftIO)
import Data.Aeson (Value(..), encode, object, (.=))
import Control.Exception (SomeException)
import Data.ByteString (ByteString)
import Data.Conduit (ResourceT, ($$))
import Control.Exception.Lifted (handle)

import qualified Data.HashMap.Strict as M
import Data.Aeson.TH (deriveJSON)

-- I ADDED THIS

data JSONRequest = JSONRequest {
    command :: ByteString,
    params :: M.HashMap ByteString ByteString
}

deriveJSON id ''JSONRequest

-- END OF WHAT I ADDED

main :: IO ()
main = run 3000 app

app :: Application
app req = handle invalidJson $ do
    value <- requestBody req $$ sinkParser json
    newValue <- liftIO $ dispatch value
    return $ responseLBS
        status200
        [("Content-Type", "application/json")]
        $ encode newValue

invalidJson :: SomeException -> ResourceT IO Response
invalidJson ex = return $ responseLBS
    status400
    [("Content-Type", "application/json")]
    $ encode $ object
        [ ("message" .= show ex)
        ]

-- Application-specific logic would go here.
dispatch :: Value -> IO Value
dispatch = return

基本上,我想将dispatch的类型更改为JSONRequest -> IO JSONRequest。如何告诉解析器使用我自己的 fromJSON 派生实例?

我尝试只添加一个类型声明,为 json 上的多态返回类型祈祷,但我意识到它严格用于 Value。

【问题讨论】:

    标签: haskell conduit aeson


    【解决方案1】:

    只看类型,你不只需要fmap 你的 fromJSON 超过来自json 的结果吗?有了dispatch 的合适签名,我们只需要:

    -- import Data.Aeson
    app :: Application
    app req = handle invalidJson $ do
          result <- requestBody req $$ sinkParser (fmap fromJSON json)
          next_result <- liftIO $ dispatch result
          return $ responseLBS status200 [("Content-Type", "application/json")] 
                 $ encode next_result   
    
    dispatch :: Result JSONRequest -> IO JSONRequest
    dispatch (Error str) = undefined
    dispatch (Success jsonreq) = return jsonreq
    

    但也许这样写得更清楚一点:

    -- import Data.Aeson
    -- import qualified Data.Attoparsec as Atto
    toRequest ::    Value -> Result JSONRequest
    toRequest = fromJSON   -- specialized now to your fromJSON
    
    jsonRequestParser :: Atto.Parser (Result JSONRequest)
    jsonRequestParser = fmap toRequest json 
    
    app :: Application
    app req = handle invalidJson $ do
          result <- requestBody req $$ sinkParser jsonRequestParser
          next_result <- liftIO $ dispatch result
          return $ responseLBS status200 [("Content-Type", "application/json")]
                 $ encode next_result   
    
    dispatch :: Result JSONRequest -> IO JSONRequest
    dispatch (Error str) = undefined
    dispatch (Success jsonreq) = return jsonreq
    

    我让解析器返回 Result JSONRequest,所以 dispatch 也在处理错误情况,这可能意味着您需要以某种方式处理异常?

    【讨论】:

    • 成功与错误从何而来?
    • 来自Data.Aeson;我刚刚将它添加到我评论的附加导入中。它们在Data.Aeson.Types.Internal 中定义:data Result a = Error String | Success a 这就是fromJSON 返回的内容。给定一个有效的 JSON“值”,它会查看它是否是您的 JSON 类型,如果有效,则返回您的 Haskell 值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    • 2017-11-08
    • 2016-08-11
    • 2017-11-28
    • 2018-12-14
    • 2019-06-27
    相关资源
    最近更新 更多