I'm trying to combine Servant authentication (servant-auth-server package) with RIO as my handler monad to avoid the ExceptT anti-pattern. However, I can't line up the types properly for handling denied authentications.
My (simplified) API endpoint is
type UserEndpoint = "user" :> (
Get '[JSON] User
:<|> ReqBody '[JSON] UpdatedUser :> Put '[JSON] User
)
and the corresponding server
protectedServer
:: HasLogFunc m
=> AuthResult AuthUserId
-> ServerT UserEndpoint (RIO m)
protectedServer (Authenticated authUser) =
getUser authUser :<|> updateUser authUser
-- Otherwise, we return a 401.
protectedServer _ = throwIO err401
A type error arises in the branch for denied authentication:
Could not deduce (MonadIO ((:<|>) (RIO m User)))
arising from a use of ‘throwIO’
[..]
I don't grok this type error. To my understanding (and given the signature of protectedServer
), the return type should be ServerT UserEndpoint (RIO m)
, which should have an instance of MonadIO
, so that exception handling according to the exceptions tutorial should use throwIO
instead of throwAll
from Servant.Auth.Server
. It seems that I haven't fully understood Servant's type machinery yet, where is my mistake?
The two handler functions are defined as
updateUser :: HasLogFunc m => AuthUserId -> UpdatedUser -> RIO m User
updateUser authUser updateUser = ...
getUser :: HasLogFunc m => AuthUserId -> RIO m User
getUser authUser = ...