Как создать маршрут, который будет запускаться на любом пути в Servant? - PullRequest
2 голосов
/ 14 марта 2019

У меня есть функция уровня типа (семейство типов) в приложении Haskell Servant, которое принимает символ и создает тип (маршрут), т.е.

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 - это функция уровня типа, которая принимает любую строку и возвращает маршрут.

В итоге вместо записи

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

Я хочу быть в состоянии написать только : <|> AppRoute _

1 Ответ

1 голос
/ 14 марта 2019

Вы можете использовать Capture для захвата любого пути. Однако ему должно предшествовать : char. Так например

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

Вы можете прочитать об этом здесь .


Кстати, почему бы не использовать псевдоним type вместо того, чтобы брать семейства типа танки? В моих приложениях Servant я обычно делаю

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

Который работает отлично.

...