Fetch (Fetch v0.1.0)

View Source

A small just-for-fun HTTP/1.1 client written in plain Elixir/OTP.

{:ok, response} = Fetch.get("https://example.com")
response.status
#=> 200

Every call opens a new connection, sends one request with connection: close, reads the response and closes the connection:

URL → DNS → TCP → (TLS) → request → response head → body → close

To send several requests over one connection (keep-alive), use Fetch.Conn.

Options

  • :headers — list of {name, value} tuples. Default [].
  • :body — request body as iodata. Default nil.
  • :connect_timeout — ms, applied to each of DNS lookup, TCP connect and TLS handshake. Default 5_000.
  • :receive_timeout — ms, the longest the server may stay silent while we wait for bytes (and while a send is blocked). Default 15_000.
  • :max_body_size — bytes. Larger responses fail with {:recv, :body_too_large}. Default 16 MiB.
  • :ssl — extra :ssl client options merged over the secure defaults, e.g. cacerts: [der] for a private CA.
  • :follow_redirects — follow 301, 302, 303, 307 and 308 responses, see Fetch.Redirect. Default true.
  • :max_redirects — redirects to follow before failing with {:redirect, :too_many_redirects}. Default 10.

Errors

All errors are {:error, {stage, reason}}, where stage is one of :url, :request, :dns, :connect, :tls, :send, :recv, :parse, :redirect. Timeouts are {stage, :timeout}.

Invalid options or an unsupported method raise ArgumentError: those are bugs in the calling code, not runtime conditions.

Summary

Functions

Sends a DELETE request. See request/3.

Sends a GET request. See request/3.

Sends a HEAD request. The response body is always empty. See request/3.

Sends a PATCH request. See request/3.

Sends a POST request. See request/3.

Sends a PUT request. See request/3.

Sends a request and returns the whole response.

Types

error()

@type error() :: {:error, {error_stage(), term()}}

error_stage()

@type error_stage() ::
  :url | :request | :dns | :connect | :tls | :send | :recv | :parse | :redirect

Functions

delete(url, opts \\ [])

@spec delete(
  String.t(),
  keyword()
) :: {:ok, Fetch.Response.t()} | error()

Sends a DELETE request. See request/3.

get(url, opts \\ [])

@spec get(
  String.t(),
  keyword()
) :: {:ok, Fetch.Response.t()} | error()

Sends a GET request. See request/3.

head(url, opts \\ [])

@spec head(
  String.t(),
  keyword()
) :: {:ok, Fetch.Response.t()} | error()

Sends a HEAD request. The response body is always empty. See request/3.

patch(url, opts \\ [])

@spec patch(
  String.t(),
  keyword()
) :: {:ok, Fetch.Response.t()} | error()

Sends a PATCH request. See request/3.

post(url, opts \\ [])

@spec post(
  String.t(),
  keyword()
) :: {:ok, Fetch.Response.t()} | error()

Sends a POST request. See request/3.

put(url, opts \\ [])

@spec put(
  String.t(),
  keyword()
) :: {:ok, Fetch.Response.t()} | error()

Sends a PUT request. See request/3.

request(method, url, opts \\ [])

@spec request(Fetch.Request.method(), String.t(), keyword()) ::
  {:ok, Fetch.Response.t()} | error()

Sends a request and returns the whole response.

Fetch.request(:post, "http://localhost:4000/users",
  headers: [{"content-type", "application/json"}],
  body: ~s({"name":"Jon Snow"})
)

Any HTTP status is {:ok, response} — a 404 is a valid response, not an error. Redirects are followed unless follow_redirects: false; the response is the one from the last request. See the module docs for options and errors.