Fork me on GitHub
#clojure
<
2021-10-18
>
paulspencerwilliams10:10:32

Hey, any recommendations on how to stub error http responses from clj-http. I’m currently using conjure to stub successful responses but need errors to hit for example this 403 block

(try+
  (client/get "")
  (catch [:status 403] {:keys [request-time headers body]}
    (log/warn "403" request-time headers)))

Ed11:10:21

if it's for running some tests, you could use with-redefs to temporarily change the definition of client/get?

paulspencerwilliams11:10:49

Thats what conjure does. I’m trying to figure what an error value looks like

paulspencerwilliams11:10:32

Haha, I’ve just been pointed in that direction. Cheers, trying now 🤞

dharrigan14:10:20

I also successfully use wiremock

dharrigan14:10:25

pretty easy to use with Clojure

paulspencerwilliams14:10:13

I’ve used wiremock frequently from Java but thought there might something less ‘heavy’

dharrigan15:10:59

Yeah, agreed, can be heavy to mock out an entire HTTP call

pinkfrog14:10:38

Hi guys. How do you feel about redisson vs other redis clients in clojure land? I am in choosing a redis client which shall have rich functionalities such as redis stream, distributed lock, etc (I don’t mind implementing the features with the client thought).

dharrigan14:10:51

My go-to redis library is . I find it works really well.

dharrigan14:10:46

(at work, we use carmine)

pinkfrog15:10:30

Thanks. Going to have a taste with the raw lettuce library.

hiredman15:10:57

We a we aren't super heavy redis users at work, some key value stuff, some pubsub stuff, and redisson worked just fine, but the big reason we moved away was it was a long term maintenance headache because it depends on both netty and Jackson, two big complicated common java dependencies, so it often conflicted with other java libraries

hiredman15:10:47

We're just using jedis now, which is more minimal, but like I said we don't use a ton of features

Eddie15:10:43

Is there a way to core.match on a list?

(match ['(1 2)]
    [(a b)]
    a)
;; Invalid list syntax b in (a b) ...
I feel like I am missing something obvious but I’m not seeing it in the wiki.

borkdude15:10:16

@erp12

user=>  (match ['(1 2)] [([a b] :seq)] a)
1

Eddie15:10:21

Ah thanks @borkdude! I was just reading the :seq docs and getting confused by the extra nesting. That minimal example helps.

dpsutton15:10:12

i always go look at the tests for core.match when i forget a syntax

👍 2
borkdude15:10:30

I quickly tried it in the #babashka repl which also has core.match :-)

richiardiandrea18:10:03

Hi there, what is the best way to store an ex-info on file and then read it back in Clojure code? I have tried with Throwable->map and edn/read-string but that throws an exception to me:

No dispatch macro for: "
Execution error at nrepl.middleware.interruptible-eval/evaluate$fn$fn (interruptible_eval.clj:87).
...

borkdude18:10:51

@richiardiandrea it seems you have written a regex to EDN but EDN doesn't support Clojure regex notation

richiardiandrea18:10:04

Not sure about regexes, what I am doing is

(spit (io/file filename) (Throwable->map ex-info))
and then
(edn/read-string filename)

borkdude18:10:26

What I'm saying is that your error is likely the result of writing a regex to the file.

user=> (clojure.edn/read-string (pr-str #"foo"))

Execution error at user/eval1 (REPL:1).
No dispatch macro for: "

❤️ 1
borkdude18:10:38

a regex as part of your throwable map

richiardiandrea18:10:38

ok weird, I don't think I have control over the ex-info map

borkdude18:10:21

btw if you really need to read regexes as edn, you can use edamame for this which optionally supports it

👍 1
borkdude18:10:29

but in general you still can have objects in your data which won't work

borkdude18:10:46

although you could work around those perhaps as well

❤️ 1
borkdude18:10:00

(edamame.core/parse-string "..." {:regex true})

richiardiandrea18:10:15

I think it's clara rules printing out regexes

borkdude18:10:45

user=> (def m {:a (Object.) :b #"foo"})
#'user/m
user=> (pr-str m)
"{:a #object[java.lang.Object 0x2a50b32d \"java.lang.Object@2a50b32d\"], :b #\"foo\"}"
user=> (e/parse-string (pr-str m) {:readers (fn [tag] identity) :regex true})
{:a [java.lang.Object 709931821 "java.lang.Object@2a50b32d"], :b #"foo"}

borkdude18:10:29

Another approach might be to sanitize the data structure first before writing it

richiardiandrea18:10:54

@borkdude is the above edamame only or clojure as well? Sorry got confused 😄

borkdude18:10:11

The above e/parse-string call is edamame

borkdude18:10:19

Clojure does not support this

richiardiandrea18:10:43

ok thanks for confirming

richiardiandrea19:10:08

edamame's (-> file-path slurp (e/parse-string {:readers (constantly identity) :regex true})) Works like a charm on these logs. Thanks @borkdude. For the future ones I am thinking of pre-processing but your parser really helped here.

borkdude18:10:33

in general you can't expect random data written to disk be readable as EDN

richiardiandrea18:10:48

ok, would pr-str help then?

borkdude18:10:59

no. see other thread.

hiredman18:10:24

Execution error at nrepl.middleware.interruptible-eval/evaluate$fn$fn is not a string that Throwable->map produces, so it seems like what you are trying to read was not produced by Throwable->map

mpenet18:10:29

exoscale/ex has something like that, based on datafy. But it's assumed everything in ex-data is serializable and the ex-cause is intentionally left out

👍 1
hiredman18:10:50

user=> (clojure.edn/read-string (pr-str (Throwable->map (Exception.))))
{:via [{:type java.lang.Exception, :at [user$eval5 invokeStatic "NO_SOURCE_FILE" 1]}], :trace [[user$eval5 invokeStatic "NO_SOURCE_FILE" 1] [user$eval5 invoke "NO_SOURCE_FILE" 1] [clojure.lang.Compiler eval "Compiler.java" 7181] [clojure.lang.Compiler eval "Compiler.java" 7136] [clojure.core$eval invokeStatic "core.clj" 3202] [clojure.core$eval invoke "core.clj" 3198] [clojure.main$repl$read_eval_print__9112$fn__9115 invoke "main.clj" 437] [clojure.main$repl$read_eval_print__9112 invoke "main.clj" 437] [clojure.main$repl$fn__9121 invoke "main.clj" 458] [clojure.main$repl invokeStatic "main.clj" 458] [clojure.main$repl_opt invokeStatic "main.clj" 522] [clojure.main$main invokeStatic "main.clj" 667] [clojure.main$main doInvoke "main.clj" 616] [clojure.lang.RestFn invoke "RestFn.java" 397] [clojure.lang.AFn applyToHelper "AFn.java" 152] [clojure.lang.RestFn applyTo "RestFn.java" 132] [clojure.lang.Var applyTo "Var.java" 705] [clojure.main main "main.java" 40]]}
user=>

👍 1
richiardiandrea18:10:37

Got it, it seems then something in the ex-data is not serializable, thanks everybody

(ex-info "Exception caught while running the rule engine."
                              {:action action
                               :tree root}
                              exception)

dpsutton18:10:57

if you are writing to a file, can you just go look at the file to see what's in there?

richiardiandrea18:10:36

Yep I definitely can, I was not sure it was in the data... No dispatch macro for: " was not really hinting at that

Alex Miller (Clojure team)18:10:25

that's the reader finding #" - the leading # is a character in the reader indicating a dispatch macro, and #" is not in the reader table

Alex Miller (Clojure team)18:10:20

or maybe that's something hard to print that's showing up in that way, but it's something like that

richiardiandrea18:10:31

Oh thanks Alex that's why sounds good

Alex Miller (Clojure team)18:10:04

the EdnReader dispatch does not support #"" so if you try to read that in edn, that's what you'll get

Alex Miller (Clojure team)18:10:10

user=> (clojure.edn/read-string "#\"abc\"")
Execution error at user/eval3 (REPL:1).
No dispatch macro for: "

👍 1
richiardiandrea19:10:08

edamame's (-> file-path slurp (e/parse-string {:readers (constantly identity) :regex true})) Works like a charm on these logs. Thanks @borkdude. For the future ones I am thinking of pre-processing but your parser really helped here.

dpsutton22:10:43

is there a good way to spec a comma separated list of values in a string?

(s/def ::valid-dbs
  (fn [s]
    (let [dbs (into #{} (map str/trim) (str/split s #","))]
      (and (seq dbs)
           (every? #{"h2" "mysql" "mariadb" "postgresql"} dbs)))))
Is there a way to conform to the split string and then use a traditional (s/def ::db-types #{"h2" ...})?

Alex Miller (Clojure team)23:10:49

Any predicate function can be a spec

Alex Miller (Clojure team)23:10:00

Beyond that, you need to also consider whether unforming and gen are important to you

Alex Miller (Clojure team)23:10:50

In general I would caution against doing too much coercion at the same time as validation

dpsutton23:10:45

We just validate. And i'm looking for the best error message.

"h2,mysqll" - failed: (fn [s] (let [dbs (into #{} (map trim) (split s #","))] (and (seq dbs) (every? #{"mysql" "postgresql" "h2" "mariadb"} dbs)))) in: [:preConditions 0 :dbms :type] at: [:preConditions :dbms :type] spec: :change-set.common/valid-dbs

dpsutton23:10:33

The function goes in the failure message and the errors for

(s/explain #{:a :b} :c)
:c - failed: #{:b :a}
are a bit more clear

dpsutton23:10:04

it's just validating some yaml so just looking for the easiest to understand for a dev

dpsutton23:10:14

although it's not terrible here. just wondering if there was a bit cleaner way to get something similar to the "mysqll" failed #{"h2" "mysql"} type message