SkillAgentSearch skills...

Hato

An HTTP client for Clojure, wrapping JDK 11's HttpClient

Install / Use

/learn @gnarroway/Hato
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

hato

Clojars Project

An HTTP client for Clojure, wrapping JDK 11's HttpClient.

It supports both HTTP/1.1 and HTTP/2, with synchronous and asynchronous execution modes as well as websockets.

In general, it will feel familiar to users of http clients like clj-http. The API is designed to be idiomatic and to make common tasks convenient, whilst still allowing the underlying HttpClient to be configured via native Java objects.

Status

hato has a stable API and is used in production for both synchronous and asynchronous use cases. Please try it out and raise any issues you may find.

Installation

hato requires JDK 11 and above. If you are running an older version of Java, please look at clj-http.

For Leiningen, add this to your project.clj

[hato "1.0.0"]

Quickstart

The main client is available in hato.client.

Require it to get started and make a request:


(ns my.app
  (:require [hato.client :as hc]))

  (hc/get "https://httpbin.org/get")
  ; =>
  ; {:request-time 112
  ;  :status 200
  ;  :body "{\"url\" ...}"
  ;  ...}

Usage

Building a client

Generally, you want to make a reusable client first. This will give you nice things like persistent connections and connection pooling.

This can be done with build-http-client:

; Build the client
(def c (hc/build-http-client {:connect-timeout 10000
                              :redirect-policy :always}))

; Use it for multiple requests
(hc/get "https://httpbin.org/get" {:http-client c})
(hc/head "https://httpbin.org/head" {:http-client c})

build-http-client options

authenticator Used for non-preemptive basic authentication. See the basic-auth request option for pre-emptive authentication. Accepts:

cookie-handler a java.net.CookieHandler if you need full control of your cookies. See cookie-policy for a more convenient option.

cookie-policy Determines whether to accept cookies. The cookie-handler option will take precedence if it is set. If an invalid option is provided, a CookieManager with the default policy (original-server) will be created. Valid options:

  • :none Accepts no cookies
  • :all Accepts all cookies
  • :original-server (default) Accepts cookies from original server
  • An implementation of java.net.CookiePolicy.

connect-timeout Timeout to making a connection, in milliseconds (default: unlimited).

executor Sets the thread executor.

redirect-policy Sets the redirect policy.

  • :never (default) Never follow redirects.
  • :normal Always redirect, except from HTTPS URLs to HTTP URLs.
  • :always Always redirect

priority an integer between 1 and 256 (both inclusive) for HTTP/2 requests

proxy Sets a proxy selector. If not set, uses the default system-wide ProxySelector, which can be configured by Java opts such as -Dhttp.proxyHost=somehost and -Dhttp.proxyPort=80 (see all options). Also accepts:

  • :no-proxy to explicitly disable the default behavior, implying a direct connection; or
  • a java.net.ProxySelector

ssl-context Sets the SSLContext. If not specified, uses the default (SSLContext/getDefault). Accepts:

  • a map of :keystore :keystore-pass :trust-store :trust-store-pass, :insecure?. See client authentication examples for more details.
  • an javax.net.ssl.SSLContext

ssl-parameters a javax.net.ssl.SSLParameters

version Sets preferred HTTP protocol version.

  • :http-1.1 prefer HTTP/1.1
  • :http-2 (default) tries to upgrade to HTTP/2, falling back to HTTP/1.1

Making requests

The core function for making requests is hato.client/request, which takes a ring request and returns a response. Convenience wrappers are provided for the http verbs (get, post, put etc.).

; The main request function
(hc/request {:method :get, :url "https://httpbin.org/get"})

; Convenience wrappers
(hc/get "https://httpbin.org/get")
(hc/get "https://httpbin.org/get" {:as :json})
(hc/post "https://httpbin.org/post" {:body "{\"a\": 1}" :content-type :json})

request options

methodLowercase keyword corresponding to a HTTP request method, such as :get or :post.

url An absolute url to the requested resource (e.g. "http://moo.com/api/1").

accept Sets the accept header. a keyword (e.g. :json, for any application/* type) or string (e.g. "text/html") for anything else.

accept-encoding List of string/keywords (e.g. [:gzip]). By default, "gzip, deflate" will be concatenated unless decompress-body? is false.

content-type a keyword (e.g. :json, for any application/* type) or string (e.g. "text/html") for anything else. Sets the appropriate header.

body the body of the request. This should be a string, byte array, input stream, or a java.net.http.HttpRequest$BodyPublisher. To send a clojure map as json (or some other format), use the form-params option with the appropriate content-type.

as Return response body in a certain format. Valid options:

  • Return an object type: :string (default), :byte-array, :stream (java.lang.io.InputStream).
  • :auto, to automatically coerce response body based on the response (e.g. content-type). This is an alpha feature and the implementation may change.
  • :lines, will give you back a lazy java.util.Stream<String> (must be closed by the caller). This is very useful for (newline-delimited) server-sent-events (i.e. text/event-stream content-type).
  • Coerce response body with certain format: :json, :json-string-keys, :clojure, :transit+json, :transit+msgpack. JSON and transit coercion require optional dependencies cheshire (5.9.0 or later) and com.cognitect/transit-clj to be installed, respectively.

coerce Determine which status codes to coerce response bodies. :unexceptional (default), :always, :exceptional. This presently only has an effect for json coercions.

query-params A map of options to turn into a query string. See usage examples for details.

form-params A map of options that will be sent as the body, depending on the content-type option. For example, set :content-type :json to coerce the form-params to a json string (requires cheshire). See usage examples for details.

multi-param-style Decides how to represent array values when converting query-params into a query string. Accepts:

  • When unset (default), a repeating parameter a=1&a=2&a=3
  • :array, a repeating param with array suffix: a[]=1&a[]=2&a[]=3
  • :indexed, a repeating param with array suffix and index: a[0]=1&a[1]=2&a[2]=3

multipart A sequence of maps with the following keys:

  • :name The name of the param
  • :part-name To preserve the order of entities, :name will be used as the part name unless :part-name is specified
  • :content The part's data. May be a String, InputStream, Reader, File, char-array, or a byte-array
  • :file-name The part's file name. If the :content is a File, it will use .getName by default but may be overridden.
  • :content-type The part's content type. The value may be a String such as "text/plain; charset=utf-8" or represented as a map such as {:mime-type "text/html"} or {:mime-type "text/plain" :charset "iso-8859-1"}. If left empty, the value will depend on :content. When :content is a String, it will be text/plain; charset=UTF-8 and when :content is a File, it will attempt to guess the best content type or fallback to application/octet-stream.

headers Map of lower case strings to a header value. A header's value may be a string or a sequence of strings when there are multiple values for a given header.

basic-auth Performs basic authentication (sending Basic authorization header). Accepts {:user "user" :pass "pass"} Note that basic auth can also be passed via the url (e.g. http://user:pass@moo.com)

oauth-token String, will set Bearer authorization header

decompress-body? By default, sets request header to accept "gzip, deflate" encoding, and decompresses the response. Set to false to turn off this behaviour.

throw-exceptions? By default, the client will throw exceptions for exceptional response statuses. Set this to false to return the response without throwing.

async? Boolean, defaults to false. See below section on async requests.

http-client An HttpClient created by build-http-client or other means. For single-use clients, it also accepts a map of the options accepted by build-http-client.

expect-continue Requests the server to acknowledge the request before sending the body. This is disabled by default.

timeout Timeout to receiving a response, in milliseconds (default: unlimited).

version Sets preferred HTTP protocol version per request

View on GitHub
GitHub Stars412
CategoryDevelopment
Updated8d ago
Forks28

Languages

Clojure

Security Score

95/100

Audited on Mar 29, 2026

No findings