Search code examples
testingclojureringmidje

Passing data to a liberator post endpoint in midje test using ring-mock


I am trying to write a midje test using ring-mock to do a post to a liberator endpoint. I can successfully write a test for get requests but I can't seem to pass data to the post, I only get back the malformed response. Here is the meat of the code that I have.

;; ====
; Resource
;; ====
(def users (atom [{:id 1 :name "User One"} {:id 2 :name "User Two"}]))

(defn malformed-users? [context]
  (let [params (get-in context [:request :multipart-params])]
    (and
      (empty? (get params "id"))
      (= (get-in context [:request :request-method]) :post))))

(defresource all-users []
  :allowed-methods [:get :post]
  :available-media-types ["application/json"]
  :handle-ok (fn [_] {:users @users})
  :malformed? (fn [context] (malformed-users? context))
  :handle-malformed "You need to pass both a valid name and id"
  :post! (fn [context]
           (let [params (get-in context [:request :multipart-params])]
             (swap! users conj {:id (bigint (get params "id")) :name (get params "name")})))
  :handle-created (fn [_] {:users @users}))

(defroutes user-routes
  (ANY "/users" [_] (all-users)))


;; ====
; Test
;; ====
(fact "Get request to users endpoint returns desired content"
  (let [response (user-routes (mock/request :post "/users" {:id "3" :name "TestGuy"}))]
    (:status response) => 201
    (get-in response [:headers "Content-Type"]) => "application/json;charset=UTF-8"))

Solution

  • There are a few problems with this code.

    First, your resource accepts JSON, but your code uses multipart parameters. You need to decide whether you're accepting "application/json" or "multipart/form-data".

    Let's assume you're accepting JSON. In which case, you need to actually parse this data from the request body. Typically you do this at the :malformed? decision point. See the putting it all together documentation on the Liberator website.

    Third, your mock request needs to include a content type, and format the body as JSON. The Ring-Mock library is very simple; it can't guess what you need unless you tell it.

    There are a few other weird things in your code, such as (empty? (get params "id")). Do you really expect your "id" parameter to be a collection?

    I'd suggest taking a look at the Liberator examples, and try to get something simple working, before you attempt more complex resources.