Getting a clojure map with keywords from a POST using Liberator

520 Views Asked by At

I'm using Liberator, and am having a hard time getting my POSTed data into a map using with keywords as the keys. Here is my resource, with a few printlines for testing:

(defresource finish_validation
             :allowed-methods [:post]
             :available-media-types ["application/json"]
             :post! (fn [context]
                      (let [params (slurp (get-in context [:request :body]))
                            mapped_params (cheshire/parse-string params)]

                        (println (type params))
                        (println (type mapped_params))
                        (validation/finish mapped_params)))
             :handle-created (println ))

For testing, I'm posting the data using curl:

curl -H "Content-Type: application/json" -X POST -d '{"email":"[email protected]","code":"xyz"}' http://localhost:8080/validate

cheshire converts the params into a map, but the keys are not keywords: I get {email [email protected], code xyz} as the output, instead of the hoped-for {:email [email protected], :code xyz}.

Should I be doing something differently? Is this even the right approach to getting the data?

3

There are 3 best solutions below

1
On

I just had to put "true" at the end of the call to the cheshire function, and the keys are returned as keywords:

(cheshire/parse-string params true)
2
On

Depending on your requirements, you can simplify the handling of your post data using various ring middleware. This will allow you to process your json data in one place and eliminate the need to have duplicate data processing in each of your handlers/resource definitions. There are a few ways of doing this. You can have the json data added as keywordized parameters in the params map or a json-params map. Have a look at ring.middleware.format and ring.middleware.json.

0
On

You need to leverage ring's wrap-params middleware, coupled with the wrap-keyword-params middleware which converts the params map to a key map.

(ns your.namespace
  (:require [ring.middleware.params :refer  [wrap-params]]
            [ring.middleware.keyword-params :refer  [wrap-keyword-params]]))

(def app
  (-> some-other-middleware
      wrap-keyword-params
      wrap-params))

Using this middleware with wrap-params converts params to use keys. After adding this middleware, you can access your params from the request map, like so (-> ctx :request :params). No need to convert them per request. This will handle all requests.