Let's assume, that I've got an endpoint POST /endpoint
that takes JSON as input data:
POST /endpoint
{
"resource": {
"name": "great"
}
}
Now, I want to check whether the incoming JSON is valid. I thought that :malformed?
hook would be a great place for doing that.
So I came up with such a code:
(ANY "/endpoint" []
(resource
:allowed-methods [:post]
:available-media-types ["application/json"]
:malformed? (fn [ctx] (let [body (get-body-from-request ctx)
is-malformed (not (is-body-valid body))]
is-malformed)
:post! (fn [ctx] (let [body (get-body-from-request ctx)]
(create-an-object body)))
:handle-created (fn [ctx] {:method :post :body (:body @request)})))
So my intention was:
body
from request, check if it's valid (is-body-valid
)post!
hook, use the body
again and do real work (create-an-object
)The problem here is the get-body-from-request
function:
(defn get-body-from-request [ctx]
(json/read-str (slurp (get-in ctx [:request :body])) :key-fn keyword))
It works perfectly but the body
is an InputStream
, so I can read it only once.
Is there a way to use body
of the request in more than one hook NOT using atoms?
The solutions coming to my mind:
body
to the ctx
param.malformed?
to post!
...Thanks!
OK, it was pretty easy, there's of course a wrapper that does that...
[ring-json-params "0.1.3"]
Then you just wrap your app handler:
(ns my.app
(:require [ring.middleware.json :refer [wrap-json-params]]))
(def app
(-> handler
(wrap-json-params)))
and in your ctx
object you've got a json-params
object:
:malformed? (fn [ctx] (let [params (get-in ctx [:request :json-params])]
false))