Yesod - получение тела запроса для POST "Content-type: application/json"

Используя yesod 0.8.0, я пытаюсь получить тело сообщения сообщения из этого примера запроса:

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

в моем обработчике единственный способ, которым я вижу это использовать

(pp, files) <- runRequestBody

Но это не удается из-за типа содержимого. Есть ли другая функция для этого?

Ответ 1

Другие ответы кажутся довольно старыми и до того, как были добавлены функции, используемые ниже.

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)

Ответ 2

Здесь, как это сделать сейчас. Для будущих выпусков я надеюсь добавить некоторые удобные обертки; ввод по этому признаку.

Объяснение: Каждая функция обработчика живет в монаде GGHandler sub master (Iteratee ByteString IO). Это довольно сложно, но что это значит, так это то, что он превращает монад-конвертер вокруг Iteratee, который получает поток ByteStrings. Этот поток ByteStrings является необработанным телом запроса.

Итак, нам нужно использовать функцию перечислителя, чтобы взять весь поток ByteStrings и сохранить их в виде списка. И мы должны использовать функцию подъема, чтобы поднять ее на внутреннюю монаду (Iteratee). L.fromChunks затем преобразует из списка строгих ByteStrings в ленивую ByteString, которую вы можете анализировать с любой произвольной библиотекой JSON (Yesod стандартизирует на aeson).

Я предполагаю, что наиболее удобной функцией, которую я мог бы предоставить, было бы parseRequestJson :: GGHandler s m (Iteratee ByteString IO) (Maybe Data.Aeson.Value). Я могу добавить это в точечный выпуск yesod-json.

Ответ 3

В Yesod 1.0+ (и, возможно, раньше, не уверен) появляется следующее:

postRootR = do
    wr <- waiRequest
    bss <- lift $ lazyConsume $ requestBody wr
    let requestBody = L.fromChunks bss