An idiomatic clojure http client wrapping the apache client. Offically supported version.
Pull request Compare This branch is 801 commits behind dakrone:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


A Clojure HTTP library wrapping the Apache HttpComponents client.

This library has taken over from mmcgrana's clj-http. Please send a pull request or open an issue if you have any problems

Continuous Integration status


clj-http is available as a Maven artifact from Clojars:

[clj-http "0.3.2"]

Previous versions available as

[clj-http "0.3.1"]
[clj-http "0.3.0"]
[clj-http "0.2.7"]


The main HTTP client functionality is provided by the clj-http.client namespace:

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

The client supports simple get, head, put, post, and delete requests. Responses are returned as Ring-style response maps:

(client/get "")
=> {:status 200
    :headers {"date" "Sun, 01 Aug 2010 07:03:49 GMT"
              "cache-control" "private, max-age=0"
              "content-type" "text/html; charset=ISO-8859-1"
    :body "<!doctype html>..."
    :trace-redirects ["" "" ""]}

:trace-redirects will contain the chain of the redirections followed.

More example requests:

(client/get "")

(client/get "" {:accept :json})

;; Various options:
(client/post ""
  {:basic-auth ["user" "pass"]
   :body "{\"json\": \"input\"}"
   :headers {"X-Api-Version" "2"}
   :content-type :json
   :socket-timeout 1000
   :conn-timeout 1000
   :accept :json})

;; Need to contact a server with an untrusted SSL cert?
(client/get "" {:insecure? true})

;; If you don't want to follow-redirects automatically:
(client/get "http://site.come/redirects-somewhere" {:follow-redirects false})

;; Only follow a certain number of redirects:
(client/get "http://site.come/redirects-somewhere" {:max-redirects 5})

;; Throw an exception if redirected too many times:
(client/get "http://site.come/redirects-somewhere" {:max-redirects 5 :throw-exceptions true})

;; Send form params as a urlencoded body
(client/post "http//" {:form-params {:foo "bar"}})

;; Multipart form uploads/posts
;; a map or vector works as the multipart object. Use a vector of
;; vectors if you need to preserve order, a map otherwise.
(client/post "http//" {:multipart [["title" "My Awesome Picture"]
                                              ["Content/type" "image/jpeg"]
                                              ["file" ( "pic.jpg")]]})
;; Multipart values can be one of the following:
;; String, InputStream, File, or a byte-array

;; Basic authentication
(client/get "" {:basic-auth ["user" "pass"]})
(client/get "" {:basic-auth "user:pass"})

;; Query parameters
(client/get "" {:query-params {"q" "foo, bar"}})

The client will also follow redirects on the appropriate 30* status codes.

The client transparently accepts and decompresses the gzip and deflate content encodings.

Input coercion

;; body as a byte-array
(client/post "" {:body my-byte-array})

;; body as a string
(client/post "" {:body "string"})

;; :body-encoding is optional and defaults to "UTF-8"
(client/post ""
             {:body "string" :body-encoding "UTF-8"})

;; body as a file
(client/post ""
             {:body ( "/tmp/foo") :body-encoding

;; :length is NOT optional for passing an InputStream in
(client/post ""
             {:body ( "/tmp/foo")
              :length 1000})

Output coercion

;; The default output is a string body
(client/get "")

;; Coerce as a byte-array
(client/get "" {:as :byte-array})

;; Coerce as something other than UTF-8 string
(client/get "" {:as "UTF-16"})

;; Coerce as json
(client/get "" {:as :json})
(client/get "" {:as :json-string-keys})

;; Try to automatically coerce the output based on the content-type
;; header (this is currently a BETA feature!)
(client/get "" {:as :auto})

;; Return the body as a stream
(client/get "" {:as :stream})
;; Note that the connection to the server will NOT be closed until the
;; stream has been read

A more general request function is also available, which is useful as a primitive for building higher-level interfaces:

(defn api-action [method path & [opts]]
    (merge {:method method :url (str "" path)} opts)))


The client will throw exceptions on, well, exceptional status codes. clj-http will throw a Slingshot Stone that can be caught by a regular (catch Exception e ...) or in Slingshot's try+ block:

(client/get "")
=> Stone Object thrown by throw+: {:status 404, :headers {"server" "nginx/1.0.4",
                                                          "x-runtime" "12ms",
                                                          "content-encoding" "gzip",
                                                          "content-type" "text/html; charset=utf-8",
                                                          "date" "Mon, 17 Oct 2011 23:15 :36 GMT",
                                                          "cache-control" "no-cache",
                                                          "status" "404 Not Found",
                                                          "transfer-encoding" "chunked",
                                                          "connection" "close"},
                                   :body "...body here..."}
   clj-http.client/wrap-exceptions/fn--227 (client.clj:37)

;; You can also ignore exceptions and handle them yourself:
(client/get "" {:throw-exceptions false})
;; Or ignore an unknown host (methods return 'nil' if this is set to
;; true and the host does not exist:
(client/get "" {:ignore-unknown-host? true})

(spacing added by me to be human readable)


A proxy can be specified by setting the Java properties: <scheme>.proxyHost and <scheme>.proxyPort where <scheme> is the client scheme used (normally 'http' or 'https'). Additionally, per-request proxies can be specified with the proxy-host and proxy-port options:

(client/get "" {:proxy-host "" :proxy-port 8118})

Using persistent connections

clj-http can use persistent connections to speed up connections if multiple connections are being used:

(with-connection-pool {:timeout 5 :threads 4 :insecure? false}
  (get "")
  (post "")
  (get "")
  (get ""))

This is MUCH faster than sequentially performing all requests, because a persistent connection can be used instead creating a new connection for each request.

This feature is fairly new, please let me know if you have any feedback!

Faking clj-http responses

If you need to fake clj-http responses (for things like testing and such), check out the clj-http-fake library.


The design of clj-http is inspired by the Ring protocol for Clojure HTTP server applications.

The client in clj-http.core makes HTTP requests according to a given Ring request map and returns Ring response maps corresponding to the resulting HTTP response. The function clj-http.client/request uses Ring-style middleware to layer functionality over the core HTTP request/response implementation. Methods like clj-http.client/get are sugar over this clj-http.client/request function.


Like clj-http but need something more lightweight without as many external dependencies? Check out clj-http-lite for a project that can be used as a drop-in replacement for clj-http.


To run the tests:

$ lein deps
$ lein test

Run all tests (including integration):
$ lein test :all

Run tests against 1.2.1, 1.3 and 1.4
$ lein multi deps
$ lein multi test
$ lein multi test :all


Released under the MIT License: