Share your thoughts in the 2024 State of Clojure Survey!

Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by

I have several request handlers which all follow a similar pattern.


(defn handle-data-1
  [req]
  {:pre [(some? req)]}
  (try
    (let [start-date (parse-query-param (-> req :params :start-date))
          end-date (parse-query-param (-> req :params :end-date))
          data (db/fetch-data-1 start-date end-date)
          data-count (count data)]
      (log/debugf "data-count=%d start-date=%s end-date=%s" data-count start-date end-date)
      (if (pos? data-count)
        {:status 200
         :body data}
        {:status 404}))
    (catch Exception e
      (let [error-message (.getMessage e)]
        (log/errorf "%s" error-message)
        {:status 500 :body error-message}))))

(defn handle-data-2
  [req]
  {:pre [(some? req)]}
  (try
    (let [limit (Long/valueOf (parse-query-param (-> req :params :limit)))
          data (db/fetch-data-2 limit)
          data-count (count data)]
      (if (pos? data-count)
        {:status 200
         :body data}
        {:status 404}))
    (catch Exception e
      (let [error-message (.getMessage e)]
        (log/errorf "%s" error-message)
        {:status 500 :body error-message}))))

(defn handle-data-3
  [_]
  (try
    (let [data (db/fetch-data-3)
          data-count (count data)]
      (log/debugf "data-count=%d" data-count)
      (if (pos? data-count)
        {:status 200
         :body data}
        {:status 404}))
    (catch Exception e
      (let [error-message (.getMessage e)]
        (log/errorf "%s" error-message)
        {:status 500 :body error-message}))))

I'm trying to make a generic function which can be used by all the handle functions. Something like:


(defn try-query [f]
  {:pre [(some? f)]}
  (try
    (let [data (f) ;; <- need to invoke function and store results in data
          data-count (count data)]
      (if (pos? data-count)
        {:status 200
         :body data}
        {:status 404}))
    (catch Exception e
      (let [error-message (.getMessage e)]
        (log/errorf "%s" error-message)
        {:status 500 :body error-message}))))

(defn handle-data-1 [req]
  (let [start-date (parse-query-param (-> req :params :start-date))
        end-date (parse-query-param (-> req :params :end-date))]
    (log/debugf "start-date=%s end-date=%s" start-date end-date)
    (try-query (fn [] (db/fetch-data-1 start-date end-date))))) ;; 

The generic function needs to take another function (or closure) as a parameter and it can be of varying arity. I want that generic function to invoke the passed-in function and store its results in a variable.

In Ruby I could do this by passing a lambda to the function, then inside the function call the lambda. I'm not sure how to achieve this in Clojure.

Any ideas?

by
edited by
It's working now. I believe the original `Cannot open <nil> as a Reader` error was being caused by a missed deref further up the call chain.

I moved the function to let to clean it up a little:

(defn handle-data-1 [req]
  (let [start-date (parse-query-param (-> req :params :start-date))
        end-date (parse-query-param (-> req :params :end-date))
        query-fn (fn [] (db/fetch-data-1 start-date end-date)]
    (log/debugf "start-date=%s end-date=%s" start-date end-date)
    (try-query query-fn))))

1 Answer

0 votes
by

Are you seeing an error when you run this? It's difficult to know without the missing context. In any case, as long as the argument f in try-query is a function, then the form (f) will invoke it.

by
Yes: `Cannot open <nil> as a Reader.` I've tried the short-hard way too, same error.
by
I believe that error was being caused by a missed deref further up the call chain.
...