Fetch.Conn (Fetch v0.1.0)
View SourceOne HTTP/1.1 connection to one origin, reused for many requests (keep-alive).
{:ok, conn} = Fetch.Conn.new("https://example.com")
{:ok, conn, first} = Fetch.Conn.request(conn, :get, "/")
{:ok, conn, second} = Fetch.Conn.request(conn, :get, "/other")
conn = Fetch.Conn.close(conn)A connection is a value, not a process. Every request returns the updated connection, because a request can change it: the server may ask to close it, or a failure may leave it unusable. Always continue with the returned one.
Lifecycle
new ──► request ──► request ──► ... ──► close
│
├─ not connected, or the idle socket was closed by the server
│ → connect: DNS → TCP → TLS
├─ send the request, read the response
└─ keep the socket if the response allows it, close it otherwiseAn HTTP/1.1 connection stays open after a response unless (RFC 9112 §9.3):
- the response says
connection: close - the response is HTTP/1.0
- the body was delimited by closing the connection
- the server sent more bytes than the response contains
- anything went wrong while sending or receiving
Servers close idle connections whenever they like. Before reusing one, the
client checks, without waiting, whether the server closed it (or sent
something on its own, like 408 Request Timeout) and reconnects if so. That
is safe because nothing has been sent yet. A connection that breaks after
the request was sent is an error, not a retry: the server may already have
acted on the request.
The socket belongs to the process that connected it and is closed when that process exits. Use a connection from one process.
Options
new/2 takes the connection options of Fetch: :connect_timeout,
:receive_timeout, :max_body_size and :ssl.
request/4 takes:
:headers— list of{name, value}tuples. Default[].:body— request body as iodata. Defaultnil.:keep_alive—falsesendsconnection: closeand closes the connection after the response. Defaulttrue.
Redirects are not followed: a connection belongs to one origin.
Summary
Functions
Closes the socket, if any. The connection can still be used: the next request reconnects.
Creates a connection to the origin (scheme, host, port) of url; the path is
ignored. Nothing happens on the network until the first request.
Sends a request for path (like "/users?page=2") and reads the response.
Types
@type t() :: %Fetch.Conn{ opts: keyword(), transport: Fetch.Transport.t() | nil, url: Fetch.URL.t() }
Functions
Closes the socket, if any. The connection can still be used: the next request reconnects.
@spec new( String.t() | Fetch.URL.t(), keyword() ) :: {:ok, t()} | {:error, {:url, term()}}
Creates a connection to the origin (scheme, host, port) of url; the path is
ignored. Nothing happens on the network until the first request.
@spec request(t(), Fetch.Request.method(), String.t(), keyword()) :: {:ok, t(), Fetch.Response.t()} | {:error, t(), {atom(), term()}}
Sends a request for path (like "/users?page=2") and reads the response.
Returns the connection to use next together with the response or the error.
Errors are the same {stage, reason} as in Fetch, plus
{:url, {:invalid_path, path}}.