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
@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"])
@spec default_name() :: atom()
Returns the default supervisor name (Quiver.Pool).
@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")
@spec new(Quiver.Conn.method(), String.t()) :: Quiver.Request.t()
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()
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
:name-- atom identifying theQuiver.Supervisor(default:Quiver.Pool)
Examples
{:ok, %{idle: 8, active: 2, queued: 0}} =
Quiver.pool_stats("https://example.com")
@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
:name-- atom identifying theQuiver.Supervisor(default:Quiver.Pool):receive_timeout-- max ms to wait for the response (default: 15,000)
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)
@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))
@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 theQuiver.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()