Reputation: 6409
EDIT - The source code is on github if you're interested. Thanks
I am a bit confused as to how to access json data that has been posted to a url in clojure; I just can't seem to get it to work.
This is my route:
(cc/POST "/add"
request
(str ": " request))
I am not entirely sure what I have to put in place of request
- I just saw some blog online and tried to follow it, but couldn't get it to work.
Here's how I'm trying to post: (from fiddler)
note: request header port is different in the image; it's a mistake, I was trying to mess with that data to see what it says so ignore that part in the above image please
In curl, I'm just doing this:
curl -X POST -H "Content-Type: application/json" -d '{"foo":"bar","baz":5}'
http://localhost:3005/add
It looks like clojure is not receiving the json data that I posted at all.
Here's what the request var contains:
: {:scheme :http, :query-params {}, :form-params {}, :request-method :post,
:query-string nil, :route-params {}, :content-type "\"application/json\"",
:uri "/event", :server-name "localhost", :params {},
:headers {"user-agent" "Fiddler", "content-type" "\"application/json\"",
"content-length" "23", "host" "localhost:3005"},
:content-length 23, :server-port 3005, :character-encoding nil, :body #}
As you can see, all params
are empty...
I am using compojure and cheshire - and I can convert data into json and return them just fine for GET
routes.. I need to figure out how to pass json and convert it into clojure data..
thanks
Upvotes: 6
Views: 8223
Reputation: 27536
Just an update to a previous answers, now is enough to add formats
key with list of formats which will be processed by Ring to your handler.
So something like
(def app (noir.util.middleware/app-handler
[your-routes]
:formats [:json-kw]))
Upvotes: 0
Reputation: 1372
Here is an example that does what you want. The code was taken from this project. In the README you will see some of the access patterns that this supports. The code is a little messy, but it should illustrate how this can be done.
(ns poky.protocol.http.jdbc.text
(:require [poky.kv.core :as kv]
(compojure [core :refer :all]
[route :as route]
[handler :as handler])
[ring.util.response :refer [response not-found]]
(ring.middleware [format-response :as format-response ]
[format-params :as format-params])
[cheshire.core :as json]
[ring.middleware.stacktrace :as trace]))
;
; curl -d"some data" -H'Content-Type: application/text' -v -X PUT http://localhost:8080/xxx
; curl -d'{"bla":"bar"}' -H'Content-Type: application/json' -v -X PUT http://localhost:8080/bla
(def valid-key-regex #"[\d\w-_.,]+")
; FIXME: this should be split- one fn for get, one for mget
(defn- wrap-get
[kvstore ks params headers body]
(response
(let [eks (clojure.string/split ks #",")
nks (count eks)
multi (> nks 1)
ret (if multi (kv/mget* kvstore eks) (kv/get* kvstore ks))]
(condp = (get headers "accept")
"application/json" ret
"text/plain" (if multi (throw (Exception. "Multi get unsupported with Accept: text/plain")) (get ret ks))
ret))))
(defn- wrap-put
[kvstore ks params headers body]
(if (and
(= (get headers "content-type") "application/json")
(get params (keyword ks) nil))
(kv/set* kvstore ks (get params (keyword ks)))
(kv/set* kvstore ks body))
(response ""))
(defn api
[kvstore]
(let [api-routes
(routes
(GET ["/:ks" :ks valid-key-regex] {{:keys [ks] :as params} :params body :body headers :headers}
(wrap-get kvstore ks params headers body))
(PUT ["/:ks" :ks valid-key-regex] {{:keys [ks] :as params} :params
body :body body-params :body-params headers :headers}
(let [body (slurp body)
body (if (empty? body) body-params body)]
(wrap-put kvstore ks params headers body))))]
(-> (handler/api api-routes)
(format-params/wrap-format-params
:predicate format-params/json-request?
:decoder #(json/parse-string % true)
:charset format-params/get-or-guess-charset)
(format-response/wrap-format-response
:predicate format-response/serializable?
:encoders [(format-response/make-encoder json/encode "application/json")
(format-response/make-encoder identity "text/plain")]
:charset "utf-8")
trace/wrap-stacktrace)))
Hope this helps.
Upvotes: 1
Reputation: 5001
That's because :params is filled by a ring middleware which deals with "form-encoded" body.
You can use ring-json to wrap your application into this other middleware. It will parse the JSON body and fill :params accordingly. (https://github.com/ring-clojure/ring-json)
Upvotes: 8