如何创建将在 Servant 中的任何路径上触发的路由?

How to create route that will trigger on any path in Servant?

我在 Haskell Servant App 中有一个类型级函数(又名类型族),它接受一个符号并生成一个类型(路由),即

type family AppRoute (x :: Symbol) where
    AppRoute x = x :> Get '[HTML] RawHtml

预计将在API中使用:

type ServerAPI = 
    Get '[HTML] RawHtml 
    :<|> UserAPI
    :<|> AdminAPI
    :<|> AppRoute "about" 
    :<|> AppRoute "contact" 
    :<|> AppRoute "services"
    :<|> AppRoute "blog"
    :<|> AppRoute "products"

对应的服务器函数为

server :: Server ServerAPI
server = 
    html
    :<|> userServer
    :<|> adminServer
    :<|> html
    :<|> html
    :<|> html
    :<|> html
    :<|> html

基本上所有的 AppRoutes 都去同一个端点(原始 html 文件)。有没有办法通过写类似的东西来消除重复(指的是最后五个路线)(这不会编译)

type family AppRoute where
    AppRoute = String :> Get '[HTML] RawHtml

type ServerAPI =
    Get '[HTML] RawHtml
    :<|> UserAPI
    :<|> AdminAPI
    :<|> AppRoute _  -- * the problem is here. One function is needed here

有对应的服务器

server :: Server ServerAPI
server = 
    html
    :<|> userServer
    :<|> adminServer
    :<|> html

所以实际上,AppRoutes 是一个类型级别的函数,它接受任何字符串和 returns 一个路由。

综上所述,不写

:<|> AppRoute "about" :<|> AppRoute "contact" :<|> AppRoute "services" :<|> AppRoute "products"

我希望能够只写 :<|> AppRoute _

您可以使用Capture 来捕获任何路径。但是,它需要以 : 字符开头。例如

type AppRoute = Capture "routePath" String :> Get '[HTML] RawHtml

type ServerAPI =
    Get '[HTML] RawHtml
    :<|> UserAPI
    :<|> AdminAPI
    :<|> AppRoute

现在,AppRoute 将在 yourserver.com/:thisIsMyPath/ 上触发并将 "thisIsMyPath" 作为端点的参数传递。我目前不知道如何绕过这个 :。假设 html 是此时不依赖于给定路径的端点,您可以将整个服务器定义为

server :: Server ServerAPI
server = html
  :<|> userServer
  :<|> adminServer
  :<|> const html

你可能会读到它 here


顺便说一句,为什么不使用 type 别名而不是采用 tanky 类型的家族?在我的仆人应用程序中,我通常这样做

type AppRoute (x :: Symbol) = x :> Get '[HTML] RawHtml

效果很好。

如果有人仍在寻找答案,还有另一种方法可以捕获任何路线。看看 CaptureAll 类型