Why do I have to flatten nested JSON when using the ring json middleware

I have been writing a clojure application with ring and compojure. I am using the ring.middleware.json middleware for handling JSON so I don't have to serialise and deserialise it myself in my code.

This middleware only seems to correctly parse nested JSON when given in a flattened format, for example if I want to POST nested data to an API route I have to encode it as:

{"task"            : 1,
 "success"         : false,
 "files[0][type]"   : "log",
 "files[0][sha256]" : "adef5c",
 "files[0][url]"    : "s3://url"}

Instead of, what seems to me, more standard JSON:

{"task"    : 1,
 "success" : false,
 "files"   : [{"type" : "log", "sha256" : "adef5c", "url": "s3://url"}]}

Is this indented or a standard way of posting nested JSON? Here is my middleware stack:

(defn middleware [handler]
  (-> handler
    (wrap-json-response)
    (wrap-with-logger)
    (api)))

Answers


Here is a full Clojure example of post and get routes that handle JSON or return JSON:

(ns ring-app.core
  (:require [ring.adapter.jetty :as jetty]
            [compojure.core :as compojure]
            [ring.middleware.keyword-params :refer [wrap-keyword-params]]
            [ring.middleware.json :refer [wrap-json-response wrap-json-body]]
            [ring.util.http-response :as response]
            [clojure.pprint :refer [pprint]]
            [ring.middleware.reload :refer [wrap-reload]]))

(defn json-get [request]
  (response/ok 
    {"task"  1 
     "success"  false  
     "files" [{"type"  "log" "sha256"  "adef5c" "url"  "s3://url"}]}))

(defn json-post [request]
  (let [bpdy (:body request)]
    (prn bpdy)
    (response/ok bpdy)))

(compojure/defroutes handler_
 (compojure/GET "/get" request json-get)
 (compojure/POST "/post" request json-post))

(defn wrap-nocache [handler]
  (fn [request]
    (-> request
        handler
        (assoc-in [:headers "Pragma"] "no-cache"))))

(def handler 
  (-> #'handler_ wrap-nocache wrap-reload wrap-json-response wrap-json-body ) )

The get endpoint returns the nested structure:

curl http://localhost:3000/get
; {"task":1,"success":false,"files":[{"type":"log","sha256":"adef5c","url":"s3://url"}]}                                    

And the POST endpoint parses the json and create a Clojure data structure:

  curl -X post  -d '{"task":1,"success":false,"files":[{"type":"log","sha256":"adef5c","url":"s3://url"}]}'  -H "Accept: application/json" -H "Content-type: application/json"  http://localhost:3000/post
  ; {"task":1,"success":false,"files":[{"type":"log","sha256":"adef5c","url":"s3://url"}]}

This is roundtripping on JSON->CLJ->JSON

The json ring middleware expects the Content-type to be properly set so maybe that was why the structure was not parsed properly in your case ?


Need Your Help

How can I store the user details (ip, name, duration) after login using php ?

php login ip

In my application, I want to store the user details (ip, name, duration) after login. Duration means How long the user stay as login in my application ? using php.

Jquery.get cannot retrieve XML from RESTful Service

jquery xml rest timeout get

I'm trying to get an XML document from a REST service using the Jquery get method, but it doesn't seem to be able to download. After only about 11 seconds, the connection dies and I receive a blank