0

I am new to clojure and I am trying to make a simple API with 3 endpoints. I am trying to implement an endpoint which will take each row of a query and put it to a json. So I have an SQLite database. These are my entries for example:

{:timestamp 2020-09-11 14:29:30, :lat 36.0, :long 36.0, :user michav}
{:timestamp 2020-09-11 14:31:47, :lat 36.0, :long 36.0, :user michav}

So I want a json response like the below:

{:get
    :status 200
    :body {:timestamp "2020-09-11 14:29:30" 
           :lat 36.0 
           :long 36.0
           :user "michav"}
          {:timestamp "2020-09-11 14:31:47" 
           :lat 36.0 
           :long 36.0
           :user "michav"}
   }

} Here is my code that I am trying to fix it in order to get the above result.

(def db
    {:classname   "org.sqlite.JDBC"
     :subprotocol "sqlite"
     :subname     "db/database.db"
    }) 
 
 (defn getparameter [req pname] (get (:params req) pname))

 (defn output
    "execute query and return lazy sequence"
    []
    (query db ["select * from traffic_users"]))

 (defn print-result-set
    "prints the result set in tabular form"
    [result-set]
    (doseq [row result-set]
        (println row)))

  (defn request-example [req]
    (response {:get {:status 200 
                     :body  (-> (doseq [row output]
                                {:timestamp  (getparameter row :timestamp) :lat  (getparameter row :lat) :long  (getparameter row :long) :user  (getparameter row :user)} ))
                     }}))
  
(defroutes my_routes
    (GET "/request" [] request-example)
    (route/resources "/"))

(def app (-> #'my_routes wrap-cookies wrap-keyword-params wrap-params wrap-json-response))

The error I encounter is the following :

java.lang.IllegalArgumentException: Don't know how to create ISeq from: mybank.core$output
                             RT.java:557 clojure.lang.RT.seqFrom
                             RT.java:537 clojure.lang.RT.seq
                            core.clj:137 clojure.core/seq
                            core.clj:137 clojure.core/seq
                             core.clj:65 mybank.core/request-example[fn]
                             core.clj:65 mybank.core/request-example
                             core.clj:63 mybank.core/request-example
                         response.clj:47 compojure.response/eval1399[fn]
                          response.clj:7 compojure.response/eval1321[fn]
                            core.clj:158 compojure.core/wrap-response[fn]
                            core.clj:128 compojure.core/wrap-route-middleware[fn]
                            core.clj:137 compojure.core/wrap-route-info[fn]
                            core.clj:146 compojure.core/wrap-route-matches[fn]
                            core.clj:185 compojure.core/routing[fn]
                           core.clj:2701 clojure.core/some
                           core.clj:2692 clojure.core/some
                            core.clj:185 compojure.core/routing
                            core.clj:182 compojure.core/routing
                         RestFn.java:139 clojure.lang.RestFn.applyTo
                            core.clj:667 clojure.core/apply
                            core.clj:660 clojure.core/apply
                            core.clj:192 compojure.core/routes[fn]
                            Var.java:384 clojure.lang.Var.invoke
                         cookies.clj:171 ring.middleware.cookies/wrap-cookies[fn]
                   keyword_params.clj:32 ring.middleware.keyword-params/wrap-keyword-params[fn]
                           params.clj:57 ring.middleware.params/wrap-params[fn]
                             json.clj:42 ring.middleware.json/wrap-json-response[fn]
                            Var.java:384 clojure.lang.Var.invoke
                           reload.clj:18 ring.middleware.reload/wrap-reload[fn]
                       stacktrace.clj:17 ring.middleware.stacktrace/wrap-stacktrace-log[fn]
                       stacktrace.clj:80 ring.middleware.stacktrace/wrap-stacktrace-web[fn]
                            jetty.clj:27 ring.adapter.jetty/proxy-handler[fn]
                        (Unknown Source) ring.adapter.jetty.proxy$org.eclipse.jetty.server.handler.AbstractHandler$ff19274a.handle
                 HandlerWrapper.java:127 org.eclipse.jetty.server.handler.HandlerWrapper.handle
                         Server.java:500 org.eclipse.jetty.server.Server.handle
                    HttpChannel.java:386 org.eclipse.jetty.server.HttpChannel.lambda$handle$1
                    HttpChannel.java:562 org.eclipse.jetty.server.HttpChannel.dispatch
                    HttpChannel.java:378 org.eclipse.jetty.server.HttpChannel.handle
                 HttpConnection.java:270 org.eclipse.jetty.server.HttpConnection.onFillable
             AbstractConnection.java:311 org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded
                   FillInterest.java:103 org.eclipse.jetty.io.FillInterest.fillable
                ChannelEndPoint.java:117 org.eclipse.jetty.io.ChannelEndPoint$2.run
                 EatWhatYouKill.java:336 org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask
                 EatWhatYouKill.java:313 org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce
                 EatWhatYouKill.java:171 org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce
                 EatWhatYouKill.java:135 org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce
               QueuedThreadPool.java:806 org.eclipse.jetty.util.thread.QueuedThreadPool.runJob
               QueuedThreadPool.java:938 org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run
                        (Unknown Source) java.lang.Thread.run

1 Answer 1

2

Your mistake is on this line:

(doseq [row output] ...

The error message

Don't know how to create ISeq from: mybank.core$output

gives the clue. The variable output is the function, not a sequence like doseq expects. You meant to call the output function, so you need to use parentheses to create a function call like:

(doseq [row (output)] ...

Update

You need to include an external library to convert between EDN data and a JSON string. My favorite way is my own library Tupelo Clojure. Use it like this:

(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(let [data [{:timestamp "2020-09-11 14:29:30", :lat 36.0, :long 36.0, :user "michav"}
            {:timestamp "2020-09-11 14:31:47", :lat 36.0, :long 36.0, :user "michav"}]]
  (println (edn->json data)))

with result:

[{"timestamp":"2020-09-11 14:29:30","lat":36.0,"long":36.0,"user":"michav"},
 {"timestamp":"2020-09-11 14:31:47","lat":36.0,"long":36.0,"user":"michav"}]

You will need a line like this in your project.clj:

[tupelo "20.08.27"] 

Please also see this template project for an easy way to get started. Enjoy!

Sign up to request clarification or add additional context in comments.

2 Comments

I haven tested at all your solution because I have another problem which I hope I will solve it soon
Could you also advice me how could I write to the json those multiple lines I want??

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.