我的类型和对应的 FromJSON 实现如下所示。nonEmpty
变成 List
变成 Maybe NonEmpty
我正在尝试正确处理 List
的情况确实是空的,我必须中止解析。这个解析实际上是在 parseJsonBody
内部完成的。 ,这意味着我不想 error "foo"
我的出路,但我想返回mzero
(或者其他任何可以解决问题的方法,mzero
是我迄今为止偶然发现的唯一东西)以便处理程序正确返回 400 而不是以 500 崩溃。
下面的方法可以编译,但据我所知几乎等于 error
或在 parseJSON 中抛出某种其他形式的异常。如果我返回 mzero
但是(例如,使用 <*> mzero
而不是该行),它按预期很好地失败了。
import qualified Data.List.NonEmpty as NE
data GSAnswer = GSAnswer { gsAnswerQuestionId :: Int
, gsAnswerResponses :: NE.NonEmpty GSResponse
} deriving (Show, Eq)
instance FromJSON GSAnswer where
parseJSON (Object o) =
GSAnswer <$> o .: "question-id"
-- how do I return mzero here based on NE.nonEmpty?
-- this will throw an exception right now on an empty list
<*> fmap (fromMaybe (fail "foo") . NE.nonEmpty) (o .: "responses")
parseJSON _ = mzero
一种选择是以某种方式对
fmap NE.nonEmpty (o .: "responses")
的结果进行模式匹配。 ,但我不太清楚那里的模式是什么:看起来 Parser 没有任何构造函数?
最佳答案
本质上,您需要一个 Parser [a] -> Parser NE.NonEmpty
变压器,比较简单:
-- toNonEmptyP :: Parser [a] -> Parser NE.NonEmtpy
toNonEmptyP p = fmap NE.nonEmpty p >>= maybe mzero return
我们 map
NE.nonEmpty
在我们的常规列表解析器上,它给了我们 Parser (Maybe NE.NonEmpty)
.然后我们检查 Maybe
与 maybe
或者使用 mzero
如果是 Nothing
, 或 return
解析后的值返回到解析上下文。您的 FromJSON
实例然后归结为instance FromJSON GSAnswer where
parseJSON (Object o) =
GSAnswer <$> o .: "question-id"
<*> toNonEmptyP (o .: "responses")
parseJSON _ = mzero
您可以使用
fail msg
而不是 mzero
提供自定义错误消息,如 fail :: String -> Parser a
没有触底。
关于parsing - 如何在使用 Data.Aeson 解析 JSON 时正确出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28494209/