I use servant 0.19, so no the type RawM
. I have a handler:
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).
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.