Packages

A protocol-agnostic, zero-buffer suite of Web Standard APIs for Elixir.

Current section

Files

Jump to
web lib web.ex
Raw

lib/web.ex

defmodule Web do
@moduledoc """
A Universal Fetch Library for Elixir.
Matches the Javascript Fetch API standard with zero-buffer streaming and an extensible dispatcher architecture.
## Examples
# Simple HTTP GET
{:ok, response} = Web.fetch("https://api.github.com/zen")
response.body |> Enum.each(&IO.write/1)
# Using a Web.Request struct
req = Web.Request.new("https://example.com")
{:ok, response} = Web.fetch(req)
"""
@doc """
Initiates a network fetch.
Matches the Javascript Fetch API standard.
## Parameters
- `input`: A string representing the URL, OR a pre-constructed `Web.Request` struct.
- `init`: A keyword list of options (ignored if `input` is already a Request struct).
- `:method` (String.t | atom) - HTTP method (default: "GET").
- `:headers` (Map.t | List.t | Web.Headers.t) - Request headers.
- `:body` (any) - Request payload.
- `:redirect` (`"follow" | "error" | "manual"`) - Redirect handling mode.
- `:signal` (`Web.AbortSignal.t()` | pid | reference) - Optional abort signal.
- `:dispatcher` (module) - Optional override for the request handler.
## Returns
- `{:ok, Web.Response.t()}` on success.
- `{:error, any()}` on failure.
## Examples
iex> {:error, _} = Web.fetch("http://localhost_nxdomain")
iex> is_tuple(Web.fetch("http://localhost_nxdomain"))
true
iex> req = Web.Request.new("http://localhost_nxdomain")
iex> {:error, _} = Web.fetch(req)
"""
@spec fetch(String.t() | Web.URL.t() | Web.Request.t(), keyword()) ::
{:ok, Web.Response.t()} | {:error, any()}
def fetch(input, init \\ [])
def fetch(%Web.Request{} = request, _init) do
do_fetch(request)
catch
:throw, {:abort, :aborted} -> {:error, :aborted}
end
def fetch(%Web.URL{} = input, init) do
request = Web.Request.new(input, init)
do_fetch(request)
catch
:throw, {:abort, :aborted} -> {:error, :aborted}
end
def fetch(input, init) when is_binary(input) do
request = Web.Request.new(input, init)
do_fetch(request)
catch
:throw, {:abort, :aborted} -> {:error, :aborted}
end
defp do_fetch(request) do
Web.AbortSignal.check!(request.signal)
dispatcher =
request.dispatcher ||
Web.Resolver.resolve(request.url)
dispatcher.fetch(request)
end
end