将模式匹配与 servant-client 结合使用的问题
Issues using pattern matching with servant-client
在Servant docs中,我们有以下api:
type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
:<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
:<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
我们可以这样定义客户端函数:
api :: Proxy API
api = Proxy
position :<|> hello :<|> marketing = client api
如果我们的 api 类型看起来像:
type API = QueryParam "test" Int :> (
"position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
:<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
:<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email)
与原始 api 相同,但为所有端点增加了一个额外的 "test" 查询参数,我们将如何获取我们的客户端函数?我已经尝试了几种模式匹配的变体,但都无济于事。
如果一切都失败了,"test" 查询参数可以在每个端点的 api 类型中重复,但这是 Haskell,我们尽量避免重复。
Servant API 定义存在于类型级别。如果我们想要操作它们,我们需要类似函数的东西,将类型(不是值,类型本身)转换为其他类型。
在 Haskell 中最接近这种类型级函数的东西叫做 closed type family:
{-# LANGUAGE TypeFamilies #-}
type family PrependParam api where
PrependParam (a :<|> b) = PrependParam a :<|> PrependParam b
PrependParam leaf = QueryParam "test" Int :> leaf
type API' = PrependParam API
:<|>
分隔路线,而 :>
分隔路线内的组件。我们正在映射路由树并为每个路由添加前缀。
我们可以使用 kind!
命令从 ghci 检查它是否有效:
ghci> :kind! API'
API' :: *
= (QueryParam "test" Int
:> ("position"
:> (Capture "x" Int :> (Capture "y" Int :> Get '[JSON] Position))))
:<|> ((QueryParam "test" Int
:> ("hello"
:> (QueryParam "name" String :> Get '[JSON] HelloMessage)))
:<|> (QueryParam "test" Int
:> ("marketing"
:> (ReqBody '[JSON] ClientInfo :> Post '[JSON] Email))))
在Servant docs中,我们有以下api:
type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
:<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
:<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email
我们可以这样定义客户端函数:
api :: Proxy API
api = Proxy
position :<|> hello :<|> marketing = client api
如果我们的 api 类型看起来像:
type API = QueryParam "test" Int :> (
"position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position
:<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage
:<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email)
与原始 api 相同,但为所有端点增加了一个额外的 "test" 查询参数,我们将如何获取我们的客户端函数?我已经尝试了几种模式匹配的变体,但都无济于事。
如果一切都失败了,"test" 查询参数可以在每个端点的 api 类型中重复,但这是 Haskell,我们尽量避免重复。
Servant API 定义存在于类型级别。如果我们想要操作它们,我们需要类似函数的东西,将类型(不是值,类型本身)转换为其他类型。
在 Haskell 中最接近这种类型级函数的东西叫做 closed type family:
{-# LANGUAGE TypeFamilies #-}
type family PrependParam api where
PrependParam (a :<|> b) = PrependParam a :<|> PrependParam b
PrependParam leaf = QueryParam "test" Int :> leaf
type API' = PrependParam API
:<|>
分隔路线,而 :>
分隔路线内的组件。我们正在映射路由树并为每个路由添加前缀。
我们可以使用 kind!
命令从 ghci 检查它是否有效:
ghci> :kind! API'
API' :: *
= (QueryParam "test" Int
:> ("position"
:> (Capture "x" Int :> (Capture "y" Int :> Get '[JSON] Position))))
:<|> ((QueryParam "test" Int
:> ("hello"
:> (QueryParam "name" String :> Get '[JSON] HelloMessage)))
:<|> (QueryParam "test" Int
:> ("marketing"
:> (ReqBody '[JSON] ClientInfo :> Post '[JSON] Email))))