Fork me on GitHub

Or Transit.

👍 1

But transit requires a dependency, right?


I am stuck figuring out how to create a list with elements from 2 long object ? argh> (def bob 3) #'argh/bob argh> (def sue 7) #'argh/sue argh> (def l1 '(7 3)) #'argh/l1 argh> l1 (7 3) argh> (def l1-from-bob-n-sue '(bob sue)) #'argh/l1-from-bob-n-sue argh> l1-from-bob-n-sue (bob sue) But i want same as l1 ie.. (7 3)

Ferdinand Beyer10:03:26

Use (list bob sue)

Ferdinand Beyer10:03:19

The problem is that you use quote: '(bob sue) does not evaluate bob and sue but just keeps them as symbols. The list function evaluates its arguments and puts them in a list. Alternatively you could use “syntax quote” with “unquote”:

(def l1-from-bob-n-sue `(~bob ~sue))
Here, the backtick is a special form of quoting allowing to selectively “unquote” using the tilde ~. But list is probably easier to read 🙂


Or simply use a vector instead

✔️ 3

thx was trying to get list via ' but I can see my error now 😀 thx alot


Yeah the unquote thingy was the missing thing in my idea but def list was the intent


Why vector isnt that just another form of memory layout ? How does vector makes it easier?


Vectors do not require quoting, i.e. you can just write (def l1-from-bob-n-sue [bob sue]) and yes vectors grow (`conj`) at the end whereas lists grow at the beginning. Using vectors is idiomatic and common in clojure.

Tuomas-Matti Soikkeli10:03:05

You can pretty much always use vector [bob sue]. If you are really thinking how to optimise your performance, list has O(n) random access look up time compared to O(1) in vector.


thx for the vector reply


thx for the vector replys ..

Tuomas-Matti Soikkeli10:03:33

I think quotes are from the lisp heritage and perhaps not the first thing you should consider learning

👍 1

Yes @UTA54EFQF, the internals are different between vector and list but even though lists definitely have their uses, most of the time, especially as a beginner, when you think you need a list you really want a vector in Clojure, so reach out for vectors first.

  (def l (list :a :b :c))
  (def v [:a :b :c])
  (get v 1) ;; => :b
  (get l 1) ;; => nil
  (conj v :d) ;; => [:a :b :c :d]
  (conj l :d) ;; => (:d :a :b :c)
  (assoc v 1 :new-b) ;; => [:a :new-b :c]
  (assoc l 1 :new-b) ;; => ClassCastException
(plus the whole O(1) vs O(n) random access)


thx alot for the advice i really appreciate


does anyone know what might be causing this error when I’m making a request to the server:

{:cached nil, :request-time 35, :repeatable? false, :protocol-version {:name "HTTP", :major 1, :minor 1}, :streaming? true, :http-client #object[org.apache.http.impl.client.InternalHttpClient 0xb6a995b "org.apache.http.impl.client.InternalHttpClient@b6a995b"], :chunked? false, :type :clj-http.client/unexceptional-status, :reason-phrase "Server Error", :headers {"Connection" "close", "Cache-Control" "must-revalidate,no-cache,no-store", "Content-Type" "text/html;charset=iso-8859-1", "Content-Length" "3076", "Server" "Jetty(9.4.28.v20200408)"}, :orig-content-encoding nil, :status 500, :length 3076, :body "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\n<title>Error 500 java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #&apos;ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap</title>\n</head>\n<body><h2>HTTP ERROR 500 java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #&apos;ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap</h2>\n<table>\n<tr><th>URI:</th><td>/api/login</td></tr>\n<tr><th>STATUS:</th><td>500</td></tr>\n<tr><th>MESSAGE:</th><td>java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #&apos;ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap</td></tr>\n<tr><th>SERVLET:</th><td>-</td></tr>\n<tr><th>CAUSED BY:</th><td>java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #&apos;ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap</td></tr>\n</table>\n<h3>Caused by:</h3><pre>java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #&apos;ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap\n\tat clojure.core$_cache_protocol_fn.invokeStatic(core_deftype.clj:583)\n\tat clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:575)\n\tat ring.core.protocols$eval25675$fn__25676$G__25666__25685.invoke(protocols.clj:8)\n\tat ring.util.servlet$update_servlet_response.invokeStatic(servlet.clj:106)\n\tat ring.util.servlet$update_servlet_response.invoke(servlet.clj:91)\n\tat ring.util.servlet$update_servlet_response.invokeStatic(servlet.clj:95)\n\tat ring.util.servlet$update_servlet_response.invoke(servlet.clj:91)\n\tat ring.adapter.jetty$proxy_handler$fn__32745.invoke(jetty.clj:28)\n\tat ring.adapter.jetty.proxy$org.eclipse.jetty.server.handler.AbstractHandler$ff19274a.handle(Unknown Source)\n\tat org.eclipse.jetty.server.handler.HandlerWrapper.handle(\n\tat org.eclipse.jetty.server.Server.handle(\n\tat org.eclipse.jetty.server.HttpChannel.lambda$handle$1(\n\tat org.eclipse.jetty.server.HttpChannel.dispatch(\n\tat org.eclipse.jetty.server.HttpChannel.handle(\n\tat org.eclipse.jetty.server.HttpConnection.onFillable(\n\tat$ReadCallback.succeeded(\n\tat\n\tat$\n\tat org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(\n\tat org.eclipse.jetty.util.thread.QueuedThreadPool$\n\tat java.base/\n</pre>\n<hr><a href=\"\">Powered by Jetty:// 9.4.28.v20200408</a><hr/>\n\n</body>\n</html>\n", :trace-redirects []}


The error is > java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap Seems straightforward. You returned a map from a handler and your app doesn’t know how to serialize that to the response. I am guessing you intended that to come back as json or edn but haven’t hooked up the middleware that would do that transformation?

James Amberger17:03:44

Hello, can I have the accepted way to go from {:a []} to {:a [:b]} ? in particular when using update-in?


What have you tried?

James Amberger17:03:15

Is it just (update-in {:a []} [:a] cons :b)


Yup, except conj not cons


conj = generic “add to collection”


cons = specific prepend to list


user=> (conj [1 2 3] 4)
[1 2 3 4]
user=> (cons [1 2 3] 4) ;; broken arg order!
Execution error (IllegalArgumentException) at user/eval3 (REPL:1).
Don't know how to create ISeq from: java.lang.Long
user=> (cons 4 [1 2 3])
(4 1 2 3) ;; note it returns a seq, not a vector!

James Amberger17:03:52

yeah but isn’t it (conj coll item) where the funciton here will be getting coll in the last position?


update-in and similar functions will apply the function you pass (conj) to the thing it found, followed by trailing args


thing it found = []


trailing args = :b


(conj [] :b)

James Amberger17:03:39

“followed by trailing args” ok I see

James Amberger17:03:51

I did not grok this point about the behavior of update-in


you can add more trailing args


if the function you are passing can handle them

James Amberger17:03:20

i can add more rtailing args but the second position of what’s gonna get executed will be the [] (in this case)


there are a few other functions in clojure.core with this same exact argument shape: update-in update swap!


(update-in {:foo [:x]} [:foo] conj :b :c :d) (conj [:x] :b :c :d)

James Amberger17:03:50

As a beginner, I think the docstring for update-in is unnecessarily subtle as to this point!


I would recommend checking the community-written on update-in to see if it clarifies anything for you. It is not "official" docs, but there are often helpful examples there that the core documentation does not have.


You can create an question asking whether the built-in doc strings can be enhanced, but there is a very high bar there to pass before the Clojure core team would agree to changes.


ninja edited that ^

James Amberger17:03:13

definitely saved me a couple million brain cycles

🧠 1

does anyone know how one can replicate a request that contains :body-params using clj-http or peridot that don’t support the :body-params keys but in which the params have to be sent in the body? Here are body-params being sent: But when I try to send body-params like so using peridot:

(-> session
      (request "/api/reset-password"
               :content-type "application/json"
               :request-method :post
               :body (cc/generate-string
                      {:email email
                       :newPassword newPassword
                       :resetToken token}
the body-params don’t seem to be detected in the server. What am I doing wrong?


you need to look at the set of middleware that server uses


the set of middleware will tell you how and where the :body-params key comes from, which will tell you how it needs t o be sent


we’re using the same middleware as in the github example:

[;; swagger feature
   ;; query-params & form-params
   ;; content-negotiation
   ;; encoding response body
   ;; exception handling
   ;; decoding request body
   ;; coercing response bodys
   ;; coercing request parameters
   ;; multipart
but they seems to get the body-params in the server, whereas we don’t


I dunno anything about all this metosi stuff, but you have format-response-middleware and don't appear to have similar for requests


@hiredman I have both muuntaja/format-request-middleware and muuntaja/format-response-middleware


then you need to look at request middleware, figure out its rules for decoding stuff (good luck) and then have your requests put things in the format it wants


Can I pass a value by reference in clojure ?


technically all objects are passed by reference on the JVM (apart from primitive values like longs and doubles)


can you clarify what you actually need to do?


I need to pass a map to a function and need to add new key-value pair in that map and then use that map back in the calling function.


All Clojure collections are immutable. The typical way to do what you ask for is to pass one collection as a parameter, and the function returns a new collection that is similar to the one passed in, but with whatever "changes" you want to return, in the return value.


This is a big shift in thinking in day-to-day application development if you are accustomed to mutating objects.


In Clojure on the JVM, you can of course use mutable Java collections if you want to.


And in ClojureScript, you can use mutable JavaScript collections.


The thing is that it is already returning a function and I can not return new collection so I need to find way of extracting that value somehow


I think this might fix it: [ring.middleware.format-params :refer [wrap-format-params]] but including this gives:

Could not locate ring/middleware/format_params__init.class, ring/middleware/format_params.clj or ring/middleware/format_params.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.


even though I have ring in my project.clj


sure, what makes you think ring.middleware.format-params is a thing?


what happens on the server side when you make the request?


I get this:

actual: java.lang.NullPointerException: Cannot invoke "clojure.lang.IFn.invoke(Object, Object, Object)" because "this.handle_error" is null
 at ring.middleware.format_params$wrap_format_params$fn__28345.invoke (format_params.clj:115)
    reitit.ring$ring_handler$fn__23796.invoke (ring.cljc:329)
    clojure.lang.AFn.applyToHelper (
    clojure.lang.AFn.applyTo (
    clojure.lang.AFunction$1.doInvoke (
    clojure.lang.RestFn.invoke (
    peridot.core$request.invokeStatic (core.clj:18)
    peridot.core$request.doInvoke (core.clj:12)
    clojure.lang.RestFn.invoke (
    helpers.helpers$register_user.invokeStatic (helpers.clj:145)
    helpers.helpers$register_user.invoke (helpers.clj:143)
    unit.login_test$fn__33611.invokeStatic (login_test.clj:12)
    unit.login_test/fn (login_test.clj:11)
    clojure.test$test_var$fn__9761.invoke (test.clj:717)
    clojure.test$test_var.invokeStatic (test.clj:717)
    clojure.test$test_var.invoke (test.clj:708)
    clojure.test$test_vars$fn__9787$fn__9792.invoke (test.clj:735)
    helpers.fixtures$with_db$fn__33049.invoke (fixtures.clj:82)
    clojure.core$with_redefs_fn.invokeStatic (core.clj:7516)
    clojure.core$with_redefs_fn.invoke (core.clj:7500)
    helpers.fixtures$with_db.invokeStatic (fixtures.clj:29)
    helpers.fixtures$with_db.invoke (fixtures.clj:23)
    clojure.test$compose_fixtures$fn__9755$fn__9756.invoke (test.clj:694)
    clojure.test$default_fixture.invokeStatic (test.clj:687)
    clojure.test$default_fixture.invoke (test.clj:683)
    clojure.test$compose_fixtures$fn__9755.invoke (test.clj:694)
    clojure.test$test_vars$fn__9787.invoke (test.clj:735)
    clojure.test$default_fixture.invokeStatic (test.clj:687)
    clojure.test$default_fixture.invoke (test.clj:683)
    clojure.test$test_vars.invokeStatic (test.clj:731)
    clojure.test$test_all_vars.invokeStatic (test.clj:737)
    clojure.test$test_ns.invokeStatic (test.clj:758)
    clojure.test$test_ns.invoke (test.clj:743)
    clojure.core$map$fn__5884.invoke (core.clj:2759)
    clojure.lang.LazySeq.sval (
    clojure.lang.LazySeq.seq ( (
    clojure.lang.RT.boundedLength (
    clojure.lang.RestFn.applyTo (
    clojure.core$apply.invokeStatic (core.clj:669)
    clojure.test$run_tests.invokeStatic (test.clj:768)
    clojure.test$run_tests.doInvoke (test.clj:768)
    clojure.lang.RestFn.invoke (
    clojure.test$run_tests.invokeStatic (test.clj:773)
    clojure.test$run_tests.invoke (test.clj:768)
    unit.login_test$eval33664.invokeStatic (login_test.clj:50)
    unit.login_test$eval33664.invoke (login_test.clj:50)
    clojure.lang.Compiler.eval (
    clojure.lang.Compiler.load (
    user$eval33597.invokeStatic (form-init15147153642663810079.clj:1)
    user$eval33597.invoke (form-init15147153642663810079.clj:1)
    clojure.lang.Compiler.eval (
    clojure.lang.Compiler.eval (
    clojure.core$eval.invokeStatic (core.clj:3202)
    clojure.core$eval.invoke (core.clj:3198)
    nrepl.middleware.interruptible_eval$evaluate$fn__31851$fn__31852.invoke (interruptible_eval.clj:87)
    clojure.lang.AFn.applyToHelper (
    clojure.lang.AFn.applyTo (
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$with_bindings_STAR_.invokeStatic (core.clj:1977)
    clojure.core$with_bindings_STAR_.doInvoke (core.clj:1977)
    clojure.lang.RestFn.invoke (
    nrepl.middleware.interruptible_eval$evaluate$fn__31851.invoke (interruptible_eval.clj:87)
    clojure.main$repl$read_eval_print__9110$fn__9113.invoke (main.clj:437)
    clojure.main$repl$read_eval_print__9110.invoke (main.clj:437)
    clojure.main$repl$fn__9119.invoke (main.clj:458)
    clojure.main$repl.invokeStatic (main.clj:458)
    clojure.main$repl.doInvoke (main.clj:368)
    clojure.lang.RestFn.invoke (
    nrepl.middleware.interruptible_eval$evaluate.invokeStatic (interruptible_eval.clj:84)
    nrepl.middleware.interruptible_eval$evaluate.invoke (interruptible_eval.clj:56)
    nrepl.middleware.interruptible_eval$interruptible_eval$fn__31882$fn__31886.invoke (interruptible_eval.clj:152) (
    nrepl.middleware.session$session_exec$main_loop__31950$fn__31954.invoke (session.clj:202)
    nrepl.middleware.session$session_exec$main_loop__31950.invoke (session.clj:201) ( (


that looks like exception happening while looking for an error handle, which doesn't tell you what caused it to look for an error handler


oh, you aren't actually making a request, you are just passing the data to the function in a test, and passing a string where it wants an inputstream (would be my guess)


it’s a request


(-> session
      (request "/api/reset-password"
               :content-type "application/json"
               :request-method :post
               :body (cc/generate-string
                      {:email email
                                    :newPassword newPassword
                                    :resetToken token}


what is 'request'


and what does the peridot docs say about :body


it doesn't look like it does anything to body


so it doesn't turn body into an inputstream


the ring spec says :body is an inputstream


so the metosin whatever, if the body is present, treats it as an inputstream and tries to decode it


I mean, I don't know, if I were you the thing to do is figure out how to set whatever error handler retit wants so that you can display the error that happens, instead of getting a stacktrace that just tells you there was an error trying to call the error handler


this explains why the example app doesn't get the error


it doesn't have a :body, it passes in :body-params, so the stuff doesn't look for an inputstream in :body to decode from


the exception only happens with wrap-format-parasm


without it I get:


             "(spec-tools.core/spec {:spec (clojure.spec.alpha/keys :req-un [:lms.auth.spec/resetToken :lms.auth.spec/newPassword :lms.auth.spec/email]), :type :map, :leaf? false})",
             [{:path [],
               :pred "clojure.core/map?",
               :val nil,
               :via [:lms.auth.spec/reset-password-params],
               :in []}],
             :type :reitit.coercion/request-coercion,
             :coercion :spec,
             :value nil,
             :in [:request :body-params]}


notice :value nil in :request :body-params


there’s gotta be a middleware that converts body to body-params


I tried wrap-format-params but that gave the exception


I believe the m* whatever stuff does it, but I dunno that I want to spend my time digging through that, so you'll need to dig through it, it may still be the fact that you are passing in a string and not an inputstream