wsp*_*pbr 4 haskell type-level-computation servant
假设我们有这个简单的 API:
type FooAPI
= "foo"
:> QueryParam "age" Int
:> Get '[PlainText] Text
Run Code Online (Sandbox Code Playgroud)
有没有办法将 type-levelservant的 API 与为其生成 URL 的函数链接起来?喜欢
someMagicFunction :: Proxy api -> SomeTypeFamily api
someMagicFunction = ?
generateURL :: Maybe Int -> Text
generateURL = someMagicFunction (Proxy @FooAPI)
>>> generateURL (Just 42)
"https://somehost/foo?age=42"
>>> generateURL Nothing
"https://somehost/foo"
Run Code Online (Sandbox Code Playgroud)
我想提高 URL 生成的类型安全性,因此如果我向其中添加一些新参数,FooAPI它将立即出现在 的类型中generateURL,并且如果不编辑 的调用,我的代码将无法编译generateURL。
我知道servant-client库,并且我知道该client函数的功能有些类似,但我不知道如何在我的情况下使用这个库。
我想说这Servant.Links正是您正在寻找的。
特别是,在您的情况下,我将使用allLinks生成Link与包含路径和查询参数的 URL 片段相对应的内容:
>>> linkURI $ allLinks (Proxy @FooAPI) Nothing
foo
>>> linkURI $ allLinks (Proxy @FooAPI) (Just 18)
foo?age=18
Run Code Online (Sandbox Code Playgroud)
然后我会将生成的内容转换Link为URI我将指定所需方案和主机名的位置。这是一个完整工作的模块:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
import Data.Proxy
import Data.Text (Text)
import Network.URI
import Servant.API
import Servant.Links
type FooAPI
= "foo"
:> QueryParam "age" Int
:> Get '[PlainText] Text
generateURL :: Maybe Int -> String
generateURL age = show uri
{ uriScheme = "https:"
, uriAuthority = Just nullURIAuth
{ uriRegName = "somehost" }
, uriPath = "/" <> uriPath uri
}
where
uri = linkURI link
link = allLinks (Proxy @FooAPI) age
Run Code Online (Sandbox Code Playgroud)
并演示:
>>> generateURL (Just 42)
"https://somehost/foo?age=42"
>>> generateURL Nothing
"https://somehost/foo"
Run Code Online (Sandbox Code Playgroud)