如何解决使用 RIO
我正在尝试将 Servant 身份验证(servant-auth-server 包)与 RIO 结合作为我的处理程序 monad,以避免出现 ExceptT 反模式。但是,我无法正确排列类型以处理被拒绝的身份验证。
我的(简化的)API 端点是
type UserEndpoint = "user" :> (
Get '[JSON] User
:<|> ReqBody '[JSON] UpdatedUser :> Put '[JSON] User
)
和对应的服务器
protectedServer
:: HasLogFunc m
=> AuthResult AuthUserId
-> ServerT UserEndpoint (RIO m)
protectedServer (Authenticated authUser) =
getUser authUser :<|> updateUser authUser
-- Otherwise,we return a 401.
protectedServer _ = throwIO err401
在拒绝身份验证的分支中出现类型错误:
Could not deduce (Monadio ((:<|>) (RIO m User)))
arising from a use of ‘throwIO’
[..]
我不理解这种类型的错误。根据我的理解(并给出 protectedServer
的签名),返回类型应该是 ServerT UserEndpoint (RIO m)
,它应该有一个 Monadio
的实例,以便根据 {{3} } 应该使用 throwIO
而不是 throwAll
中的 Servant.Auth.Server
。看来我还没有完全理解Servant的类型机制,我的错误在哪里?
两个处理函数定义为
updateUser :: HasLogFunc m => AuthUserId -> UpdatedUser -> RIO m User
updateUser authUser updateUser = ...
getUser :: HasLogFunc m => AuthUserId -> RIO m User
getUser authUser = ...
解决方法
问题在于 throwIO err401
是一个单个 RIO
操作。但是当一个servant服务器有多个端点时,每个不同的处理程序都必须由:<|>
组合子组成。
如果您的 API 有许多端点,那么为每个端点编写 401 返回处理程序很快就会变得烦人。幸运的是,servant-auth-server 似乎提供了一个 throwAll
辅助函数,可以为整个 API 自动构建错误返回处理程序。
编辑:正如 Ulrich 所指出的,throwAll
的问题在于它只适用于 MonadError
单子,而 RIO
不是 { {1}}。但是应该可以修改类型类以使其支持 MonadError
。
首先,一些导入和辅助数据类型:
RIO
这是主要的 {-# LANGUAGE UndecidableInstances,TypeOperators,FlexibleInstances,TypeFamilies,DataKinds,ImportQualifiedPost
#-}
module Main where
import RIO (RIO) -- rio
import RIO qualified
import Data.Tagged (Tagged (..)) -- package tagged
import Servant ((:<|>) (..),ServerError(..))
import Network.HTTP.Types -- package http-types
import Network.Wai -- package wai
import Data.ByteString.Char8 qualified as BS
类型类:
RIOThrowAll
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。