babashka

Casey 2025-07-25T10:53:15.913289Z

How can I disable babashka/http-clients default behavior to parse a body. I am trying to make a GET request to a url that returns a 302 with no body, I want to get the response headers to parse the Location header. But babashka fails with Cannot open <nil> as a Reader.

✅ 1
Casey 2025-07-25T10:53:50.159539Z

(http/get "" {:client (merge http/default-client-opts
                                                               {:follow-redirects :never})})
(unfortunately http://cljdoc.org doesn't handle the HEAD method

borkdude 2025-07-25T10:58:00.114409Z

(require '[babashka.http-client :as http]
         '[babashka.http-client.interceptors :as interceptors])

#_(prn (map :name interceptors/default-interceptors))

(prn
 (http/get ""
           {:client (merge http/default-client-opts
                           {:follow-redirects :never})
            :interceptors (filter #(not= :babashka.http-client.interceptors/decode-body (:name %))
                                  interceptors/default-interceptors)}))

❤️ 1
borkdude 2025-07-25T10:58:38.932969Z

If you think this is a bug, then we can make this more robust by checking for nil first

borkdude 2025-07-25T10:58:42.374139Z

PR welcome

borkdude 2025-07-25T11:48:37.558129Z

wow:

/private/tmp/kondo-performance/metabase/src/metabase/session/task/session_cleanup.clj
Inspected all files in 12,99 seconds.
Heap used: 28.159408569335938 MB

borkdude 2025-07-25T11:48:45.661709Z

:-D

borkdude 2025-07-25T11:54:08.025369Z

I localized all memoize usage to run! now, so all memory is freed after run!

borkdude 2025-07-25T11:55:18.565969Z

in graalvm native-image things have become slower though. maybe I shouldn't use a cache at all in some cases. needs more testing, but this is promising

Casey 2025-07-25T12:49:35.879139Z

nice job! .. but wrong thread?

borkdude 2025-07-25T12:51:08.972119Z

whoops sorry!

Casey 2025-07-25T12:58:26.881459Z

> If you think this is a bug, then we can make this more robust by checking for nil first My gut says this is a bug, because I don't think I should have to jump through hoops like that just to make an http request that returns no body (which is perfectly valid and normal).

borkdude 2025-07-25T12:59:39.859969Z

yeah seems like it

borkdude 2025-07-25T12:59:45.231729Z

isssue (+ optional PR) welcome

borkdude 2025-07-25T13:00:24.726129Z

What's weird is that the response I printed in the above script, doesn't even have a :status etc

Casey 2025-07-25T13:07:09.639449Z

Yea I just tested it, also no :headers

Casey 2025-07-25T13:07:30.332419Z

just :request and :`body`

borkdude 2025-07-25T13:16:07.880239Z

oh I get it, client shouldn't be a map

borkdude 2025-07-25T13:18:45.652989Z

so it works like expected, the client should just be like this:

(http/get ""
           {:client (http/client (merge http/default-client-opts
                                        {:follow-redirects :never}))
            })

🙏 1
borkdude 2025-07-25T13:19:21.354089Z

the error is confusing since client can also be a function where you do your own thing

Casey 2025-07-25T13:22:50.623059Z

oh interesting

Casey 2025-07-25T13:24:04.184599Z

I see where I went wrong. The client docstring says "To get the same behavior as the (implicit) default client, pass default-client-opts." and I then passed the twiddled client-opts to request, not the client fn.

borkdude 2025-07-25T13:24:22.740989Z

yeah, an easy mistake to make, glad we found it

Ryan Tate 2025-07-25T18:01:28.298869Z

If you need JVM clojure from within babashka, is the best solution just to shell out and call the clj/`clojure` cli? Maybe using babashka.process? Context is, I have a babashka cli tool with a bunch of subcommands, they all run fine under bb but now I need to add a couple of commands that need jvm stuff (kicking off Lucene indexing jobs, lot of interop). It's fine if these are slow since they'll be slow in any case - and I'd love to keep using the tool under bb since I call the other commands more often and they're much faster under bb. Thanks for any tips!

borkdude 2025-07-25T18:02:33.463019Z

@ryantate You can use babashka.tasks/clojure from bb.edn or babashka.deps/clojure (which is really the same function) in code files

🙌 1
borkdude 2025-07-25T18:02:52.823959Z

e.g.:

(babashka.deps/clojure "-X:foo:bar" {:arg 1})

Ryan Tate 2025-07-25T18:04:07.409659Z

Ah thanks, I had a vague memory there was a facility for this, I could not remember what it was and spent some time looking throug the docs but couldn't track it down.

borkdude 2025-07-25T18:04:25.049459Z

but shelling out is also a fine option. in bb.edn you can do that using (shell "clojure" ...) which is the same as babashka.process/shell

Ryan Tate 2025-07-25T18:05:29.516329Z

OK cool, i'll see if tasks can be a good fit first though that sounds good

seancorfield 2025-07-25T18:16:50.808669Z

Just to clarify: does that clojure function run in-process or does it shell out to deps.clj or to the (JVM) CLI?

borkdude 2025-07-25T18:18:21.984249Z

it runs deps.clj in process

seancorfield 2025-07-25T18:19:40.699029Z

Thanks. I'd seen in CI where bb logged that Clojure tools wasn't in the expected place (so it downloads it) when I used clojure but not when I used shell "clojure" so I wanted to double-check.

borkdude 2025-07-25T18:20:06.892289Z

yeah, indeed

seancorfield 2025-07-25T18:20:12.577569Z

Is there much reason to prefer one over the other? (in a CI context specifically)

borkdude 2025-07-25T18:21:52.136739Z

there was a period of time in which shelling out to clojure was very OS-specific and sometimes error-prone, the deps.clj built-in thing was solving that problem. also deps.clj is there anyway for dependencies in bb.edn. but if you want to call out to a specific version of clojure on your system, that's fine too. no strong preference

borkdude 2025-07-25T18:23:33.430749Z

perhaps the github action can be improved by downloading the tools jar as part of the github action installation process when bb is selected

seancorfield 2025-07-25T18:23:41.856199Z

I tend to keep cli: updated and currently setup bb: 'latest' so there wouldn't be much difference. I guess just a minor performance penalty for shelling out to clojure?

borkdude 2025-07-25T18:23:45.885679Z

that would likely be an improvement wrt/ caching too

seancorfield 2025-07-25T18:24:08.473089Z

Aye, I added .deps.clj (I think) to my GHA caches.

👍 1
borkdude 2025-07-25T18:24:40.044949Z

~/.deps.clj right

👍🏻 1
escherize 2025-07-25T20:47:27.633979Z

If you can run the tasks from a running clojure server with a repl running, you can send code into the jvm clojure repl from babashka. we have a https://github.com/metabase/metabase/blob/master/bb.edn#L173-L192 for this. -n optional:

$ bb -repl -n a.namespace '(do-stuff)'

escherize 2025-07-25T21:00:43.457169Z

help for it printed below if that helps.

Task Name: -repl
 Eval a string of clojure code in the backend dev server
Usages:
  -n, --namespace NAMESPACE  Namespace to use for the task
  -p, --port PORT            Port to use for the task, defaults to value in .nrepl-port

Examples:

 bb -repl '(+ 1 1)'
 - Eval a form in the backend dev server in the user namespace

 bb -repl --namespace metabase.app-db.connection @application-db-counter
 - Eval a form in the backend dev server in the 'metabase.app-db.connection' namespace

 bb -repl --port 59498 --namespace metabase.app-db.connection '(read-string "::hello")'
 - Evaluate a keyword inside a namespace

borkdude 2025-07-25T21:19:33.463949Z

There's also a small lib here to do a similar thing: https://github.com/babashka/nrepl-client but not sure if that's the goal of the OP

🙌 1
escherize 2025-07-25T21:20:28.266419Z

I think I took the code snippet from the babashka book. I added stdout and stderr capture and some other goodies, for claude to use, before there was clojure-mcp 😅