Haskell 使用Servant/Wai服务静态文件
我遵循本教程通过servant创建API。我想自定义服务器以提供静态文件,但找不到方法 我正在使用Haskell 使用Servant/Wai服务静态文件,haskell,haskell-wai,servant,Haskell,Haskell Wai,Servant,我遵循本教程通过servant创建API。我想自定义服务器以提供静态文件,但找不到方法 我正在使用堆栈构建工具 我修改了Main.hs文件的运行以包括static(run port$static$logger$app cfg),并导入了Network.Wai.Middleware.static(static)。我还将wai中间件static>=0.7.0&Get'[JSON][Person] :“静态”:>原始 server=createPerson:serveDirectory/“静态” 我
堆栈
构建工具
我修改了Main.hs
文件的运行以包括static
(run port$static$logger$app cfg
),并导入了Network.Wai.Middleware.static(static)
。我还将wai中间件static>=0.7.0&<0.71
添加到我的阴谋集团文件中
当我运行stack build
时,我得到:(更新:这部分完全是我的错误。我将包添加到错误的cabal文件中..lame.Importing Network.Wai.Middleware.Static工作并服务于静态文件。将错误保留在下面,以防任何人搜索它并发现它有用。)
接下来,我尝试使用servant的serveDirectory
,如下所示(简化):
typeapi=“users”:>Get'[JSON][Person]
:“静态”:>原始
server=createPerson:serveDirectory/“静态”
我得到这个错误:
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
无法将类型“IO”与“EitherT ServantErr IO”匹配
由以下两者之间的功能依赖性引起:
约束“Servant.Server.Internal.Enter.Enter”
(IO网络、Wai、内部、响应接收)
(附件:~>EitherT ServantErr IO)
(IO网络.外部.内部.响应已接收)'
因使用“回车”而产生
实例“Servant.Server.Internal.Enter.Enter”
(ma)(m:~>n)(na)"
在
在表达式中:输入(readerToEither cfg)server
在“readerServer”的方程式中:
readerServer cfg=输入(readerToEither cfg)服务器
我是Haskell初学者,我对Wai不太熟悉,所以不确定从哪里开始。我需要做哪些更改才能使博客文章中的示例代码服务于静态文件
编辑:由于注释在默认视图中隐藏,因此我将最后一条注释粘贴到此处:
这是马特博客中的低调版本。我将他的所有模块整合到一个文件中,删除了所有数据库内容,但没有清理扩展/导入。当我运行这段代码时,我得到了上面的类型不匹配错误。请注意,此代码不使用Network.Wai.Middleware.Static,我使用的是符合条件的静态文件导入
谢谢 如前所述,enter
的整个过程就是让您的请求处理程序使用一些monadm
(在您的例子中是一些ReaderT
monad),并提供一种将m
中的计算转换为服务标准EitherT ServantErr IO
monad中的计算的方法
但这里的问题是,您在ReaderT
中定义了一组请求处理程序,并在另一个请求处理程序中定义了一个用于服务静态文件的请求处理程序,然后对所有这些请求处理程序调用enter
。ReaderT
处理程序被转换为EitherT…
处理程序,但enter
尝试将serveDirectory
调用从ReaderT…
转换为EitherT…
。这当然不会很快发生,因为serveDirectory
一开始就不是ReaderT…
中的计算
可以说,servant可以把serveDirectory
单独放在一边——在这一点上,对于我们是否应该这样做,或者让文件服务处理程序单独粘贴到所有其他端点上调用enter
的结果是否更好,我没有明确的意见。下面是它的样子(查找--新建以查看更改):
type PersonAPI=
“用户”:>捕获“名称”字符串:>获取“[JSON]Person
--新的:从这里原始删除
--新的
类型WholeAPI=PersonAPI:Raw
类型AppM=ReaderT Config(EitherT ServantErr IO)
userAPI::代理角色pi
userAPI=Proxy
--新的
wholeAPI::代理wholeAPI
wholeAPI=代理
--新增:将“userAPI”更改为“wholeAPI”
app::Config->Application
app cfg=SERVICE wholeAPI(读服务器cfg)
readerServer::Config->Server WholeAPI
readerServer cfg=输入(readerToEither cfg)服务器
:S.serveDirectory“/静态”--新
readerToEither::Config->AppM:~>EitherT ServantErr IO
readerToEither cfg=Nat$\x->runReaderT x cfg
服务器::ServerT PersonAPI AppM
服务器=单人
singlePerson::String->AppM Person
单人str=do
让person=person{name=“Joe”,email=”joe@example.com" }
返回人
不管怎样,我已经把这个话题引起了其他服务开发人员的注意,谢谢!到目前为止,我们还没有真正考虑到
enter
和serveDirectory
之间的交互(我没有考虑)。对于第一个问题,我认为您需要将wai应用程序静态添加到.cabal文件中的构建中。谢谢,Michael。事实上,我把包裹放错了阴谋集团的档案里。所以,静态工作很好。我正在玩链接博客文章中的代码,我注意到它链接了中间件,所以决定使用静态中间件。我可能要花更长的时间才能弄清楚如何在这种情况下使用wai-app-static
。@Ecognium你看过仆人教程吗?@Ecogniumenter
机器将你的处理程序从一个单子转换成另一个单子。基于Reader
的服务器中有一个Raw
用于文件服务,因此enter
尝试将文件服务内容从ReaderT…
转换为EitherT…
,这将无法工作,因为serveDirectory
不存在于ReaderT
中。我不确定这是否是servant中的一个bug,或者除了所有的ReaderT
之外,单独定义文件服务处理程序是否真的更有意义。我已经通知了其他服务开发者@当然,我会试着写一个最小的完整答案。有关更多问题,请访问fe
type API = "users" :> Get '[JSON] [Person]
:<|> "static" :> Raw
server = createPerson :<|> serveDirectory "/static"
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
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