HTTP Gun

HTTP Gun is a Gleam HTTP client for Erlang/OTP applications. One client gives you a reusable connection pool, collected or streamed byte responses, explicit resource limits, and offline playback. Your application decides what a status or response body means.

Capabilities

When to use it

Use HTTP Gun for ordinary API calls in a supervised Erlang application, for reading large responses a chunk at a time, or for tests that need deterministic offline responses and recorded exchanges. It is a transport client: provider adapters still own authentication, status and content interpretation, retries, protocol framing such as SSE, and reconciliation of external effects.

Install

HTTP Gun requires Gleam 1.18 or newer on the Erlang target. Add it from Hex:

gleam add http_gun

Commit the application’s gleam.toml and manifest.toml to retain the resolved versions.

Send a request

This excerpt uses server, local_request, and local_config from the complete ordinary consumer. That consumer starts a local fixture and explicitly permits loopback access.

let req = local_request(server())
// The common path: start a client, send, read the collected response, stop.
let assert Ok(client) = http_gun.start(local_config())
let assert Ok(reply) = http_gun.send(client, req)
let assert 200 = reply.response.status
let assert <<"abc":utf8>> = reply.response.body
http_gun.stop(client)

send collects the response body up to its configured limit. Statuses such as 404 and 500 are still response data. For a streaming response, scope body cleanup with with_response and read chunks using body.next:

let assert Ok(3) = {
  use response <- http_gun.with_response(stream, req, fn(failure) { failure })
  count(response.body, 0)
}

The consumer source includes the count helper and runs this example against a local server.

Runtime ownership

Each client has a pool process that admits requests and assigns connection capacity. Each response has a body owner that coordinates the HTTP exchange; only the process that opened a body may read it. Gun handles HTTP wire protocols. An optional recorder captures exchanges, and lifecycle events go to Sinal handlers.

flowchart LR
  caller[Calling process] -->|send / open / batch| pool[Client pool process]
  pool -->|admit and lease| body[Body owner]
  body -->|requests and cancellation| gun[Gun connections]
  gun -->|response events| body
  caller -->|next / close| body
  pool -. lifecycle events .-> sinal[Sinal handlers]
  body -. lifecycle events .-> sinal
  body -. optional capture .-> recorder[Recorder]

Operational limits

Examples and reference

The ordinary consumer runs the public API examples. See the async feed recipe for application owned jobs and sinks, and the mTLS consumer for client identity setup and rotation. The public API, design, and coverage map describe the package contracts. Benchmark notes report retained local workload measurements; they predate this checkout and make no performance promise.

The changelog records releases and additions to public error variants.

✨ Search Document