Arguments getting mismatched

FUNCTION:

(defn download-chatrooms
  "Export chatrooms of the workflow template in CSV format"
  [db-spec org-id uid template-id & {:keys [order-by filter-by report-id]}]
    (println "ORDR_BY FILTR_BY RPTID " order-by filter-by report-id))

FUNCTION CALL:

(fn [context]
     (let [{:keys [org-id uid]} (get-in context [:request])
           db (get-in context [:request :system :db])
           id (get-in context [:request :path-params :id])
           {sort :sort :as params} (context :kebab-params)
           {:keys [filename data]} (p/download-chatrooms db
                                                         org-id
                                                         uid
                                                         (read-string id)
                                                         (query/sorting-intent->map sort)
                                                         (dissoc params :page :sort))]

REQ:
http://localhost:3593/workflow/4/chatroom/download?page=1&sort=seqNo:desc&reportId=3
OUTPUT:
ORDR_BY FILTR_BY RPTID [{:seq-no desc}] {:report-id 3} nil

Why are these arguments getting mismatched?

But If I keep everything the same and just change the function signature to

(defn download-chatrooms
  "Export chatrooms of the workflow template in CSV format"
  [db-spec org-id uid template-id & [[order-by filter-by] report-id]]
  (println "ORDR_BY FILTR_BY RPTID " order-by filter-by report-id)

OUTPUT LOOKS CORRECT:
ORDR_BY FILTR_BY RPTID {:seq-no desc} nil {:report-id 3}

BUT THERE’S AN ERROR:
: clojure.lang.ExceptionInfo: java.lang.ClassCastException in Interceptor :workflow-instances-download - class clojure.lang.MapEntry cannot be cast to class clojure.lang.IPersistentMap (clojure.lang.MapEntry and clojure.lang.IPersistentMap are in unnamed module of loader 'app')

When you say & {:keys [foo bar]} in a function signature, it is expecting named arguments like this:

(some-func :foo 42 :bar "arg")

You are calling the function download-chatrooms with six positional arguments.

In the & [foo bar] case, you are describing optional positional arguments instead of named arguments.

Only the ones after & are the positional arguments, right?

If I keep the function

(defn download-chatrooms
  "Export chatrooms of the workflow template in CSV format"
  [db-spec org-id uid template-id & {:keys [order-by filter-by report-id]}]

And call it directly in the REPL (download-chatrooms (:myapp/db integrant.repl.state/system) 1 "L0QGp8J3P0fFNq7eGeR7Tl61UuL2" 4 :report-id 3)
I’m passing only report-id and ignore order-by and filter-by, then I get this ORDR_BY FILTR_BY RPTID nil nil 3 along with the data

But for the same function if I have another method call it like this:

(let [{:keys [org-id uid]} (get-in context [:request])
           db (get-in context [:request :system :db])
           id (get-in context [:request :path-params :id])
           {sort :sort :as params} (context :kebab-params)
           {:keys [filename data]} (p/download-chatrooms db
                                                         org-id
                                                         uid
                                                         (read-string id)
                                                         :report-id
                                                         {:report-id 3})]

The send a request http://localhost:3593/workflow/4/chatroom/download?page=1&sort=seqNo:desc&reportId=3 Then I get same like above ORDR_BY FILTR_BY RPTID nil nil 3 But doesn’t show the data and says this

ERROR [myapp.service:202] - : clojure.lang.ExceptionInfo: java.lang.IllegalArgumentException in Interceptor :workflow-instances-download - Failed to fetch the report {:execution-id 1, :stage :enter, :interceptor :workflow-instances-download, :exception-type :java.lang.IllegalArgumentException, :exception #error {
 :cause "Failed to fetch the report"
 :via
 [{:type java.lang.IllegalArgumentException
   :message "Failed to fetch the report"
   :at [myapp.db.process$get_report invokeStatic "process.clj" 677]}]

How is the req method making a difference than calling it direct?

They are positional before the &. They are positional after & as well if you use sequence destructuring & [foo bar]. They are named if you use map destructuring & {:keys [foo bar]}.

In both cases, the arguments after & are optional.

Your two calls – via the REPL and via the “req method” – are different. In the REPL you pass :report-id 3 but in the other code you pass :report-id {:report-id 3}. In the first case, report-id is bound to 3 in the call. In the second case, report-id is bound to a hash map (which is why you get the illegal argument exception): {:report-id 3}

oh…
So it should be?

(let [{:keys [org-id uid]} (get-in context [:request])
           db (get-in context [:request :system :db])
           id (get-in context [:request :path-params :id])
           {sort :sort :as params} (context :kebab-params)
           {:keys [filename data]} (p/download-chatrooms db
                                                         org-id
                                                         uid
                                                         (read-string id)
                                                         :report-id
                                                         3)]

That would match the (successful) call from the REPL, yes.

There’s no error now but the postman just says 200OK no output