Quiver (quiver v0.2.0)

Copy Markdown View Source

A mid-level HTTP client for Elixir supporting HTTP/1.1 and HTTP/2.

Usage

# Using the default supervisor name (Quiver.Pool):
children = [{Quiver.Supervisor, pools: %{default: []}}]

{:ok, %Quiver.Response{status: 200, body: body}} =
  Quiver.new(:get, "https://example.com/api")
  |> Quiver.header("authorization", "Bearer token")
  |> Quiver.request()

# Using a custom supervisor name:
children = [{Quiver.Supervisor, name: :my_client, pools: %{default: []}}]

{:ok, %Quiver.Response{status: 200, body: body}} =
  Quiver.new(:get, "https://example.com/api")
  |> Quiver.request(name: :my_client)

Summary

Functions

Sets the request body.

Returns the default supervisor name (Quiver.Pool).

Appends a header to the request.

Creates a new request with the given HTTP method and URL.

Returns pool statistics for the given URL's origin.

Executes the request and returns the full response.

Sets a streaming body on the request.

Executes the request in streaming mode.

Functions

body(request, body)

@spec body(Quiver.Request.t(), iodata()) :: Quiver.Request.t()

Sets the request body.

Accepts any iodata/0 value. Overwrites any previously set body.

Examples

Quiver.new(:post, "https://example.com/api")
|> Quiver.body(~s({"key": "value"}))

Quiver.new(:put, "https://example.com/upload")
|> Quiver.body(["chunk1", "chunk2"])

default_name()

@spec default_name() :: atom()

Returns the default supervisor name (Quiver.Pool).

header(request, key, value)

@spec header(Quiver.Request.t(), String.t(), String.t()) :: Quiver.Request.t()

Appends a header to the request.

Headers are stored as a list of {key, value} tuples. Calling this multiple times with the same key adds duplicate headers (does not replace). Both key and value must be binaries.

Examples

request
|> Quiver.header("authorization", "Bearer token")
|> Quiver.header("accept", "application/json")

new(method, url)

Creates a new request with the given HTTP method and URL.

The URL is parsed into a URI struct and stored on the request. Combine with header/3, body/2, and request/2 to build and execute the full request pipeline.

Examples

Quiver.new(:get, "https://example.com/api/users")

Quiver.new(:post, "https://example.com/api/users")
|> Quiver.header("content-type", "application/json")
|> Quiver.body(~s({"name": "Ada"}))
|> Quiver.request()

pool_stats(url, opts \\ [])

@spec pool_stats(
  String.t(),
  keyword()
) :: {:ok, map()} | {:error, :not_found}

Returns pool statistics for the given URL's origin.

The returned map contains:

  • :idle -- number of idle connections/stream slots
  • :active -- number of in-flight requests
  • :queued -- number of callers waiting for a connection

Returns {:error, :not_found} if no pool exists for the origin yet.

Options

Examples

{:ok, %{idle: 8, active: 2, queued: 0}} =
  Quiver.pool_stats("https://example.com")

request(request, opts \\ [])

@spec request(
  Quiver.Request.t(),
  keyword()
) ::
  {:ok, Quiver.Response.t()} | {:upgrade, Quiver.Upgrade.t()} | {:error, term()}

Executes the request and returns the full response.

The entire response body is buffered in memory. For large responses, consider stream_request/2 instead.

Pools are selected automatically based on the request's origin (scheme + host + port) and the rules configured in Quiver.Supervisor.

Options

Examples

{:ok, %Quiver.Response{status: 200, body: body}} =
  Quiver.new(:get, "https://example.com/api")
  |> Quiver.request()

{:ok, resp} =
  Quiver.new(:get, "https://internal.api/data")
  |> Quiver.request(name: :internal_client, receive_timeout: 30_000)

stream_body(request, enumerable)

@spec stream_body(Quiver.Request.t(), Enumerable.t()) :: Quiver.Request.t()

Sets a streaming body on the request.

Wraps the given enumerable in a {:stream, enumerable} tagged tuple, replacing any previously set body. The enumerable will be consumed lazily when the request is sent.

Examples

Quiver.new(:post, "https://example.com/upload")
|> Quiver.stream_body(Stream.map(chunks, &compress/1))

stream_request(request, opts \\ [])

@spec stream_request(
  Quiver.Request.t(),
  keyword()
) :: {:ok, Quiver.StreamResponse.t()} | {:error, term()}

Executes the request in streaming mode.

Returns a Quiver.StreamResponse with eagerly-received status and headers, and a lazy body stream that yields binary chunks as the caller enumerates it. The underlying pool connection is held for the lifetime of the stream and released when the stream is fully consumed or halted.

Options

  • :name -- atom identifying the Quiver.Supervisor (default: Quiver.Pool)
  • :receive_timeout -- max ms to wait per response chunk (default: 15,000)

Examples

{:ok, %Quiver.StreamResponse{status: 200, body: body_stream}} =
  Quiver.new(:get, "https://example.com/stream/100")
  |> Quiver.stream_request()

body_stream
|> Stream.each(&IO.write/1)
|> Stream.run()