pickwick
pickwick

Reputation: 3154

Getting a clojure map with keywords from a POST using Liberator

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?

Upvotes: 2

Views: 521

Answers (3)

Seth
Seth

Reputation: 10454

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.

Upvotes: 2

Tim X
Tim X

Reputation: 4235

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.

Upvotes: 0

pickwick
pickwick

Reputation: 3154

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)

Upvotes: 1

Related Questions