Servant使用Servant.API.safeLink
来生成相对URL,但是我遇到了一个问题,使我认为我对如何使用它或如何定义Servant API误解了一些基本知识。
我构建的最小示例包含两个端点。一个目标是在(相对URL)/foo
处成为“前门”端点,另一个目标是在/foo/1
处:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import Servant
data HTML
type Foo = "foo" :> (Foo0 :<|> Foo1)
type Foo0 = Get '[HTML] String
type Foo1 = "1" :> Get '[HTML] String
slFoo :: Link
slFoo = safeLink (Proxy :: Proxy Foo) (Proxy :: Proxy Foo1)
上面slFoo
的定义给了我错误
Could not deduce: IsElem' ("1" :> Get '[HTML] String) ("foo" :> (Foo0 :<|> Foo1))
...这恰恰是当我要求safeLink产生一个链接时出现的错误,该链接不在其第一个参数定义的API中。当safeLink
的第二个参数改为Proxy :: Foo0
时,错误类似。
我已经尝试了很多这种排列方式,但似乎无法自己使用找到的文档来解决。我希望能得到一些提示,让我弄清楚我的误解在哪里。
答案 0 :(得分:0)
该示例不起作用,因为您为端点定义的类型Foo1
本身不包含相对于Foo
API顶部的自身完整路径。
解决此问题的一种方法是改用“扁平化” API:
safeLink (Proxy :: Proxy (Flat Foo)) (Proxy :: Proxy (Nth 1 (Flat Foo)))
(还需要import Servant.API.Flatten
)
缺点是您必须知道Foo1
在Foo
中的序数位置。似乎没有一种方法可以通过使用问题中指定的类型来获得所需的答案。您可以首先定义扁平化的API,但要以使结构清晰(IMO)为代价。
感谢Alp Mestanogullari在上述问题的评论中向我解释了这一点。他的答案应该真的很值得!