Search code examples
clojuremacroscompojurering

Ring request map deconstruction macro


Trying to make a macro deconstruct parameters from a ring request map using a Macro. It works ok:

(defmacro defpage [fname args & body]
  `(defn ~fname [{{:keys ~args} :params}]
     ~@body))

(defpage h-projects [name description]
  ; some code using name and description...
   )

(defroutes app-routes
   (ANY "/p/" [] h-projects)

But, I would like to be able to use the request map directly in the h-projects function:

(defpage h-projects [name description]
  ; some code using name and description, and also
  ; the request map.
   )

How can the defpage macro be modified to make the request map available to the h-projects function?

I know I could change the parameters for the h-projects function, but I would like to keep the simple vector with parameters, not som deep nested deconstructing map.


Solution

  • You can destructure with the :as keyword to get a handle on the entire destructured map. To do this in a macro I'd recommend you take an input for what the name should be:

    (defmacro defpage [fname args map-name & body]
      `(defn ~fname [{{:keys ~args :as ~map-name} :params}]
         ~@body))
    

    but you can also choose to just define a "magic name" that all defpages share. This kinda loses clarity because when you read a defpage it looks like a name comes out of nowhere.

    (defmacro defpage [fname args & body]
      `(defn ~fname [{{:keys ~args :as ~'my-magic-name} :params}]
         ~@body))
    

    The ~' allows for namespace capture.