在URI上定义FromJSON

时间:2017-10-22 01:49:46

标签: haskell aeson

使用Network-URI和Aeson,我定义了以下FROMJson URI

简而言之,我试图实现一个需要的JSON解码器:

{ "value" : X }其中X是一个JSON字符串,其parseURIJust)的评估结果为X

instance FromJSON URI where
    parseJSON = withObject "URI" $ \v ->
      case Data.HashMap.Lazy.lookup "value" v of
        Just (String str) -> let unpacked = T.unpack str in
          case parseURI unpacked of
            Just uri -> pure uri
            Nothing  -> fail $ "String:" ++ unpacked ++ "is not a valid URI."
        Just value        -> typeMismatch "value" value
        Nothing           -> fail $ "JSON object does not have 'value' key."

但是,对于有效的URI,我的代码无效:

λ: >parseURI "http://www.foo.com"
Just http://www.foo.com

λ: >toJSON $ URI "http" Nothing "//www.foo.com" "" ""
String "http//www.foo.com"

λ: >fromJSON $ toJSON $ URI "http" Nothing "//www.foo.com" "" ""
Error "expected (), encountered String"

如何修复我的FromJSON实例?

1 个答案:

答案 0 :(得分:2)

您的实例需要一个形状为{ "value": "url" }的JSON对象,但您正在使用的toJSON实例显然会产生一个纯字符串,因为您的交互式输出清楚地表明了这一点。

要使交互式会话中的最后一个表达式起作用,您需要使ToFrom个实例对称:或者让ToJSON实例生成一个对象{ "value": "url" }或者使FromJSON实例期望一个普通的字符串。

另外,您可以使用.:运算符以更短的方式表达您的实例:

instance FromJSON URI where
    parseJSON = withObject "URI" $ \v -> do
        mUri <- parseURI . T.unpack <$> v .: "value"
        maybe (fail "Bad URI") pure mUri