6

I'm currently doing some REST API stuff in clojure, and I am using the ring.middleware.format library with compojure to transform JSON to and from clojure data structures.

I am having a huge issue, in that and JSON posted to the ring app will have all arrays replaced with the first item that was in the array. I.E. it will turn this JSON posted to it from

{
    "buyer":"Test Name",
    "items":[
        {"qty":1,"size":"S","product":"Red T-Shirt"},
        {"qty":1,"size":"M","product":"Green T-Shirt"}
    ],
    "address":"123 Fake St",
    "shipping":"express"
}

to this

{
    "buyer": "Test Name",
    "items": {
        "qty": 1,
        "size": "M",
        "product": "Green T-Shirt"
    },
    "address": "123 Fake St",
    "shipping": "express"
}

It does it for any arrays, including when an array is the root element.

I am using the following code in clojure to return the json:

(defroutes app-routes
  (GET "/"
       []
       {:body test-data})
  (POST "/"
        {data :params}
        {:body data}))
        ;{:body (str "Printing " (count (data :jobs)) " jobs")}))

(def app
  (-> (handler/api app-routes)
      (wrap-json-params)
      (wrap-json-response)))

The GET route has no issues with arrays and outputs properly, so it has to be either the way I am getting the data or the wrap-restful-params middleware.

Any ideas?

Tom Brunoli
  • 3,436
  • 9
  • 36
  • 54

3 Answers3

3

I am having similar problem with ring-json-params. So I ended up using raw request body and parsing the JSON string myself.

I used the folliwng code:

(defroutes app-routes
(POST "/"
    {params :body}
    (slurp params)))

I use the clj-json.core library for parsing JSON.

Hope this helps. If you figured out a better way then please share. I am a Clojure/Compojure newbie!!!

Dhruv Chandna
  • 571
  • 5
  • 17
  • Thanks! That worked great. It's not an ideal solution, but it works. – Tom Brunoli Nov 16 '12 at 05:40
  • 1
    Great. I agree it is not the best solution. I have forked the ring-json-params repository and will try and fix the problem. – Dhruv Chandna Nov 16 '12 at 05:58
  • Did you ever get to the bottom of this? I found a similar issue in ring-middleware-format and opened an issue: https://github.com/ngrunwald/ring-middleware-format/issues/15 – noahlz May 23 '13 at 05:40
2

I ran into this problem recently and actually figured out what the problem is: it's that you have wrap-nested-params middleware getting evaluated after your wrap-json-params middleware, which causes objects stored in JSON arrays/Clojure vectors to be flattened by grabbing the first element contained within.

user=> bod-map
{:address "100 Bush Street", :contacts [{:name "Dudely Mcdooderson", :title "engineer", :tax_id "555"}], :name "Dudely Inc.", :tax_id "5234234"}
user=> (ring.middleware.nested-params/nested-params-request {:params bod-map})
{:params {"tax_id" "5234234", "name" "Dudely Inc.", "contacts" {:name "Dudely Mcdooderson", :title "engineer", :tax_id "555"}, "address" "100 Bush Street"}}

You can get around this by just making sure that wrap-nested-params is evaluated first in your middleware ordering.

Venantius
  • 2,471
  • 2
  • 28
  • 36
1

I know it's been some time but I did just stumble upon the same issue. The only way I got it to work was to use the ring.middleware.format/wrap-restful-format before the compojure.handler/api. I'm not sure why that is but if I put the compujure.handler/api wrapper first, it messes up the array parameteres

ls4f
  • 21
  • 1
  • 1