Fork me on GitHub
#beginners
<
2022-12-24
>
Joseph Graham07:12:17

What am I doing wrong here?

(let [myvar 1] myvar)
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: myvar in this context

Joseph Graham07:12:34

OK I quit clojure and re-opened it and now it works

Joseph Graham07:12:00

oh it's the same repl where I redefined let

👀 3
🙂 1
2
👏 1
leinfink09:12:07

as one does 😆

kennytilton17:12:34

Lispers hold inalienable the right to shoot off our own toes. Welcome to the club.

😁 1
Uli14:12:31

Hi all. I think I'm just missig some obvious thing. What I'd like to achieve is essentially curl -d '{"A": "huhu"}' "" {"A" "huhu"} I'm trying to achieve this with:

(defn add-question [request]
  {:satus 200
   :headers {}
   :body (generate-string (:params request))})

(defroutes app-routes
  (GET "/" [] "Hello World")
  (POST "/api/srv/question" [] add-question)
  (route/not-found "Not Found"))

(def app (-> app-routes
             (wrap-params)))
while generate-string comes from chechire https://github.com/dakrone/cheshire but the result I get is:
curl -d '{"A": "huhu"}' ""
{}%
What am I missing?

dpsutton15:12:14

(ns server
  (:require cheshire.core
            [compojure.core :refer [defroutes GET POST]]
            [compojure.route :as route]
            [ring.adapter.jetty :as jetty]
            [ring.middleware.json :refer [wrap-json-response wrap-json-body]]
            [ring.middleware.params :as params]))


(defn add-question [request]
  {:satus 200
   :headers {}
   :body {:body (:body request)
          :params (:params request)}})

(defroutes app-routes
  (GET "/" [] "Hello World")
  (POST "/api/srv/question" [] add-question)
  (route/not-found "Not Found"))

(def app (-> app-routes
             params/wrap-params
             wrap-json-response
             wrap-json-body))

(comment
  (def server (jetty/run-jetty #'app {:port 4000 :join? false}))
  (.stop server)
  )

dpsutton15:12:58

i’ve added a few other things here. wrap-json-response will make maps returned be serialized into json. and wrap-json-body will parse the body of requests with an application/json content-type into a clojure datastructure

dpsutton15:12:16

and the crux of it is that you are sending the data over as the body of the request. It’s not a parameter of the request

dpsutton15:12:24

❯ curl --data '{"A": "huhu"}' --header 'Content-Type: application/json' ""
{"body":{"A":"huhu"},"params":{"params":"here"}}%

dpsutton15:12:08

I’m returning a map with two keys: • "body": This has the payload sent over • "params" this has the params from the route. (note my route is api/srv/question?params=here)

dpsutton15:12:13

deps required for these:

{:deps {ring/ring {:mvn/version "1.9.6"}
        compojure/compojure {:mvn/version "1.7.0"}
        ring/ring-json {:mvn/version "0.5.1"}
        cheshire/cheshire {:mvn/version "5.11.0"}}}

agile_geek15:12:35

FYI what you are destructuring in add-question (before @U11BV7MTK changes) are the query parameters passed to the URI not the body of the request (sent in the cURL -d option). So if you did this:

curl -X post ""
{"A":"huhu"}
You would see the expected results.

agile_geek15:12:26

The query params are key value pairs following the ?

dpsutton15:12:16

I believe it also includes route params. Like if your route was api/srv/question/<question-id> you would have the question id in the params map as well

Uli08:12:00

Ok, thank you very much @U11BV7MTKand @U05390U2P you helped me a lot here. I cannot tell you, why I missed something here, or what it was. I also was aware that params and body are diffferent things, but ring-documentation was a bit confusing in some paragraphs... any, I struggeled, because I constantly got an

:body #object[org.eclipse.jetty.server.HttpInputOverHTTP 0x
5f126a6c HttpInputOverHTTP@5f126a6c]

Uli08:12:01

why is it gone now? and how could I handle a inputOverHttp, seems to be a stream, also tried to play around with io/stream-reader... you see I dived in a big sea there 😄

Uli08:12:09

but maybe it also was a side-effect of using wrap-defaults with site-defaults.... have to dig around a bit

Uli08:12:48

I tried a lot there, also using api-defaults http://et.al.

Uli08:12:37

anyways: thanks a lot, your example here works perfectly fine for me so far, thank you!

mister_m18:12:31

~Hi - question about `line-seq` -- this just appears to hang my repl and I'm unable to interrupt evaluation when I invoke it with something like `(count (get-lines "~/tmp/blah.dat"))` . This file is outside of my project directory if that matters.~ ```(defn get-lines [file-pathname-string] (with-open [rdr (io/reader file-pathname-string)] (line-seq rdr)))``` ~What I think I am doing here is returning a lazy sequence of lines from this file that I could then use else where. Is that actually what I am doing?~ It is paredit messing with my repl. NEVERMIND

mister_m19:12:39

actually - the code above seems to consistently result in an IOException "stream closed" in the repl. I know that passing the line-seq to something like doallshould make it work but that defeats the purpose of the sequence, no? Is it possible to use line-seq on an io/reader result lazily?

emilaasa19:12:13

You can do the lazy work inside of the with-open before the stream is closed

phronmophobic19:12:42

If you macroexpand with-open, you'll see that it will close the reader before the function returns.

(clojure.core/let
 [rdr (io/reader file-pathname-string)]
 (try
  (clojure.core/with-open [] (line-seq rdr))
  (finally (. rdr clojure.core/close))))
If you want to read after the function returns, then you can't use with-open. However, if you don't use with-open , then you want some way to clean up at the right time (whenever that is).

emilaasa19:12:52

^ that's a better answer 🙂

phronmophobic19:12:16

It's usually fine to use doall in cases like these. The main exception is if the file is large and you don't want to hold the full contents of the file in memory. In those cases, you can do as @U6T7M9DBR suggests and do the processing inside.

phronmophobic19:12:47

I think processing a file line by line is a good use case for transducers. something like:

(defn transduce-lines [xform f init fname]
  (with-open [rdr (io/reader fname)]
    (transduce
     xform
     f
     init
     (line-seq rdr))))

;; count characters
(transduce-lines
 (map count)
 +
 0
 (io/file "deps.edn"))

mister_m20:12:17

I was just thinking on the drive home whether or not I could use a transducer here. That seems like a good approach

pppaul18:12:47

you don't need a transducer, even though it may be the better solution. to me the main idea in the transducer code is that you are processing the whole file in the fn, and one of the params is the transformation/behaviour. you can do this with or without a transducer, just make sure that your file processing function follows the same guidelines.

Lambdaphile20:12:47

Hmm, I guess it’s better to post noob questions here, than the Clojure/ClojureScript channels.

seancorfield20:12:41

Yes, you'll get more polite and more in-depth answers here as folks have opted in to helping folks who are new to Clojure/Script.

❤️ 1
Lambdaphile20:12:13

Can someone help me understand why empty? doesn’t work in functions like map, filter (empty? '()) => true filter empty? '((1, 2, 3), (), (4, 5, 6)) => '((1, 2, 3), (), (4, 5, 6)) ; Doesn't filter the empty list items

phronmophobic20:12:26

I think you're missing some parens and it's just returning the last form

phronmophobic20:12:37

> (filter empty? '((1, 2, 3), (), (4, 5, 6)))
(())

👍 1
Lambdaphile20:12:29

O_O Yeah, just noticed. I have to look better. Thanks!

👍 1
Lambdaphile20:12:49

What are some good online Clojure REPL’s that I can use to share code? 😄 Currently, the only one that I’m aware of is Replit