英文:
How to use IO in a raw serving handler?
问题
我使用servant 0.19版本,所以没有`RawM`类型。我有一个处理器:
```haskell
hnd :: Something -> ServerT Raw Handler
hnd Something {..} = do
-- p <- readIORef somePath -- 无法匹配类型"IO b0"与"Tagged Handler Application"
let stSet = defaultFileServerSettings "a/b/c"
serveDirectoryWith stSet
该处理器在API的类型中描述为::<|> "some" :> Raw
我想在我的hnd
处理器中进行IO操作。如何在这个servant版本中做到这一点(不使用RawM
)?此外,如果您可以展示如何使用RawM
,我将不胜感激(尽管由于使用的版本0.19,这不是很重要)。
<details>
<summary>英文:</summary>
I use servant 0.19, so no the type `RawM`. I have a handler:
```haskell
hnd :: Something -> ServerT Raw Handler
hnd Something {..} = do
-- p <- readIORef somePath -- COULDN'T MATCH TYPE "IO b0" WITH "Tagged Handler Application"
let stSet = defaultFileServerSettings "a/b/c"
serveDirectoryWith stSet
which is described as an API's type: :<|> "some" :> Raw
I want to do IO operations in my hnd
handler. How to do it with this servant version (without RawM
)? Also, I'd be grateful if you show it with RawM
too (though it is not important due to the used version 0.19).
答案1
得分: 3
Short answer. 试一下:
hnd :: Something -> ServerT Raw Handler
hnd Something{..} = Tagged $ \req resp -> do
p <- readIORef somePath
let stSet = defaultFileServerSettings p
staticApp stSet req resp
The longer answer is that ServerT
is a type family associated with the HasServer
type class that maps API expressions to transformations of the Handler
monad to implement the API :>
and :<|>
combinators as well as individual endpoints. For a "normal" endpoint, like Get
, it maps the type ServerT (Get ...) Handler
to plain old Handler
.
To implement Raw
, ServerT Raw Handler
is mapped to Tagged Handler Application
. This is simply a WAI Application
whose type has been Tagged
with the Handler
monad.
Servant-supplied wrappers, like serveDirectoryWith
, are really just WAI Application
s that have been Tagged
:
serveDirectoryWith :: StaticSettings -> ServerT Raw m
serveDirectoryWith = Tagged . staticApp
where staticApp
is the underlying static file serving Application
from the wai-app-static
package.
So, that means that the simplified handler:
hnd :: Something -> ServerT Raw Handler
hnd _ = serveDirectoryWith "a/b/c"
is equivalent to:
hnd _ = Tagged (staticApp "a/b/c")
and given that an Application
is actually a Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
, this is the same as:
hnd _ = Tagged (\req resp -> staticApp "a/b/c" req resp)
or:
hnd Something{..} = Tagged $ \req resp -> do
staticApp "a/b/c" req resp
where the do
-block is running in the plain old IO
monad. In this form, it's now possible to do "normal" IO stuff, which is how I derived the short answer above.
RawM
from version 0.20 doesn't gain you much here. It maps ServantT RawM Handler
to a modified version of an application:
Request -> (Response -> IO ResponseReceived) -> Handler ResponseReceived
instead of IO
, which adds the ability to perform Handler
actions besides IO
, namely signaling a specific ServerError
. If you had a custom HandlerT
, it could be more useful. It wouldn't make it any easier to write your hnd
, though.
英文:
Short answer. Try:
hnd :: Something -> ServerT Raw Handler
hnd Something{..} = Tagged $ \req resp -> do
p <- readIORef somePath
let stSet = defaultFileServerSettings p
staticApp stSet req resp
The longer answer is that ServerT
is a type family associated with the HasServer
type class that maps API expressions to transformations of the Handler
monad to implement the API :>
and :<|>
combinators as well as individual endpoints. For a "normal" endpoint, like Get
, it maps the type ServerT (Get ...) Handler
to plain old Handler
.
To implement Raw
, ServerT Raw Handler
is mapped to Tagged Handler Application
. This is simply a WAI Application
whose type has been Tagged
with the Handler
monad.
Servant-supplied wrappers, like serveDirectoryWith
, are really just WAI Application
s that have been Tagged
:
serveDirectoryWith :: StaticSettings -> ServerT Raw m
serveDirectoryWith = Tagged . staticApp
where staticApp
is the underlying static file serving Application
from the wai-app-static
package.
So, that means that the simplified handler:
hnd :: Something -> ServerT Raw Handler
hnd _ = serveDirectoryWith "a/b/c"
is equivalent to:
hnd _ = Tagged (staticApp "a/b/c")
and given that an Application
is actually a Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
, this is the same as:
hnd _ = Tagged (\req resp -> staticApp "a/b/c" req resp)
or:
hnd Something{..} = Tagged $ \req resp -> do
staticApp "a/b/c" req resp
where the do
-block is running in the plain old IO
monad. In this form, it's now possible to do "normal" IO stuff, which is how I derived the short answer above.
RawM
from version 0.20 doesn't gain you much here. It maps ServantT RawM Handler
to a modified version of an application:
Request -> (Response -> IO ResponseReceived) -> Handler ResponseReceived
^^^^^^^
instead of IO
which adds the ability to perform Handler
actions besides IO
, namely signaling a specific ServerError
. If you had a custom HandlerT
, it could be more useful. It wouldn't make it any easier to write your hnd
, though.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论