Haskell 全部捕获或默认路由

Haskell 全部捕获或默认路由,haskell,servant,Haskell,Servant,如今,如果请求的路由与现有API端点或其他静态资产不匹配,则需要从后端返回文件(例如,index.html)的情况并不少见。这在使用和时特别方便 我有点困惑,不知道该如何和仆人一起解决这个问题。我确实想知道拦截404是否是一种可行的方法,但当然有时候API需要合法地发布404。我一直在用这种东西来做实验: data Wombat = Wombat { id :: Int , name :: String } deriving (Eq, Show, Generic) instance

如今,如果请求的路由与现有API端点或其他静态资产不匹配,则需要从后端返回文件(例如,
index.html
)的情况并不少见。这在使用和时特别方便

我有点困惑,不知道该如何和仆人一起解决这个问题。我确实想知道拦截404是否是一种可行的方法,但当然有时候API需要合法地发布404。我一直在用这种东西来做实验:

data Wombat = Wombat
  { id :: Int
  , name :: String
  } deriving (Eq, Show, Generic)
instance ToJSON Wombat

wombatStore :: [Wombat]
wombatStore = 
  [ Wombat 0 "Gertrude"
  , Wombat 1 "Horace"
  , Wombat 2 "Maisie"
  , Wombat 3 "Julius"
  ]

wombats :: Handler [Wombat]
wombats = return wombatStore

wombat :: Int -> Handler Wombat
wombat wid = do
  case find (\w -> Main.id w == wid) wombatStore of
    Just x -> return x
    Nothing -> throwE err404

type API = 
    "api" :> "wombats" :> Get '[JSON] [Wombat] :<|>
    "api" :> "wombats" :> Capture "id" Int :> Get '[JSON] Wombat :<|>
    Raw

api :: Proxy API
api = Proxy

server :: Server API 
server = wombats
  :<|> wombat
  :<|> serveDirectory "static"

app :: Application
app = serve api server

main :: IO ()
main = run 3000 app
data袋熊=袋熊
{id::Int
,name::String
}派生(等式、显示、通用)
实例ToJSON-Wombat
袋熊商店::[袋熊]
袋熊商店=
[袋熊0“格特鲁德”
,袋熊1“贺拉斯”
,袋熊2“Maisie”
,袋熊3“朱利叶斯”
]
袋熊::Handler[袋熊]
袋熊=返回袋熊商店
袋熊::Int->Handler袋熊
袋熊wid=do
wombatStore的大小写查找(\w->Main.id w==wid)
只需x->返回x
没什么错
类型API=
“api”:>“袋熊”:>获取“[JSON][袋熊]:
“api”:>“袋熊”:>捕获“id”Int:>获取“[JSON]袋熊:
未经加工的
api::代理api
api=代理
服务器::服务器API
服务器=袋熊
:袋熊
:serveDirectory“static”
应用程序::应用程序
app=服务api服务器
main::IO()
main=运行3000应用程序

我想看一个例子,说明如果请求与API端点或静态目录中的任何内容不匹配,如何添加一个“默认路由”来发送HTML响应。玩具回购。

基本上,你得到了
serveDirectory“static”
可以被任何wai
应用程序替换,例如,我们可以:

...
{-# LANGUAGE OverloadedStrings #-}
...
import Network.Wai        (responseLBS)
import Network.HTTP.Types (status200)
...
server :: Server API 
server = wombats
    :<|> wombat
    :<|> hello

hello :: Application
hello req respond = respond $ 
  responseLBS 
  status200                        -- 
  [("Content-Type", "text/plain")] -- headers
  "Hello, World!"                  -- content
...
因此,既然您已经访问了IO,您就可以检查文件是否存在,如果存在,就提供它,否则就做任何您喜欢的事情。事实上,wai定义了
type Middleware=Application->Application
,因此您可能会想到一个方便的中间件,将
hello
(或任何其他应用程序!)封装在文件存在检查器和服务器中。

这里是另一个路径:

serveDirectory
定义为

serveDirectory = staticApp . defaultFileServerSettings . addTrailingPathSeparator
包含一个字段
ssLookupFile
,如果找不到该文件,您可以更改该字段以提供所需的服务。也许:

import WaiAppStatic.Types
import WaiAppStatic.Storage.Filesystem
import Network.Wai.Application.Static
import System.FilePath

fileOrIndex root pieces = do
  res <- ssLookupFile (defaultFileServerSettings root) pieces
  case res of
    LRNotFound -> undefined -- index.html here
    _ -> return res

serveStatic root =
  let root' = addTrailingPathSeparator root in
  staticApp $ (defaultFileServerSettings root') {ssLookupFile = fileOrIndex root'}
导入WaiAppStatic.Types
导入WaiAppStatic.Storage.Filesystem
导入Network.Wai.Application.Static
导入System.FilePath
fileOrIndex根片段=do
res未定义——此处为index.html
_->返回res
地榆根=
让根“=addTrailingPathSeparator根在
staticApp$(defaultFileServerSettings根“{ssLookupFile=fileOrIndex根“}

非常感谢,这真的很有帮助!
import WaiAppStatic.Types
import WaiAppStatic.Storage.Filesystem
import Network.Wai.Application.Static
import System.FilePath

fileOrIndex root pieces = do
  res <- ssLookupFile (defaultFileServerSettings root) pieces
  case res of
    LRNotFound -> undefined -- index.html here
    _ -> return res

serveStatic root =
  let root' = addTrailingPathSeparator root in
  staticApp $ (defaultFileServerSettings root') {ssLookupFile = fileOrIndex root'}