clj-http icon indicating copy to clipboard operation
clj-http copied to clipboard

An idiomatic clojure http client wrapping the apache client. Officially supported version.

#+TITLE: clj-http documentation #+AUTHOR: Lee Hinman #+STARTUP: align fold nodlcheck lognotestate showall #+OPTIONS: H:4 num:nil toc:t \n:nil @:t ::t |:t ^:{} -:t f:t *:t #+OPTIONS: skip:nil d:(HIDE) tags:not-in-toc auto-id:t #+PROPERTY: header-args :results code :exports both :noweb yes #+HTML_HEAD: #+LANGUAGE: en

[[https://clojars.org/clj-http][file:https://img.shields.io/clojars/v/clj-http.svg]] [[https://github.com/dakrone/clj-http/actions?query=workflow%3A%22Clojure+CI%22][file:https://github.com/dakrone/clj-http/workflows/Clojure%20CI/badge.svg]] [[https://gitter.im/clj-http/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge][file:https://badges.gitter.im/clj-http/Lobby.svg]]

  • Table of Contents :TOC_3: :PROPERTIES: :CUSTOM_ID: h-aaf075ea-2f0e-4a45-871a-0f89c838fb4b :END:
  • [[#branches][Branches]]
  • [[#introduction][Introduction]]
    • [[#overview][Overview]]
    • [[#philosophy][Philosophy]]
  • [[#installation][Installation]]
  • [[#quickstart][Quickstart]]
    • [[#head][HEAD]]
    • [[#get][GET]]
    • [[#put][PUT]]
    • [[#post][POST]]
    • [[#delete][DELETE]]
    • [[#async-http-request][Async HTTP Request]]
      • [[#cancelling-requests][Cancelling Requests]]
    • [[#coercions][Coercions]]
      • [[#input-coercion][Input coercion]]
      • [[#output-coercion][Output coercion]]
    • [[#headers][Headers]]
    • [[#query-string-parameters][Query-string parameters]]
    • [[#meta-tag-headers][Meta Tag Headers]]
    • [[#link-headers][Link Headers]]
    • [[#redirects][Redirects]]
      • [[#how-to-create-a-custom-redirectstrategy][How to create a custom RedirectStrategy]]
    • [[#cookies][Cookies]]
      • [[#cookiestores][Cookiestores]]
      • [[#keystores-trust-stores][Keystores, Trust-stores]]
    • [[#exceptions][Exceptions]]
    • [[#decompression][Decompression]]
    • [[#debugging][Debugging]]
      • [[#logging][Logging]]
  • [[#caching][Caching]]
  • [[#authentication][Authentication]]
    • [[#basic-auth][Basic Auth]]
    • [[#digest-auth][Digest Auth]]
    • [[#ntlm-auth][NTLM Auth]]
    • [[#oauth2][oAuth2]]
  • [[#advanced-usage][Advanced Usage]]
    • [[#raw-request][Raw Request]]
      • [[#boolean-options][Boolean options]]
    • [[#persistent-connections][Persistent Connections]]
    • [[#re-using-httpclient-between-requests][Re-using =HttpClient= between requests]]
    • [[#proxies][Proxies]]
    • [[#custom-middleware][Custom Middleware]]
    • [[#modifying-apache-specific-features-of-the-httpclientbuilder-and-httpasyncclientbuilder][Modifying Apache-specific features of the =HttpClientBuilder= and =HttpAsyncClientBuilder=]]
    • [[#incrementally-json-parsing][Incrementally JSON Parsing]]
    • [[#dns-resolution][DNS Resolution]]
  • [[#development][Development]]
    • [[#faking-responses][Faking Responses]]
    • [[#optional-dependencies][Optional Dependencies]]
    • [[#clj-http-lite][clj-http-lite]]
    • [[#troubleshooting][Troubleshooting]]
      • [[#verifyerror-class-orgcodehausjacksonsmilesmileparser-overrides-final-method-getbinaryvalue][VerifyError class org.codehaus.jackson.smile.SmileParser overrides final method getBinaryValue...]]
      • [[#nohttpresponseexception--due-to-stale-connections][NoHttpResponseException ... due to stale connections**]]
  • [[#tests][Tests]]
  • [[#testimonials][Testimonials]]
  • [[#other-libraries-providing-middleware][Other Libraries Providing Middleware]]
  • [[#license][License]]
  • Branches :PROPERTIES: :CUSTOM_ID: h-e390585c-cbd8-4e94-b36b-4e9c27c16720 :END:

There are branches for the major version numbers:

  • 2.x (no longer maintained except for security issues)
  • 3.x (current stable releases and the main Github branch)
  • master (which is 4.x, unreleased, based on version 5 of the apache http client)
  • Introduction :PROPERTIES: :CUSTOM_ID: h-d893078a-b20b-4086-9272-3d9c28c86846 :END:

** Overview :PROPERTIES: :CUSTOM_ID: h-d8b17d06-124e-44fd-9c86-0399f39b0254 :END:

clj-http is an HTTP library wrapping the [[http://hc.apache.org/][Apache HttpComponents]] client. This library has taken over from mmcgrana's clj-http.

** Philosophy :PROPERTIES: :CUSTOM_ID: h-aa21d07d-333b-4ff2-93a9-ffdca31d8949 :END:

The design of =clj-http= is inspired by the [[https://github.com/ring-clojure/ring][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 [[https://github.com/ring-clojure/ring/blob/master/SPEC][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.

  • Installation :PROPERTIES: :CUSTOM_ID: h-ddfce0e2-6797-4774-add5-d5cf5bfaaa17 :END:

=clj-http= is available as a Maven artifact from [[http://clojars.org/clj-http][Clojars]].

With Leiningen/Boot:

#+BEGIN_SRC clojure [clj-http "3.12.3"] #+END_SRC

If you need an older version, a 2.x release is also available.

#+BEGIN_SRC clojure [clj-http "2.3.0"] #+END_SRC

clj-http 3.x supports clojure 1.6.0 and higher. clj-http 4.x will support clojure 1.7.0 and higher.

  • Quickstart :PROPERTIES: :CUSTOM_ID: h-65f0132e-1f96-4711-a84e-973817f37dd3 :END:

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

First, require it in the REPL:

#+BEGIN_SRC clojure (require '[clj-http.client :as client]) #+END_SRC

Or in your application:

#+BEGIN_SRC clojure (ns my-app.core (:require [clj-http.client :as client])) #+END_SRC

The client supports simple =get=, =head=, =put=, =post=, =delete=, =copy=, =move=, =patch=, and =options= requests. Response are returned as [[https://github.com/ring-clojure/ring/blob/master/SPEC][Ring-style response maps]]:

** HEAD :PROPERTIES: :CUSTOM_ID: h-79d1bb5f-c695-46a6-af4e-a64ca599c978 :END:

#+BEGIN_SRC clojure

(client/head "http://example.com/resource")

(client/head "http://example.com/resource" {:accept :json})

#+END_SRC

** GET :PROPERTIES: :CUSTOM_ID: h-89c164fb-85c2-4953-a8c4-a50867adf42a :END:

Example requests:

#+BEGIN_SRC clojure

(client/get "http://example.com/resources/id")

;; Setting options (client/get "http://example.com/resources/3" {:accept :json}) (client/get "http://example.com/resources/3" {:accept :json :query-params {"q" "foo, bar"}})

;; Specifying headers as either a string or collection: (client/get "http://example.com" {:headers {"foo" ["bar" "baz"], "eggplant" "quux"}})

;; Using either string or keyword header names: (client/get "http://example.com" {:headers {:foo ["bar" "baz"], :eggplant "quux"}})

;; Completely ignore cookies: (client/post "http://example.com" {:cookie-policy :none}) ;; There are also multiple ways to handle cookies (client/post "http://example.com" {:cookie-policy :default}) (client/post "http://example.com" {:cookie-policy :netscape}) (client/post "http://example.com" {:cookie-policy :standard}) (client/post "http://example.com" {:cookie-policy :standard-strict})

;; Cookies can be completely configurable with a custom spec by adding a ;; function to return a cookie spec for parsing the cookie. For example, if you ;; wanted to configure a spec provider to have a certain compatibility level: (client/post "http://example.com" {:cookie-spec (fn [http-context] (println "generating a new cookie spec") (.create (org.apache.http.impl.cookie.RFC6265CookieSpecProvider. org.apache.http.impl.cookie.RFC6265CookieSpecProvider$CompatibilityLevel/IE_MEDIUM_SECURITY (PublicSuffixMatcherLoader/getDefault)) http-context))}) ;; Or a version with relaxed compatibility (client/post "http://example.com" {:cookie-spec (fn [http-context] (println "generating a new cookie spec") (.create (org.apache.http.impl.cookie.RFC6265CookieSpecProvider. org.apache.http.impl.cookie.RFC6265CookieSpecProvider$CompatibilityLevel/RELAXED (PublicSuffixMatcherLoader/getDefault)) http-context))})

;; Sometimes you want to do your own validation or something, which you can do ;; by proxying the CookieSpecBase. Note that this doesn't actually return the ;; cookies, because clj-http does its own cookie parsing. If you want to store ;; the cookies from these methods you'll need to use a cookie store or put it in ;; some datastructure yourself. (client/post "http://example.com" {:cookie-spec (fn [http-context] (proxy [org.apache.http.impl.cookie.CookieSpecBase] [] ;; Version and version header (getVersion [] 0) (getVersionHeader [] nil) ;; parse headers into cookie objects (parse [header cookie-origin] (java.util.ArrayList.)) ;; Validate a cookie, throwing MalformedCookieException if the ;; cookies isn't valid (validate [cookie cookie-origin] (println "validating:" cookie)) ;; Determine if a cookie matches the target location (match [cookie cookie-origin] true) ;; Format a list of cookies into a list of headers (formatCookies [cookies] (java.util.ArrayList.))))})

;; If you have created your own registry for cookie policies, you can provide ;; :cookie-policy-registry to use it. See ;; clj-http.core/create-custom-cookie-policy-registry for an example of a custom ;; registry (client/post "http://example.com" {:cookie-policy-registry my-custom-policy-registry :cookie-policy "my-policy"})

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

;; If you don't want to follow-redirects automatically: (client/get "http://example.com/redirects-somewhere" {:redirect-strategy :none})

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

;; Avoid throwing exceptions if redirected too many times: (client/get "http://example.com/redirects-somewhere" {:max-redirects 5 :redirect-strategy :graceful})

;; Throw an exception if the get takes too long. Timeouts in milliseconds. (client/get "http://example.com/redirects-somewhere" {:socket-timeout 1000 :connection-timeout 1000})

;; Query parameters (client/get "http://example.com/search" {:query-params {"q" "foo, bar"}})

;; "Nested" query parameters ;; (this yields a query string of a[e][f]=6&a[b][c]=5) (client/get "http://example.com/search" {:query-params {:a {:b {:c 5} :e {:f 6}}}})

;; Provide cookies 窶