How to extract the form data from a request in liberator?
I have the following client-side request:
(let [form-data (doto
(js/FormData.)
(.append "filename" file))]
(ajax-request
{:uri "/some/uri"
:method :post
:body form-data
:format (raw-request-format)
:response-format (raw-response-format)})
)
And on the server (with liberator):
(defresource some-resource [_]
:allowed-methods [:get :post]
:available-media-types ["application/json"]
:exists? (fn [ctx]
(prn "form-data " (-> ctx :request :body slurp)) ;prints
(prn "form-data " (-> ctx :request :body slurp cheshire/decode)) ;doesn't print
))
At the server, I do get the print of the form-data like so:
"form-data " "------WebKitFormBoundaryI9CA2zKhFT0Stmx7\r\nContent-Disposition: form-data; name=\"new-name\"\r\n\r\n{:uploaded-file #object[File [object File]], :name \"somename\", :another \"1234\"}\r\n------WebKitFormBoundaryI9CA2zKhFT0Stmx7--\r\n"
But the next prn doesn't print anything where my goal is to extract the :uploaded-file. What am I doing wrong?
I bet you should use ring.middleware.params/wrap-params to get form-data in :form-params map of request. Then, your form data will appear in this sub-map with keys corresponding to names of inputs you had specified in your HTML (I assume but omit such HTML):
(require '[ring.middleware.params :refer [wrap-params]])
(require '[liberator.core :refer [defresource]])
(require '[compojure.core :refer [defroutes ANY]])
(require '[expectations.clojure.test :refer [defexpect expect]])
(require '[ring.mock.request :as mock])
(defresource handle-form-uploads
:allowed-methods #{:get :post}
:available-media-types ["text/plain"]
:handle-created (fn [ctx]
(str (get-in ctx [:request :form-params "greeting"]) ", "
(get-in ctx [:request :form-params "name"]) "!")))
(defroutes my-app-routes
(ANY "/" [] handle-form-uploads))
(def my-app
(wrap-params my-app-routes))
(defexpect handling-form-uploads
(expect
{
:status 201
:headers {"Content-Type" "text/plain;charset=UTF-8" "Vary" "Accept"}
:body "Hello, Prikshet!"}
(my-app (-> (mock/request :post "/")
(mock/body {:name "Prikshet" :greeting "Hello"})))))
(handling-form-uploads)
deps.edn:
{
:deps
{
liberator/liberator {:mvn/version "0.15.3"}
ring/ring-core {:mvn/version "1.11.0-RC2"}
compojure/compojure {:mvn/version "1.7.0"}
expectations/clojure-test {:mvn/version "1.2.1"}
ring/ring-mock {:mvn/version "0.4.0"}}}
Notice that "form" keys will appear in map as strings, not keywords.
Take a look at ring.middlewares.multipart-params if you want to process uploaded files as well.