Search code examples
jsonclojurecompojurehateoas

How to get the selflink in a compojure handler?


When defining a compojure handler e.g. by using the defroutes macro, I can do something like this:

(defroutes home-routes
  (GET "/myhome/:id" [ id ] (home-page)))

(defn home-page [ id ]
   ( ... do something ... ))

So I know how to pass a piece of the path parameter. But imagine I want to return a HAL+JSON object with a selflink. How would I get defroutes to pass the whole URI to the home-page function?


Solution

  • The Ring request map contains all the necessary information to construct a "selflink". Specifically, :scheme, :server-name, :server-port, and :uri values can be assembled into full request URL. When I faced this problem I created Ring middleware that adds the assembled request URL to the Ring request map. I could then use the request URL in my handlers as long as I pass the request map (or some subset of it) into the handler. The following snippet shows one way of implementing this:

    (defroutes app-routes
      (GET "/myhome/:id" [id :as {:keys [self-link]}] (home-page id self-link))
      (route/resources "/")
      (route/not-found "Not Found"))
    
    (defn wrap-request-add-self-link [handler]
      (fn add-self-link [{:keys [scheme server-name server-port uri] :as r}]
        (let [link (str (name scheme) "://" server-name ":" server-port uri)]
          (handler (assoc r :self-link link)))))
    
    (def app
      (-> app-routes
        handler/site
        wrap-request-add-self-link))