微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何让 GHC 将我的孤立实例“HasServer”和“HasClient”应用于“AuthProtect”?

如何解决如何让 GHC 将我的孤立实例“HasServer”和“HasClient”应用于“AuthProtect”?

我使用 servant: Servant.API.Experimental.Auth 中的 AuthProtect 组合子。那里没有太多代码,实例 HasServer (AuthProtect tag) 位于 servant-server 中,实例 HasClient (AuthProtect tag) 位于您使用的任何服务客户端中。

我使用 servant-snap 而不是 servant-server 以及一个 HasClient 项目的自定义 obelisk 实现,其项目结构由三个 cabal 包组成:

  • 前端(由 ghcjs 编译)
  • common(由 ghcjs ghc 编译)
  • 后端(由 ghc 编译)

我曾经有一个 AuthProtect自定义实现以及 common 包中的实例。但是,由于 ghcjs,common 既不能依赖于 servant-snap,也不能依赖于 snap-core

现在我将 HasServer 实例移到后端......没问题,对吧?错误的。一旦 HasServer 实例被孤立,ghc 就不再正确解析我的 api 类型。就好像孤立的实例根本不存在一样。

这是为什么?

有什么,我能做什么?

解决方法

实例是全球性的...理论上。在实践中,为了支持单独编译,它们通过导入进行传播。因此,从使用它的模块导入定义实例的模块。以传递方式导入它就足够了 - 即导入一个模块,该模块导入一个模块,该模块导入定义实例的模块。

,

其中任何一个都解决了我的问题:

instance HasServer api context m => HasServer (AuthProtect "jwt" :> api) context m where
  type ServerT (AuthProtect "jwt" :> api) context m =
    String -> ServerT api context m

  hoistServerWithContext _ pc nt s = hoistServerWithContext (Proxy :: Proxy api) pc nt . s

  route (Proxy :: Proxy (AuthProtect "jwt" :> api)) context subserver =
    route (Proxy :: Proxy api) context (subserver `addAuthCheck` withRequest authCheck)
      where
        authCheck :: Request -> DelayedM m String
        authCheck =
          liftIO . evalSnap (pure "account info")
                            (\x -> pure $! (x `seq` ()))
                            (\f -> let !_ = f 0 in pure ())

如果我出于某种原因不想专门研究 AuthProtect "jwt",我必须提供约束 KnownSymbol tag

instance (KnownSymbol tag,HasServer api context m) => HasServer (AuthProtect tag :> api) context m where
  type ServerT (AuthProtect tag :> api) context m =
    String -> ServerT api context m

  hoistServerWithContext _ pc nt s = hoistServerWithContext (Proxy :: Proxy api) pc nt . s

  route (Proxy :: Proxy (AuthProtect tag :> api)) context subserver =
    route (Proxy :: Proxy api) context (subserver `addAuthCheck` withRequest authCheck)
      where
        authCheck :: Request -> DelayedM m String
        authCheck =
          liftIO . evalSnap (pure "account info")
                            (\x -> pure $! (x `seq` ()))
                            (\f -> let !_ = f 0 in pure ())

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。