Haskell/Wreq - 关于http请求的复杂类型签名的建议



我是Haskell初学者,目前正在使用wreq在API周围制作一个简单的包装器。 如果提供时间,我想发送一个if-modified-since标头。 我这样做的方式如下。

getResponse :: (FormatTime t, Exception e) => File -> Maybe t -> IO (Either e (Response L.ByteString))
getResponse file (Just t) =
let formattedTime = (B.pack . formatTime defaultTimeLocale rfc822DateFormat) t
opts = defaults & header "if-modified-since" .~ [formattedTime]
in try $ getWith opts $ buildUrl file
getResponse file Nothing = try $ (get $ buildUrl file)

我注意到304 (not modified)响应作为异常返回,因此这是我使用Either类型的理由。 我想为可能使用此 api 包装器的人提供错误的可见性。

假设请求成功,我想将响应正文解析为库中定义的相应类型。如果我正在向其发出请求的服务器上发生更改,则反序列化可能无法正常工作,因此我选择使用Maybe类型来说明这一点。

getPayload :: FromJSON b => (Either e (Response L.ByteString)) -> Either e (Maybe b)
getPayload (Left _)  = return Nothing
getPayload (Right a) = return $ fmap Just (^. responseBody) =<< asJSON a

这些功能的签名对我来说开始变得碍眼,我的直觉告诉我有更好的方法,但我不确定。我做的一件事是制作另一个功能将它们放在一起,希望它更容易使用。 这是我计划用来创建其他函数以对单个资源发出更具体请求的函数。

getResource :: (Exception e, FormatTime t, FromJSON b) => File -> Maybe t -> IO (Either e (Maybe b))
getResource f t =  getPayload <$> (getResponse f t)

我现在在处理 http 请求时必须处理 3 层结构。IOEitherMaybe。 我把这弄得太复杂了吗?从使用和可维护性的角度来看,我该怎么做才能减少使用时的痛苦?我怎样才能改善这一点?

这可能不是你想要的,但asJSON的返回类型m (Response a),其中m是一个MonadThrow。虽然Maybe是一个MonadThrow实例,但Either e也是如此。这意味着您不必使用Maybe来处理asJSON是否出现任何问题。你可以"停留"在Either的monad中:

getPayload :: FromJSON b => Either SomeException (Response L.ByteString)
-> Either SomeException b
getPayload = ((fmap (^. responseBody) . asJSON) =<<)

显然,这对左侧的错误类型施加了额外的约束,所以我不确定这是否可以接受。如果没有,请发表评论。

相关内容

  • 没有找到相关文章

最新更新