【问题标题】:Haskell Servant: Construct URL from APIHaskell Servant:从 API 构造 URL
【发布时间】:2021-12-23 15:42:26
【问题描述】:

假设我们有这个简单的 API:

type FooAPI
   = "foo" 
  :> QueryParam "age" Int 
  :> Get '[PlainText] Text

有没有办法将类型级别的servant 的 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"

我想增加 URL 生成的类型安全性,所以如果我向 FooAPI 添加一些新参数,它将立即以 generateURL 的类型出现,并且如果不编辑 @987654326 的调用,我的代码将无法编译@。

我知道servant-client 库,并且我知道client 函数的功能有些相似,但我不知道如何在我的情况下使用这个库。

【问题讨论】:

  • 这是可能的,但需要编写大量实例。我在此处或 reddit 上发表了评论,指出了特定的课程,但我只想说,当我寻找 Servant 0.14 时,这不是一份便宜的工作,而且还没有在图书馆为你完成。

标签: haskell type-level-computation servant


【解决方案1】:

我想说Servant.Links 正是您要找的。​​p>

特别是,在您的情况下,我将使用 allLinks 生成一个 Link 对应于包含路径和查询参数的 URL 片段:

>>> linkURI $ allLinks (Proxy @FooAPI) Nothing
foo
>>> linkURI $ allLinks (Proxy @FooAPI) (Just 18)
foo?age=18

然后我会将生成的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

及示范:

>>> generateURL (Just 42)
"https://somehost/foo?age=42"
>>> generateURL Nothing
"https://somehost/foo"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-25
    • 1970-01-01
    • 2014-04-18
    • 2011-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多