如何为一组处理程序提供从 servant 中的 Db 获取的值?
How to feed a group of handlers with value fetched from Db in servant?
我正在使用带有 JWT 身份验证的 servant。我正在尝试获取经过身份验证的用户并将其传递给处理程序,而不必在每个处理程序中重复相同的逻辑。
使用单个参数函数,它就像一个魅力:
listMeters :: Entity User -> Handler [Meter]
protected :: Servant.Auth.Server.AuthResult Token -> Server Protected
protected (Servant.Auth.Server.Authenticated email) = do
user <- getUser email
listMeters user
另一方面,当我尝试对采用两个参数的函数执行相同操作时:
addMeter :: Entity User -> Meter -> Handler Meter
protected :: Servant.Auth.Server.AuthResult Token -> Server Protected
protected (Servant.Auth.Server.Authenticated email) = do
user <- getUser email
addMeter user
它抛出编译错误:
/usr/src/app/src/Handlers.hs:57:3: error:
• Couldn't match type ‘Handler b0’ with ‘Meter -> Handler Meter’
Expected type: Server Protected
Actual type: Handler b0
• In a stmt of a 'do' block: user <- getUser email
In the expression:
do user <- getUser email
addMeter user
In an equation for ‘protected’:
protected (Authenticated email)
= do user <- getUser email
addMeter user
|
57 | user <- getUser email
| ^^^^^^^^^^^^^^^^^^^^^
/usr/src/app/src/Handlers.hs:64:3: error:
• Couldn't match expected type ‘Handler b0’
with actual type ‘Meter -> Handler Meter’
• Probable cause: ‘addMeter’ is applied to too few arguments
In a stmt of a 'do' block: addMeter user
In the expression:
do user <- getUser email
addMeter user
In an equation for ‘protected’:
protected (Authenticated email)
= do user <- getUser email
addMeter user
|
64 | addMeter user
| ^^^^^^^^^^^^^
从数据库中获取用户的函数:
getUser :: Token -> Handler (Entity User)
getUser email = do
userEntity <- liftIO $ runSql $ getBy $ UniqueEmail email
case userEntity of
Nothing -> throwError err401
Just user -> return user
为什么第一个示例有效而另一个无效? servant遇到这样的情况如何妥善解决?
在这个特定问题中,创建 IsAuth 的自定义实例似乎是最佳解决方案。不过似乎没有 official/idiomatic 方法。
我已经解决了这个问题:
data UserCookie
extractUser userId = (maybe mzero (return . Entity userId)) =<< fetch
where
fetch = liftIO $ runSql $ get userId
instance IsAuth UserCookie (Entity User) where
type AuthArgs UserCookie = '[CookieSettings, JWTSettings]
runAuth _ _ = \c jwt -> extractUser =<< cookieAuthCheck c jwt
这个 link 也可能有帮助:https://github.com/haskell-servant/servant-auth/issues/73
我正在使用带有 JWT 身份验证的 servant。我正在尝试获取经过身份验证的用户并将其传递给处理程序,而不必在每个处理程序中重复相同的逻辑。
使用单个参数函数,它就像一个魅力:
listMeters :: Entity User -> Handler [Meter]
protected :: Servant.Auth.Server.AuthResult Token -> Server Protected
protected (Servant.Auth.Server.Authenticated email) = do
user <- getUser email
listMeters user
另一方面,当我尝试对采用两个参数的函数执行相同操作时:
addMeter :: Entity User -> Meter -> Handler Meter
protected :: Servant.Auth.Server.AuthResult Token -> Server Protected
protected (Servant.Auth.Server.Authenticated email) = do
user <- getUser email
addMeter user
它抛出编译错误:
/usr/src/app/src/Handlers.hs:57:3: error:
• Couldn't match type ‘Handler b0’ with ‘Meter -> Handler Meter’
Expected type: Server Protected
Actual type: Handler b0
• In a stmt of a 'do' block: user <- getUser email
In the expression:
do user <- getUser email
addMeter user
In an equation for ‘protected’:
protected (Authenticated email)
= do user <- getUser email
addMeter user
|
57 | user <- getUser email
| ^^^^^^^^^^^^^^^^^^^^^
/usr/src/app/src/Handlers.hs:64:3: error:
• Couldn't match expected type ‘Handler b0’
with actual type ‘Meter -> Handler Meter’
• Probable cause: ‘addMeter’ is applied to too few arguments
In a stmt of a 'do' block: addMeter user
In the expression:
do user <- getUser email
addMeter user
In an equation for ‘protected’:
protected (Authenticated email)
= do user <- getUser email
addMeter user
|
64 | addMeter user
| ^^^^^^^^^^^^^
从数据库中获取用户的函数:
getUser :: Token -> Handler (Entity User)
getUser email = do
userEntity <- liftIO $ runSql $ getBy $ UniqueEmail email
case userEntity of
Nothing -> throwError err401
Just user -> return user
为什么第一个示例有效而另一个无效? servant遇到这样的情况如何妥善解决?
在这个特定问题中,创建 IsAuth 的自定义实例似乎是最佳解决方案。不过似乎没有 official/idiomatic 方法。
我已经解决了这个问题:
data UserCookie
extractUser userId = (maybe mzero (return . Entity userId)) =<< fetch
where
fetch = liftIO $ runSql $ get userId
instance IsAuth UserCookie (Entity User) where
type AuthArgs UserCookie = '[CookieSettings, JWTSettings]
runAuth _ _ = \c jwt -> extractUser =<< cookieAuthCheck c jwt
这个 link 也可能有帮助:https://github.com/haskell-servant/servant-auth/issues/73