与Servant/Wai一起提供静态文件

Eco*_*ium 7 haskell haskell-wai servant

我正在按照本教程http://www.parsonsmatt.org/programming/2015/06/07/servant-persistent.html通过servant创建API.我想自定义服务器以提供静态文件,但无法找到方法.

我正在使用stack构建工具.

我将Main.hs文件的运行修改为include static(run port $ static $ logger $ app cfg)并导入Network.Wai.Middleware.Static (static).我还添加wai-middleware-static >=0.7.0 && < 0.71到我的cabal文件中.

当我运行stack build我得到: (更新:这部分完全是我的错误,我添加了封装到错误的小集团文件..跛脚导入Network.Wai.Middleware.Static作品和静态文件留在以下情况下,错误.任何人都搜索它并发现它很有用.)

Could not find module ‘Network.Wai.Middleware.Static’
Perhaps you meant
  Network.Wai.Middleware.Gzip (from wai-extra-3.0.7.1@waiex_GpotceEdscHD6hq9p0wPOJ)
  Network.Wai.Middleware.Jsonp (from wai-extra-3.0.7.1@waiex_GpotceEdscHD6hq9p0wPOJ)
  Network.Wai.Middleware.Local (from wai-extra-3.0.7.1@waiex_GpotceEdscHD6hq9p0wPOJ)
Run Code Online (Sandbox Code Playgroud)

接下来我尝试使用servant serveDirectory如下(简化):

type  API = "users" :> Get   '[JSON]   [Person]
            :<|> "static" :> Raw
server = createPerson :<|> serveDirectory "/static" 
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

Couldn't match type ‘IO’ with ‘EitherT ServantErr IO’
arising from a functional dependency between:
  constraint ‘Servant.Server.Internal.Enter.Enter
                (IO Network.Wai.Internal.ResponseReceived)
                (AppM :~> EitherT ServantErr IO)
                (IO Network.Wai.Internal.ResponseReceived)’
    arising from a use of ‘enter’
  instance ‘Servant.Server.Internal.Enter.Enter
              (m a) (m :~> n) (n a)’
    at <no location info>
In the expression: enter (readerToEither cfg) server
In an equation for ‘readerServer’:
    readerServer cfg = enter (readerToEither cfg) server
Run Code Online (Sandbox Code Playgroud)

我是Haskell初学者,我不熟悉围,所以不确定从哪里开始.我需要做什么更改才能在Blog帖子中制作示例代码来提供静态文件?

编辑:由于评论从默认视图隐藏,我在这里粘贴我的最后评论:

这是他博客中Matt 代码的低调版本.我将所有模块合并到一个文件中,删除了所有数据库内容,但没有清理扩展/导入.当我运行此代码时,我得到上面的类型不匹配错误.请注意,此代码不使用Network.Wai.Middleware.Static,我使用的是Servant StaticFiles的限定导入.

谢谢!

Alp*_*ari 8

正如servant教程的相关部分所述,整个处理enter是让你的请求处理程序使用一些monad m(在你的情况下是一些ReaderTmonad)并提供一种方法将计算转换为servant标准monad中m的计算.EitherT ServantErr IO

虽然这里的问题是,你定义在一堆请求处理程序ReaderT 附加一个为静态文件,并呼吁enter所有的这些.该ReaderT处理器被转换为EitherT ...处理得很好,但enter尝试将转换serveDirectory打来ReaderT ...EitherT ....这当然不会很快发生,因为开始时serveDirectory不是计算ReaderT ...!

仆人可以说是刚刚离开serveDirectory独自-在这一点上我没有对我们是否应该这样做或不明确的意见,或者如果它是更好的只是有文件服务处理器分别粘,调用的结果enter上所有其他端点.这是这样的样子(寻找-的变化):

type PersonAPI = 
    "users" :> Capture "name" String :> Get '[JSON] Person
   -- NEW: removed Raw from here

-- NEW
type WholeAPI = PersonAPI :<|> Raw

type AppM = ReaderT Config (EitherT ServantErr IO)

userAPI :: Proxy PersonAPI
userAPI = Proxy

-- NEW
wholeAPI :: Proxy WholeAPI
wholeAPI = Proxy

-- NEW: changed 'userAPI' to 'wholeAPI'
app :: Config -> Application
app cfg = serve wholeAPI (readerServer cfg)

readerServer :: Config -> Server WholeAPI
readerServer cfg = enter (readerToEither cfg) server
              :<|> S.serveDirectory "/static" -- NEW

readerToEither :: Config -> AppM :~> EitherT ServantErr IO
readerToEither cfg = Nat $ \x -> runReaderT x cfg

server :: ServerT PersonAPI AppM
server = singlePerson

singlePerson :: String -> AppM Person
singlePerson str = do
    let person = Person { name = "Joe", email = "joe@example.com" }
    return person
Run Code Online (Sandbox Code Playgroud)

无论如何,我已经把这个话题引起了其他仆人开发者的注意,谢谢!我们真的没有想过之间的相互作用enterserveDirectory至今(当然,我没有).