Skip to content

Refactor handlers and unit testsλ︎

Refactor the unit tests to use the ring-mock library to test handler functions. Create separate handler functions for the routes in defroute (there is only one custom handler at present).

(deftest dashboard-test
  (testing "Testing elements on the dashboard"
    (is (= (SUT/dashboard (mock/request :get "/"))
           {:status  200
            :body    "Status Monitor Dashboard"
            :headers {}}))))

Create a handler for the GET "/" route

(defn dashboard
  [request]
  {:status (:OK http-status-code) :body "Status Monitor Dashboard" :headers {}})

Use the ring.util.response/response function to create a well formed response map which has a status code of 200. This removes the need to type in the response map structure explicitly which potentially can introduce bugs.

In the current namespace ns form, this function is required as an explicit refer, [ring.util.response :refer [response]], so its available to use by its unqualified name, response.

(defn dashboard
  [request]
  (response "Status Monitor Dashboard"))

Update the defroutes definition to call this handler rather than hard coding the response map.

(defroutes status-monitor
  (GET "/" [] dashboard)
  (GET "/request-dump" [] handle-dump)
  )

Run the Cognitect test runner to check the unit tests are still passing after the code refactor.

clojure -M:env/dev:test:runner

Helper functionsλ︎

The ring util library contains several other helper functions, bad-request, not-found and redirect:

(ring.util.response/bad-request "Hello")
;;=> {:status 400, :headers {}, :body "Hello"}

(ring.util.response/created "/post/clojure-is-awesome")
;;=> {:status 201, :headers {"Location" "/post/clojure-is-awesome"}, :body nil}

(ring.util.response/redirect "https://clojure.org/getting-started/")
;;=> {:status 302, :headers {"Location" "https://clojure.org/getting-started/"}, :body ""}

The status function converts an existing response to use a given status code (which can be anything). Use this with care and document what the status code means otherwise confusion will abound.

(ring.util.response/status (ring.util.response/response "Time for Cake!") 555)
;;=> {:status 555, :headers {}, :body "Time for Cake!"}

Ring utilities has functions for setting the header data for responses, content-type, header or set-cookie.

(ring.util.response/content-type (ring.util.response/response "Hello") "text/plain")
;;=>  {:status 200, :headers {"Content-Type" "text/plain"}, :body "Hello"}

(ring.util.response/header (ring.util.response/response "Hello") "X-Tutorial-For" "Practicalli")
;;=>  {:status 200, :headers {"X-Tutorial-For" "Practicalli"}, :body "Hello"}

(ring.util.response/set-cookie (ring.util.response/response "Hello") "User" "123")
;;=>  {:status 200, :headers {}, :body "Hello", :cookies {"User" {:value "123"}}}

wrap-cookies middleware required

The set-cookie function adds a new entry to the response map and requires the wrap-cookies middleware to process correctly.

Handler functionsλ︎

A handler to return the incoming IP Address

(defn check-ip-handler [request]
    (ring.util.response/content-type
        (ring.util.response/response (:remote-addr request))
        "text/plain"))