Back to skills
SKILL.md
Clojure Babashka Http Client
ASecurityHTTP client for Clojure and Babashka built on java.net.http. Use when making HTTP requests, working with REST APIs, downloading files, or needing WebSocket support in Babashka or Clojure.
- 666 stars
- 0 votes
- 0 copies
- 3 views
- Added February 8, 2026
Works with
Security analysis
100/100npx -y skills add majiayu000/claude-skill-registry --skill clojure-babashka-http-client --agent claude-codeAre you the author of Clojure Babashka Http Client?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/majiayu000-clojure-babashka-http-client)---
name: clojure-babashka-http-client
description: HTTP client for Clojure and Babashka built on java.net.http. Use when making HTTP requests, working with REST APIs, downloading files, or needing WebSocket support in Babashka or Clojure.
---
# babashka.http-client
An HTTP client for Clojure and Babashka built on java.net.http. Drop-in replacement for babashka.curl with better streaming support and no external dependencies.
Built-in to Babashka as of version 1.1.171. Supports Clojure 1.10+.
## Setup
deps.edn:
```clojure
org.babashka/http-client {:mvn/version "0.4.22"}
```
bb.edn:
```clojure
org.babashka/http-client {:mvn/version "0.4.22"}
```
See https://clojars.org/org.babashka/http-client for the latest version.
Note: Built-in to Babashka 1.1.171+, no dependency needed.
## Quick Start
```clojure
(require '[babashka.http-client :as http])
;; Simple GET
(http/get "https://httpstat.us/200")
;; => {:status 200, :body "200 OK", :headers {...}}
;; With headers and query params
(http/get "https://postman-echo.com/get"
{:headers {"Accept" "application/json"}
:query-params {"q" "clojure"}})
;; POST with JSON body
(http/post "https://postman-echo.com/post"
{:headers {:content-type "application/json"}
:body (json/encode {:a 1 :b "2"})})
```
## Core Usage Patterns
### GET Requests
Simple GET:
```clojure
(http/get "https://api.example.com/users")
```
With headers:
```clojure
(http/get "https://api.example.com/users"
{:headers {"Authorization" "Bearer token"
:accept "application/json"}})
```
Query parameters:
```clojure
(http/get "https://api.example.com/search"
{:query-params {:q "clojure" :limit 10}})
;; Multiple values for same key
(http/get "https://api.example.com/filter"
{:query-params {:tags ["clojure" "http"]}})
```
### POST Requests
JSON body:
```clojure
(http/post "https://api.example.com/users"
{:headers {:content-type "application/json"}
:body (json/encode {:name "Alice" :email "alice@example.com"})})
```
Form parameters:
```clojure
(http/post "https://api.example.com/login"
{:form-params {"username" "alice" "password" "secret"}})
```
File upload:
```clojure
(require '[clojure.java.io :as io])
(http/post "https://api.example.com/upload"
{:body (io/file "README.md")})
;; Or stream
(http/post "https://api.example.com/upload"
{:body (io/input-stream "README.md")})
```
### Authentication
Basic auth:
```clojure
(http/get "https://api.example.com/private"
{:basic-auth ["username" "password"]})
```
Bearer token:
```clojure
(http/get "https://api.example.com/private"
{:oauth-token "your-token-here"})
```
### Response Handling
String body (default):
```clojure
(:body (http/get "https://example.com"))
```
Stream for large files:
```clojure
(io/copy
(:body (http/get "https://example.com/large-file.zip" {:as :stream}))
(io/file "downloaded.zip"))
```
Binary data:
```clojure
(http/get "https://example.com/image.png" {:as :bytes})
```
### Error Handling
By default, throws on non-2xx/3xx status codes:
```clojure
(try
(http/get "https://httpstat.us/404")
(catch Exception e
(let [data (ex-data e)]
(println "Status:" (:status data)))))
```
Opt out of throwing:
```clojure
(let [resp (http/get "https://httpstat.us/404" {:throw false})]
(if (= 404 (:status resp))
(println "Not found")
(println "Success")))
```
### Multipart Uploads
```clojure
(http/post "https://api.example.com/upload"
{:multipart
[{:name "title" :content "My Document"}
{:name "file"
:content (io/file "document.pdf")
:file-name "doc.pdf"
:content-type "application/pdf"}]})
```
### Custom Client
For advanced configuration (SSL, timeouts, redirects):
```clojure
;; Start with defaults
(def client
(http/client
(assoc-in http/default-client-opts
[:ssl-context :insecure] true)))
;; Use custom client
(http/get "https://untrusted-cert.example.com" {:client client})
```
Disable redirects:
```clojure
(def no-redirect-client
(http/client {:follow-redirects :never}))
(http/get "https://httpstat.us/302" {:client no-redirect-client})
```
### Compression
Request compressed responses:
```clojure
(http/get "https://api.stackexchange.com/2.2/sites"
{:headers {"Accept-Encoding" ["gzip" "deflate"]}})
```
Response is automatically decompressed.
### Async Requests
Returns CompletableFuture:
```clojure
(def resp-future (http/get "https://example.com" {:async true}))
;; Block for result
@resp-future
;; With timeout
(deref resp-future 5000 ::timeout)
;; Callbacks
(http/get "https://example.com"
{:async true
:async-then (fn [resp] (println "Success:" (:status resp)))
:async-catch (fn [e] (println "Error:" (.getMessage e)))})
```
### Timeouts
Connection timeout (on client):
```clojure
(def client (http/client {:connect-timeout 5000})) ; 5 seconds
(http/get "https://example.com" {:client client})
```
Request timeout:
```clojure
(http/get "https://example.com" {:timeout 10000}) ; 10 seconds
```
### URI Construction
Safe URI building from components:
```clojure
(http/request
{:uri {:scheme "https"
:host "api.example.com"
:port 443
:path "/v1/users"
:query "active=true&limit=10"}})
```
### WebSockets
```clojure
(require '[babashka.http-client.websocket :as ws])
(def socket
(ws/websocket
{:uri "wss://echo.websocket.org"
:on-open (fn [ws] (ws/send! ws "Hello"))
:on-message (fn [ws data last] (println "Received:" data))
:on-close (fn [ws status reason] (println "Closed"))
:on-error (fn [ws err] (println "Error:" err))}))
;; Send message
(ws/send! socket "Hello WebSocket")
;; Close
(ws/close! socket)
```
## Key Gotchas
1. Throws on non-2xx/3xx by default - Use {:throw false} if you want to handle errors manually.
2. Streaming vs buffering - Default response body is a string (buffered in memory). Use {:as :stream} for large files to avoid OOM.
3. Built-in to Babashka - Don't add as dependency in bb.edn if using Babashka 1.1.171+.
4. Headers can be strings or keywords - Both work: {"Content-Type" "..."} and {:content-type "..."}.
5. CompletableFuture with :async - Use deref/@, not blocking waits. Add timeout to deref to avoid hanging.
6. Custom client is reusable - Create once, reuse for many requests. Don't create new client per request.
7. DNS lookup is synchronous - Even with :async true, initial DNS lookup blocks. Cache results for repeated requests to same host.
## Advanced: Interceptors
Interceptors transform requests/responses. Similar to Ring middleware.
Custom JSON interceptor:
```clojure
(require '[babashka.http-client.interceptors :as interceptors])
(def json-interceptor
{:name ::json
:request (fn [req]
(if (= :json (:as req))
(-> req
(assoc-in [:headers :accept] "application/json")
(assoc :as :string ::json true))
req))
:response (fn [resp]
(if (get-in resp [:request ::json])
(update resp :body json/parse-string)
resp))})
(def my-interceptors
(cons json-interceptor interceptors/default-interceptors))
(http/get "https://api.example.com/data"
{:interceptors my-interceptors
:as :json})
```
Modify existing interceptor:
```clojure
;; Don't throw on 404
(def unexceptional-statuses
(conj #{200 201 202 203 204 205 206 207 300 301 302 303 304 307} 404))
(def my-throw-interceptor
{:name ::throw-on-exceptional-status-code
:response (fn [resp]
(if (or (false? (some-> resp :request :throw))
(contains? unexceptional-statuses (:status resp)))
resp
(throw (ex-info (str "Exceptional status: " (:status resp)) resp))))})
(def my-interceptors
(mapv #(if (= ::interceptors/throw-on-exceptional-status-code (:name %))
my-throw-interceptor
%)
interceptors/default-interceptors))
```
## References
- [API Reference](references/API.md) - Complete API documentation
- [GitHub](https://github.com/babashka/http-client)
- [Babashka Book](https://book.babashka.org/#babashkahttp_client)
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.