Search code examples
clojureroutesmetaprogrammingnoir

Nest Noir Routes


I have an app that generates keys based for specific datastores. If there are 7 such routes and 5 apps, there would be a total of 35 routes in my event.clj (or, if split out, 7/file in 5 files). I would like to do the following dynamically:

(defnested "/:app-name"
    (defpage "/generate/event" {:keys [app-name event-name time] :as key-map}
     (response/json
      {:key (key-model/build-key :event key-map)}))

    (defpage "/generate/event/unread" {:keys [app-name event-name] :as key-map}
     (response/json
      {:key (key-model/build-key :unread-for-event key-map)}))
)

That way I can write each route once and then pass around the app-name (instead of passing it in the query params, which works but isn't very RESTful.

BONUS

How can I dynamically call a namespace so that key-model/build-key becomes a call to redis-model/build-key or riak-model/build-key based on the app name?


Solution

  • Not sure if I understand the question but isn't this what your are looking for:

    (defpage "/:app-name/generate/event" {:keys [app-name event-name time] :as key-map}
        (response/json
          {:key (key-model/build-key :event key-map)}))
    
    (defpage "/:app-name/generate/event/unread" {:keys [app-name event-name] :as key-map}
         (response/json
          {:key (key-model/build-key :unread-for-event key-map)}))
    

    BONUS

    I will also go for a simple solution of having a map with the funcitons to generate the keys, something like:

    (def key-gen {"redis" redis-model/build-key
           "riak" riak/build-key})
    
    (response/json
          {:key ((get key-gen app-name) :event key-map)})
    

    If you really want to dynamically find the build-key function, you can do something like:

    (defn build-key [app-name] 
       (let [the-ns (symbol (str app-name "-model"))] 
          (require the-ns) 
          (ns-resolve the-ns 'build-key)))