1
votes

I'm using the below code to try and access some json input in a PUT request however what I get returned has :body {}, I'm not sure what I'm doing wrong?

(ns compliant-rest.handler
  (:use compojure.core ring.middleware.json)
  (:require [compojure.handler :as handler]
            [compojure.route :as route]
            [ring.util.response :refer [response]]
            [clojure.data.json :refer [json-str]]))

(defroutes app-routes
  (PUT "/searches" {body :params} (response body))
  (route/resources "/")
  (route/not-found "Not Found"))

(def app
  (-> (handler/site app-routes)
      (wrap-json-body)
      (wrap-json-response)))

(app {
      :request-method :put 
      :uri "/searches" 
      :content-type "application/json" 
      :body (with-in-str (json-str {:field "value"}))
      })

;; {:status 200, :headers {"Content-Type" "application/json; charset=utf-8"}, :body "{}"}

Also, I'm new to Clojure/Lisp, any comments about my syntax and style would be appreciated.

2

2 Answers

4
votes

Two things stand out:

The unparsed request body is not supposed to be a string, but an InputStream. This means your test expression won't work as is.

wrap-json-body replaces (:body request) with a clojure data structure. It does not put anything in (:params request) or (:body (:params request)). You want wrap-json-params for that.

3
votes

Thanks to Joost and the comments I found there is a ring function ring.util.io.string-input-stream that does what I mistakenly thought with-in-str did. Finally I had the following working:

(ns compliant-rest.handler
  (:use compojure.core ring.middleware.json)
  (:require [compojure.handler :as handler]
            [compojure.route :as route]
            [ring.util.response :refer [response]]
            [ring.util.io :refer [string-input-stream]]
            [clojure.data.json :refer [json-str]]))

(defroutes app-routes
  (PUT "/searches/:id" {params :params body :body}
       (response body))
  (route/resources "/")
  (route/not-found "Not Found"))

(def app
  (-> (handler/site app-routes)
      (wrap-json-body)
      (wrap-json-response)))

;; Example request
(app {
      :request-method :put 
      :uri "/searches/1" 
      :content-type "application/json" 
      :body (string-input-stream (json-str {:key1 "val1"}))
      })
;; {:status 200, :headers {"Content-Type" "application/json; charset=utf-8"}, :body "{\"key1\":\"val1\"}"}

It's so awesome that I can just create a simple map and call my api's entry point without needing any sort of server or mocking. I'm totally being pulled into this whole dynamic languages thing with Clojure, the repl and light table!