如何在 JSON 解析 Data.Aeson 时正确出错
How to correctly error out in JSON parsing with Data.Aeson
我的类型和相应的 FromJSON 实现如下所列。
nonEmpty
将 List
变成 Maybe NonEmpty
,我正在尝试正确处理 List
确实为空的情况,我必须中止解析。这个解析实际上是在 parseJsonBody
内部完成的,这意味着我不想 error "foo"
我想摆脱它,但我想 return mzero
(或其他任何东西会成功的,mzero
是我迄今为止偶然发现的唯一东西)这样处理程序就可以正确地 return 发送 400 而不是崩溃 500。
下面的方法可以编译,但据我所知,它几乎等于 error
或在 parseJSON 内部抛出某种其他形式的异常。但是,如果我 return 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
我们将 NE.nonEmpty
映射到我们的常规列表解析器,这给了我们 Parser (Maybe NE.NonEmpty)
。然后,我们用 maybe
检查 Maybe
,如果它是 Nothing
,则使用 mzero
,或者 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
不会触底。
我的类型和相应的 FromJSON 实现如下所列。
nonEmpty
将 List
变成 Maybe NonEmpty
,我正在尝试正确处理 List
确实为空的情况,我必须中止解析。这个解析实际上是在 parseJsonBody
内部完成的,这意味着我不想 error "foo"
我想摆脱它,但我想 return mzero
(或其他任何东西会成功的,mzero
是我迄今为止偶然发现的唯一东西)这样处理程序就可以正确地 return 发送 400 而不是崩溃 500。
下面的方法可以编译,但据我所知,它几乎等于 error
或在 parseJSON 内部抛出某种其他形式的异常。但是,如果我 return 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
我们将 NE.nonEmpty
映射到我们的常规列表解析器,这给了我们 Parser (Maybe NE.NonEmpty)
。然后,我们用 maybe
检查 Maybe
,如果它是 Nothing
,则使用 mzero
,或者 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
不会触底。