4

A while back, Chris Granger posted this middleware to get JSON hashes to appear in the defpage params under an umbrella "backbone" element.

(defn backbone [handler]
  (fn [req]
    (let [neue (if (= "application/json" (get-in req [:headers "content-type"]))
       (update-in req [:params] assoc :backbone (json/parse-string (slurp (:body req)) true))
       req)]
    (handler neue))))

How could I modify this code to have the JSON elements appear as top-level params in defpage; i.e. get rid of the :backbone umbrella?

animuson
  • 53,861
  • 28
  • 137
  • 147
Dax Fohl
  • 10,654
  • 6
  • 46
  • 90
  • Why do you want this? It seems this could be disastrous if any of the data in the JSON object overrides existing request attributes. Unless that is what you are going for? – Jeremy May 17 '12 at 15:45
  • There are no other request attributes. Everything is posted in JSON format. That's why the umbrella "backbone" element seems redundant for me. – Dax Fohl May 17 '12 at 15:48
  • Ah, I see it's updating the `:params` key, not the request map... see my answer. – Jeremy May 17 '12 at 15:52

3 Answers3

3

There are two things you can do. One option is to replace the value of :params with the map returned after parsing the JSON. In order to do that, just associate the new map to the :params key.

(assoc req [:params] (json/parse-string (slurp (:body req)) true))

The other option (as suggested by @dAni) is to merge the values of the parsed JSON into so that existing values in the :params map are not overridden. The reason why you need to use partial instead of just using merge here is because the final map is the merged result of the maps from left-to-right. Your solution works if you want the values from the JSON map to take precedence.

(update-in req [:params]
  (partial merge (json/parse-string (slurp (:body req)) true)))
Jeremy
  • 22,188
  • 4
  • 68
  • 81
0

Got it. assoc just works for one element so you have to put everything under the :backbone umbrella. To push all the JSON elements into the params, you have to use merge. So change the 4th line to:

(update-in req [:params] merge (json/parse-string (slurp (:body req)) true))
Dax Fohl
  • 10,654
  • 6
  • 46
  • 90
  • 1
    or (update-in req [:params] (partial merge (json/parse-string (slurp (:body req)) true))) if you want the exiting params not to be overriden. – DanLebrero May 17 '12 at 16:43
-1

If you don't mind pulling in another dependency, you can use the ring-middleware-format library.

Instructions:

  • Add [ring-middleware-format "0.1.1"] to your project.clj

  • and then in your server.clj, add the following code:

Code:

(:require [ring.middleware.format-params :as format-params])

(server/add-middleware format-params/wrap-json-params)

(defn -main [& m]
; Start the server...
)

Now any incoming JSON will be available to use just like form POSTdata.

David Kay
  • 1,006
  • 10
  • 16