This is how I do it - it seems to work, but I just started using Liberator, so there may be better or more correct ways to do this!
I think you need a handler created by the handle. For instance -
(defresource shopping-calc :allowed-methods [:post] :available-media-types ["application/json"] :malformed? (fn [context] (let [params (get-in context [:request :params])] (or (empty? params) (is-malformed? params)))) :handle-malformed (fn [context] (let [params (get-in context [:request :params])] (generate-string (handle-malformed-calc params)))) :handle-created (fn [context] (let [params (get-in context [:request :params])] (generate-string (calculate-total params)))))
and I have a handler created by a handler like this
(defn calculate-total [params] {:total (calc params)})
I also use ring / json middleware and in my dev environment, add a liberator trace facility. The Liberator tracking tool is very convenient as it adds headers to the answer, which shows the decision points for Liberator. Thus, for you, the problem would probably show that Liberator used a default handler that simply returns the headers. To return your own json, you need to define a handler.
Note that I do not use this post! method. This is due to the fact that in this example, I actually do not create some new object / element, for example, adding an entry to some store. If you do this, then what you could do is use a post! to add a record and create a specific descriptor, then to get a new record (possibly with other new fields, such as record identifier or timestamp, etc.) and return it.
I use: malformed? and handle incorrectly to perform basic error checking. If: wrong? returns true, the header with the wrong expression is called, which returns the error status and the error message in the json package. I find this helps a lot so that your errors also return to json so that you can process everything on the client side sequentially.
The following are the definitions of my handlers and middleware. Please note: since I serve both applications and api routes, they are a bit more complicated because I want some middleware to be applied to some routes and other middleware applied to others. There is also a small error in the ring / ring-default settings, which after fixing will change things, because at the moment I can not use the site-api middleware to migrate by default. Check out the middleware for transferring the trace.
(def app (if (env :dev) (routes (-> api-routes (wrap-reload) (wrap-routes wrap-json-params) (wrap-routes wrap-defaults api-defaults) (wrap-routes wrap-trace :header :ui)) (-> app-routes (wrap-routes wrap-error-page) (wrap-routes wrap-exceptions))) (routes (-> api-routes (wrap-routes wrap-json-params) (wrap-routes wrap-defaults api-defaults)) app-routes)))