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)))
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 ?