Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

yesod - getting the request body for a POST "Content-type: application/json"

Tags:

haskell

yesod

Using yesod 0.8.0, I'm trying to retrieve the body of a post message from this example request:

curl -v -H "Accept: application/json" -H "Content-Type: application/json" -X POST -d '{"name":"oscar"}'    http://localhost:3000/user/xyz

in my handler the only way I see it is to use

(pp, files) <- runRequestBody

But this fails because of the content type. Is there another function to do this?

like image 469
Oscar Avatar asked Apr 24 '11 01:04

Oscar


3 Answers

The other answers seem to be pretty old and from before the functions used below were added.

postFooR :: Handler Value
postFooR = do
 foo <- requireJsonBody :: Handler Foo -- get the json body as Foo (assumes FromJSON instance)
 returnJson foo -- return json (assumes ToJSON instance)
like image 171
LuxuryMode Avatar answered Oct 08 '22 02:10

LuxuryMode


Here's how to do it now. For future releases, I'm hoping to add some convenience wrappers; input on this is appreciated.

The explanation: Each handler function lives in a GGHandler sub master (Iteratee ByteString IO) monad. That's fairly complicated, but what it means is that it's a Handler monad transformer around an Iteratee that receives a stream of ByteStrings. That stream of ByteStrings is the raw request body.

So we need to use enumerator's consume function to take that entire stream of ByteStrings and store them as a list. And we need to use the lift function to lift this to the inner monad (the Iteratee). L.fromChunks then converts from a list of strict ByteStrings to a lazy ByteString, which you can parse with any arbitrary JSON library (Yesod is standardizing on aeson).

My guess is that the most convenient function I could provide would be parseRequestJson :: GGHandler s m (Iteratee ByteString IO) (Maybe Data.Aeson.Value). I can add that in a point release of yesod-json.

like image 29
Michael Snoyman Avatar answered Oct 08 '22 03:10

Michael Snoyman


In Yesod 1.0+ (and maybe earlier, not sure), the following appears to work:

postRootR = do
    wr <- waiRequest
    bss <- lift $ lazyConsume $ requestBody wr
    let requestBody = L.fromChunks bss
like image 44
lincolnq Avatar answered Oct 08 '22 02:10

lincolnq