سؤال

I'm using scotty, which is a sinatra-like wrapper around WAI. I want to get the raw request body as a byte string so I can parse it as json. The following is close. This is similar to other questions about consuming a body using WAI, but is different because I want the body as a bytestring, and because I'm in a different monad, ActionM

import Network.Wai (requestBody)
import Web.Scotty (ActionM, request, text)

bodyExample :: ActionM ()
bodyExample = do
    r <- request
    bss <- requestBody r -- this needs a lift or something
    text "ok"
    ...

It obviously won't work, I think I need some kind of lift or something, but I don't know what to use. liftIO isn't right, and lift gives me weird errors.

http://hackage.haskell.org/packages/archive/scotty/0.0.1/doc/html/Web-Scotty.html

http://hackage.haskell.org/packages/archive/wai/latest/doc/html/Network-Wai.html

هل كانت مفيدة؟

المحلول

requestBody isn't a monadic value. It is simply a function that returns a Conduit Source IO ByteString.

To consume the source, use Data.Conduit.List.consume (or Data.Conduit.Lazy.lazyConsume). You will get a list of ByteStrings as the result. To then exit the ResourceT monad transformer, use runResourceT. The resulting code:

bss <- liftIO . runResourceT . lazyConsume . requestBody $ r
bss :: [ByteString]

نصائح أخرى

For what it's worth, the new version of Scotty (0.2.0) has a 'jsonData' method to do this for you. Thanks for using!

The accepted answer won't actually work due to the way lazyConsume works. It will always return an empty list. You need to consume the data before exiting ResourceT if you're using lazyConsume.

As an alternative, here's how to strictly consume the bytestring and return it:

rawRequestBody :: Request -> IO B.ByteString
rawRequestBody req = mconcat <$> runResourceT (requestBody req $$ consume)

This is the code that finally work for me, adapted from jhickner's

rawRequestBody req = mconcat <$> (requestBody req $$ consume)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top