Fork me on GitHub
#beginners
<
2022-11-06
>
valerauko13:11:26

Which ring middleware keywordizes the keys of :headers in the request map? In one server that uses ring.middleware.defaults/api-defaults they are keywords but I can't pinpoint where it happens

dpsutton14:11:35

are you able to reproduce it locally?

(def wrapped (mid/wrap-defaults #'simple-handler mid/api-defaults))
(def server (jetty/run-jetty simple-handler
                             {:port 3000
                              :join? false}))
and when i curl "localhost:3000/foo?foo=bar" I'm seeing the headers and params look like:
{:headers
 {"accept" "*/*", "user-agent" "curl/7.79.1", "host" "localhost:3000"},
 :params {:foo "bar"}}
the params are keywordized but the headers remain as strings

dpsutton14:11:25

If you are seeing headers keywordized, look for any uses of ring.middleware.keyword-params in your project and see if you are pointing keyify-params at :headers somewhere

valerauko14:11:59

Yeah I tried that... I think the culprit will be aleph in the server where it's keywords. It seems that the header map reacts to both keys and strings? Knowing it wasn't the middleware I'll just adjust to using strings

valerauko14:11:34

Yeah now I'm super confused. The server where the headers are keywords (and upper-case keywords at that!) I don't see any middleware or manual setting doing it...

dpsutton14:11:33

check=> (get-in req [:headers "HOST"])
"localhost:3000"
check=> (get-in req [:headers :HOST])
"localhost:3000"
check=> (get-in req [:headers :HoSt])
"localhost:3000"

🤯 1
dpsutton14:11:28

the headermap doesn't have those keys, its just the way it looks it up it calls (str/lower-case (name k)) on the lookup value

dpsutton14:11:39

so all of these are looking for the header key "host"

valerauko14:11:22

Explains everything. Thanks a lot.

dpsutton14:11:19

Read it carefully because it has an “added” map that can lookup as normal that can shadow the actual header map. Not sure how that’s used in aleph though

Wen Hou17:11:49

using reagent, i have a leaf component that takes a single string ratom and reset! the ratom based on user input. If i want to use the leaf component in a top component with a list of string ratom input, how do deref the top ratom and pass it down to the leaf component, so that the leaf component mutation of the ratom is reflected to the top component? code snippet in thread:

Wen Hou17:11:53

(defn text
  [ratom]
  [:input {:type "text"
           :default-value @ratom
           :on-change #(reset! ratom (.. % -target -value ))}])

(defn lister [ratom]
  [:ul
   (for [item @ratom]
     ^{:key item} [:li [text (r/atom item)]])]) ;; <-- this won't update


(defcard-rg text-card
  (fn [ratom _ ] [text ratom])
  (r/atom "edit me")
  {:inspect-data true}
  )
(defcard-rg lister-card
  (fn [ratom _] [lister ratom])
  (r/atom ["edit1" "edit2"])
  {:inspect-data true})

Sam Ritchie20:11:32

I think you need to pass a cursor down

Sam Ritchie20:11:45

So don’t iterate on the dereferenced atom at the top level, iterate on (range (count @ratom)) and pass cursors for each index into each text component

Wen Hou02:11:59

thanks, cursor works, even wrap works. But i found them too heavy for changes the structure of one ratom to another, e.g. build atom of vector to atom of map and pass to child component. maybe that’s why most reagent tutorials i read use top level “global” state rather than passing triaged down atom-ish state to child components.

skylize19:11:29

Writing some code where a List is an appropriate data structure. Instead of (list foo), I am using (~foo)` as makeshift "list literal". Are there any surprises or gotchas to doing this?

(let [foo :foo]
  `(~foo)) ; => (:foo)

robertfw19:11:56

Why not just '(foo)? '(1 2 3) is the standard list literal https://www.clojure.org/guides/learn/syntax#_literal_collections

skylize19:11:10

Because

(let [foo :foo] '(foo))  ;; => (foo)
(let [foo :foo] `(~foo)) ;; => (:foo)

robertfw19:11:53

Ah yeah. I can't think of a surprise or gotcha, but if I were reviewing the code I'd suggest just using (list :foo) as it's far more obvious what is going on.

hiredman19:11:51

It depends what you mean by list

hiredman19:11:31

The list function returns a list which is like a seq with extra stuff, syntax quote returns a seq

skylize20:11:35

Good point. Exactly the type of detail I am asking about. In this case. I just need something appropriate as a second arg to cons, with values generally expected to be added/removed at the front.

hiredman20:11:57

cons will coerce a vector to a seq

skylize20:11:17

If I output a vector, with the intention that it will be treated like a list, I am relying on the consumer, with no warning, to not do anything where vectors are treated differently.