View Source Req (req v0.4.11)

The high-level API.

Req is composed of three main pieces:

  • Req - the high-level API (you're here!)

  • Req.Request - the low-level API and the request struct

  • Req.Steps - the collection of built-in steps

The high-level API is what most users of Req will use most of the time.

Examples

Making a GET request with Req.get!/1:

iex> Req.get!("https://api.github.com/repos/wojtekmach/req").body["description"]
"Req is a batteries-included HTTP client for Elixir."

Same, but by explicitly building request struct first:

iex> req = Req.new(base_url: "https://api.github.com")
iex> Req.get!(req, url: "/repos/wojtekmach/req").body["description"]
"Req is a batteries-included HTTP client for Elixir."

Making a POST request with Req.post!/2:

iex> Req.post!("https://httpbin.org/post", form: [comments: "hello!"]).body["form"]
%{"comments" => "hello!"}

Stream request body:

iex> stream = Stream.duplicate("foo", 3)
iex> Req.post!("https://httpbin.org/post", body: stream).body["data"]
"foofoofoo"

Stream response body using a callback:

iex> resp =
...>   Req.get!("http://httpbin.org/stream/2", into: fn {:data, data}, {req, resp} ->
...>     IO.puts(data)
...>     {:cont, {req, resp}}
...>   end)
# output: {"url": "http://httpbin.org/stream/2", ...}
# output: {"url": "http://httpbin.org/stream/2", ...}
iex> resp.status
200
iex> resp.body
""

Stream response body into a Collectable:

iex> resp = Req.get!("http://httpbin.org/stream/2", into: IO.stream())
# output: {"url": "http://httpbin.org/stream/2", ...}
# output: {"url": "http://httpbin.org/stream/2", ...}
iex> resp.status
200
iex> resp.body
%IO.Stream{}

Header Names

The HTTP specification requires that header names should be case-insensitive. Req allows two ways to access the headers; using functions and by accessing the data directly:

iex> Req.Response.get_header(response, "content-type")
["text/html"]

iex> response.headers["content-type"]
["text/html"]

While we can ensure case-insensitive handling in the former case, we can't in the latter. For this reason, Req made the following design choices:

Summary

Making Requests

Makes a DELETE request and returns a response or an error.

Makes a DELETE request and returns a response or raises an error.

Makes a GET request and returns a response or an error.

Makes a GET request and returns a response or raises an error.

Makes a HEAD request and returns a response or an error.

Makes a HEAD request and returns a response or raises an error.

Makes a PATCH request and returns a response or an error.

Makes a PATCH request and returns a response or raises an error.

Makes a POST request and returns a response or an error.

Makes a POST request and returns a response or raises an error.

Makes a PUT request and returns a response or an error.

Makes a PUT request and returns a response or raises an error.

Makes an HTTP request and returns a response or an error.

Makes an HTTP request and returns a response or raises an error.

Functions

Returns default options.

Sets default options for Req.new/1.

Returns a new request struct with built-in steps.

Updates a request struct.

Making Requests

Link to this function

delete(request, options \\ [])

View Source
@spec delete(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  {:ok, Req.Response.t()} | {:error, Exception.t()}

Makes a DELETE request and returns a response or an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> {:ok, resp} = Req.delete("https://httpbin.org/anything")
iex> resp.body["method"]
"DELETE"

With options:

iex> {:ok, resp} = Req.delete(url: "https://httpbin.org/anything")
iex> resp.body["method"]
"DELETE"

With request struct:

iex> req = Req.new(url: "https://httpbin.org/anything")
iex> {:ok, resp} = Req.delete(req)
iex> resp.body["method"]
"DELETE"
Link to this function

delete!(request, options \\ [])

View Source
@spec delete!(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  Req.Response.t()

Makes a DELETE request and returns a response or raises an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> Req.delete!("https://httpbin.org/anything").body["method"]
"DELETE"

With options:

iex> Req.delete!(url: "https://httpbin.org/anything").body["method"]
"DELETE"

With request struct:

iex> req = Req.new(url: "https://httpbin.org/anything")
iex> Req.delete!(req).body["method"]
"DELETE"
Link to this function

get(request, options \\ [])

View Source
@spec get(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  {:ok, Req.Response.t()} | {:error, Exception.t()}

Makes a GET request and returns a response or an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> {:ok, resp} = Req.get("https://api.github.com/repos/wojtekmach/req")
iex> resp.body["description"]
"Req is a batteries-included HTTP client for Elixir."

With options:

iex> {:ok, resp} = Req.get(url: "https://api.github.com/repos/wojtekmach/req")
iex> resp.status
200

With request struct:

iex> req = Req.new(base_url: "https://api.github.com")
iex> {:ok, resp} = Req.get(req, url: "/repos/elixir-lang/elixir")
iex> resp.status
200
Link to this function

get!(request, options \\ [])

View Source
@spec get!(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  Req.Response.t()

Makes a GET request and returns a response or raises an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> Req.get!("https://api.github.com/repos/wojtekmach/req").body["description"]
"Req is a batteries-included HTTP client for Elixir."

With options:

iex> Req.get!(url: "https://api.github.com/repos/wojtekmach/req").status
200

With request struct:

iex> req = Req.new(base_url: "https://api.github.com")
iex> Req.get!(req, url: "/repos/elixir-lang/elixir").status
200
Link to this function

head(request, options \\ [])

View Source
@spec head(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  {:ok, Req.Response.t()} | {:error, Exception.t()}

Makes a HEAD request and returns a response or an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> {:ok, resp} = Req.head("https://httpbin.org/status/201")
iex> resp.status
201

With options:

iex> {:ok, resp} = Req.head(url: "https://httpbin.org/status/201")
iex> resp.status
201

With request struct:

iex> req = Req.new(base_url: "https://httpbin.org")
iex> {:ok, resp} = Req.head(req, url: "/status/201")
iex> resp.status
201
Link to this function

head!(request, options \\ [])

View Source
@spec head!(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  Req.Response.t()

Makes a HEAD request and returns a response or raises an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> Req.head!("https://httpbin.org/status/201").status
201

With options:

iex> Req.head!(url: "https://httpbin.org/status/201").status
201

With request struct:

iex> req = Req.new(base_url: "https://httpbin.org")
iex> Req.head!(req, url: "/status/201").status
201
Link to this function

patch(request, options \\ [])

View Source
@spec patch(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  {:ok, Req.Response.t()} | {:error, Exception.t()}

Makes a PATCH request and returns a response or an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> {:ok, resp} = Req.patch("https://httpbin.org/anything", body: "hello!")
iex> resp.body["data"]
"hello!"

With options:

iex> {:ok, resp} = Req.patch(url: "https://httpbin.org/anything", body: "hello!")
iex> resp.body["data"]
"hello!"

With request struct:

iex> req = Req.new(url: "https://httpbin.org/anything")
iex> {:ok, resp} = Req.patch(req, body: "hello!")
iex> resp.body["data"]
"hello!"
Link to this function

patch!(request, options \\ [])

View Source
@spec patch!(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  Req.Response.t()

Makes a PATCH request and returns a response or raises an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> Req.patch!("https://httpbin.org/anything", body: "hello!").body["data"]
"hello!"

With options:

iex> Req.patch!(url: "https://httpbin.org/anything", body: "hello!").body["data"]
"hello!"

With request struct:

iex> req = Req.new(url: "https://httpbin.org/anything")
iex> Req.patch!(req, body: "hello!").body["data"]
"hello!"
Link to this function

post(request, options \\ [])

View Source
@spec post(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  {:ok, Req.Response.t()} | {:error, Exception.t()}

Makes a POST request and returns a response or an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> {:ok, resp} = Req.post("https://httpbin.org/anything", body: "hello!")
iex> resp.body["data"]
"hello!"

iex> {:ok, resp} = Req.post("https://httpbin.org/anything", form: [x: 1])
iex> resp.body["form"]
%{"x" => "1"}

iex> {:ok, resp} = Req.post("https://httpbin.org/anything", json: %{x: 2})
iex> resp.body["json"]
%{"x" => 2}

With options:

iex> {:ok, resp} = Req.post(url: "https://httpbin.org/anything", body: "hello!")
iex> resp.body["data"]
"hello!"

With request struct:

iex> req = Req.new(url: "https://httpbin.org/anything")
iex> {:ok, resp} = Req.post(req, body: "hello!")
iex> resp.body["data"]
"hello!"
Link to this function

post!(request, options \\ [])

View Source
@spec post!(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  Req.Response.t()

Makes a POST request and returns a response or raises an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> Req.post!("https://httpbin.org/anything", body: "hello!").body["data"]
"hello!"

iex> Req.post!("https://httpbin.org/anything", form: [x: 1]).body["form"]
%{"x" => "1"}

iex> Req.post!("https://httpbin.org/anything", json: %{x: 2}).body["json"]
%{"x" => 2}

With options:

iex> Req.post!(url: "https://httpbin.org/anything", body: "hello!").body["data"]
"hello!"

With request struct:

iex> req = Req.new(url: "https://httpbin.org/anything")
iex> Req.post!(req, body: "hello!").body["data"]
"hello!"
Link to this function

put(request, options \\ [])

View Source
@spec put(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  {:ok, Req.Response.t()} | {:error, Exception.t()}

Makes a PUT request and returns a response or an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> {:ok, resp} = Req.put("https://httpbin.org/anything", body: "hello!")
iex> resp.body["data"]
"hello!"

With options:

iex> {:ok, resp} = Req.put(url: "https://httpbin.org/anything", body: "hello!")
iex> resp.body["data"]
"hello!"

With request struct:

iex> req = Req.new(url: "https://httpbin.org/anything")
iex> {:ok, resp} = Req.put(req, body: "hello!")
iex> resp.body["data"]
"hello!"
Link to this function

put!(request, options \\ [])

View Source
@spec put!(url() | keyword() | Req.Request.t(), options :: keyword()) ::
  Req.Response.t()

Makes a PUT request and returns a response or raises an error.

request can be one of:

See new/1 for a list of available options.

Examples

With URL:

iex> Req.put!("https://httpbin.org/anything", body: "hello!").body["data"]
"hello!"

With options:

iex> Req.put!(url: "https://httpbin.org/anything", body: "hello!").body["data"]
"hello!"

With request struct:

iex> req = Req.new(url: "https://httpbin.org/anything")
iex> Req.put!(req, body: "hello!").body["data"]
"hello!"
Link to this function

request(request, options \\ [])

View Source
@spec request(request :: Req.Request.t() | keyword(), options :: keyword()) ::
  {:ok, Req.Response.t()} | {:error, Exception.t()}

Makes an HTTP request and returns a response or an error.

request can be one of:

See new/1 for a list of available options.

Examples

With options keywords list:

iex> {:ok, response} = Req.request(url: "https://api.github.com/repos/wojtekmach/req")
iex> response.status
200
iex> response.body["description"]
"Req is a batteries-included HTTP client for Elixir."

With request struct:

iex> req = Req.new(url: "https://api.github.com/repos/elixir-lang/elixir")
iex> {:ok, response} = Req.request(req)
iex> response.status
200
Link to this function

request!(request, options \\ [])

View Source
@spec request!(request :: Req.Request.t() | keyword(), options :: keyword()) ::
  Req.Response.t()

Makes an HTTP request and returns a response or raises an error.

See new/1 for a list of available options.

Examples

With options keywords list:

iex> Req.request!(url: "https://api.github.com/repos/elixir-lang/elixir").status
200

With request struct:

iex> req = Req.new(url: "https://api.github.com/repos/elixir-lang/elixir")
iex> Req.request!(req).status
200

Types

Functions

@spec default_options() :: keyword()

Returns default options.

See default_options/1 for more information.

Link to this function

default_options(options)

View Source
@spec default_options(keyword()) :: :ok

Sets default options for Req.new/1.

Avoid setting default options in libraries as they are global.

Examples

iex> Req.default_options(base_url: "https://httpbin.org")
iex> Req.get!("/statuses/201").status
201
iex> Req.new() |> Req.get!(url: "/statuses/201").status
201
@spec new(options :: keyword()) :: Req.Request.t()

Returns a new request struct with built-in steps.

See Req.Request module documentation for more information on the underlying request struct.

Options

Basic request options:

  • :method - the request method, defaults to :get.

  • :url - the request URL.

  • :headers - the request headers as a {key, value} enumerable (e.g. map, keyword list).

    The header names should be downcased.

    The headers are automatically encoded using these rules:

    • atom header names are turned into strings, replacing _ with -. For example, :user_agent becomes "user-agent".

    • string header names are downcased.

    • %DateTime{} header values are encoded as "HTTP date".

    • other header values are encoded with String.Chars.to_string/1.

    If you set :headers options both in Req.new/1 and request/2, the header lists are merged.

    See also "Header Names" section in the module documentation.

  • :body - the request body.

    Can be one of:

    • iodata - send request body eagerly

    • enumerable - stream enumerable as request body

Additional URL options:

  • :base_url - if set, the request URL is prepended with this base URL (via put_base_url step.)

  • :params - if set, appends parameters to the request query string (via put_params step.)

  • :path_params - if set, uses a templated request path (via put_path_params step.)

Authentication options:

  • :auth - sets request authentication (via auth step.)

    Can be one of:

    • {:basic, userinfo} - uses Basic HTTP authentication.

    • {:bearer, token} - uses Bearer HTTP authentication.

    • :netrc - load credentials from the default .netrc file.

    • {:netrc, path} - load credentials from path.

    • string - sets to this value.

  • :redact_auth - if set to true, when Req.Request struct is inspected, authentication credentials are redacted. Defaults to true.

Request body options:

  • :form - if set, encodes the request body as form data (encode_body step.)

  • :json - if set, encodes the request body as JSON (encode_body step.)

  • :compress_body - if set to true, compresses the request body using gzip (via compress_body step.) Defaults to false.

AWS Signature Version 4 options (put_aws_sigv4 step):

  • :aws_sigv4 - if set, the AWS options to sign request:

    • :access_key_id - the AWS access key id.

    • :secret_access_key - the AWS secret access key.

    • :service - the AWS service.

    • :region - if set, AWS region. Defaults to "us-east-1".

This functionality requires :aws_signature dependency:

{:aws_signature, "~> 0.3.0"}

Response body options:

  • :compressed - if set to true, asks the server to return compressed response. (via compressed step.) Defaults to true.

  • :raw - if set to true, disables automatic body decompression (decompress_body step) and decoding (decode_body step.) Defaults to false.

  • :decode_body - if set to false, disables automatic response body decoding. Defaults to true.

  • :decode_json - options to pass to Jason.decode!/2, defaults to [].

  • :into - where to send the response body. It can be one of:

    • nil - (default) read the whole response body and store it in the response.body field.

    • fun - stream response body using a function. The first argument is a {:data, data} tuple containing the chunk of the response body. The second argument is a {request, response} tuple. To continue streaming chunks, return {:cont, {req, resp}}. To cancel, return {:halt, {req, resp}}. For example:

      into: fn {:data, data}, {req, resp} ->
        IO.puts(data)
        {:cont, {req, resp}}
      end
    • collectable - stream response body into a Collectable.t/0.

Response redirect options (redirect step):

  • :redirect - if set to false, disables automatic response redirects. Defaults to true.

  • :redirect_trusted - by default, authorization credentials are only sent on redirects with the same host, scheme and port. If :redirect_trusted is set to true, credentials will be sent to any host.

  • :max_redirects - the maximum number of redirects, defaults to 10.

Retry options (retry step):

  • :retry - can be one of the following:

    • :safe_transient (default) - retry safe (GET/HEAD) requests on HTTP 408/429/500/502/503/504 responses or exceptions with reason field set to :timeout/:econnrefused/:closed.

    • :transient - same as :safe_transient except retries all HTTP methods (POST, DELETE, etc.)

    • fun - a 2-arity function that accepts a Req.Request and either a Req.Response or an exception struct and returns one of the following:

      • true - retry with the default delay controller by default delay option described below.

      • {:delay, milliseconds} - retry with the given delay.

      • false/nil - don't retry.

    • false - don't retry.

  • :retry_delay - if not set, which is the default, the retry delay is determined by the value of retry-delay header on HTTP 429/503 responses. If the header is not set, the default delay follows a simple exponential backoff: 1s, 2s, 4s, 8s, ...

    :retry_delay can be set to a function that receives the retry count (starting at 0) and returns the delay, the number of milliseconds to sleep before making another attempt.

  • :retry_log_level - the log level to emit retry logs at. Can also be set to false to disable logging these messages. Defaults to :error.

  • :max_retries - maximum number of retry attempts, defaults to 3 (for a total of 4 requests to the server, including the initial one.)

Caching options (cache step):

  • :cache - if true, performs HTTP caching. Defaults to false.

  • :cache_dir - the directory to store the cache, defaults to <user_cache_dir>/req (see: :filename.basedir/3)

Request adapters:

  • :adapter - adapter to use to make the actual HTTP request. See :adapter field description in the Req.Request module documentation for more information. Defaults to calling run_finch.

  • :plug - if set, calls the given Plug instead of making an HTTP request over the network (via put_plug step).

Finch options (run_finch step)

  • :finch - the Finch pool to use. Defaults to pool automatically started by Req.

  • :connect_options - dynamically starts (or re-uses already started) Finch pool with the given connection options:

    • :timeout - socket connect timeout in milliseconds, defaults to 30_000.

    • :protocols - the HTTP protocols to use, defaults to [:http1, :http2], that is default to HTTP/1 but if negotiated, allow HTTP/2 over HTTP/1 connection. To force HTTP/2, set protocols: [:http2].

    • :hostname - Mint explicit hostname.

    • :transport_opts - Mint transport options.

    • :proxy_headers - Mint proxy headers.

    • :proxy - Mint HTTP/1 proxy settings, a {schema, address, port, options} tuple.

    • :client_settings - Mint HTTP/2 client settings.

  • :inet6 - if set to true, uses IPv6. Defaults to false.

  • :pool_timeout - pool checkout timeout in milliseconds, defaults to 5000.

  • :receive_timeout - socket receive timeout in milliseconds, defaults to 15_000.

  • :unix_socket - if set, connect through the given UNIX domain socket.

  • :finch_private - a map or keyword list of private metadata to add to the Finch request. May be useful for adding custom data when handling telemetry with Finch.Telemetry.

  • :finch_request - a function that executes the Finch request, defaults to using Finch.request/3.

Examples

iex> req = Req.new(url: "https://elixir-lang.org")
iex> req.method
:get
iex> URI.to_string(req.url)
"https://elixir-lang.org"

Fake adapter:

iex> fake = fn request ->
...>   {request, Req.Response.new(status: 200, body: "it works!")}
...> end
iex>
iex> req = Req.new(adapter: fake)
iex> Req.get!(req).body
"it works!"
Link to this function

update(request, options)

View Source
@spec update(Req.Request.t(), options :: keyword()) :: Req.Request.t()

Updates a request struct.

See new/1 for a list of available options. Also see Req.Request module documentation for more information on the underlying request struct.

Examples

iex> req = Req.new(base_url: "https://httpbin.org")
iex> req = Req.update(req, auth: {:basic, "alice:secret"})
iex> req.options[:base_url]
"https://httpbin.org"
iex> req.options[:auth]
{:basic, "alice:secret"}

Passing :headers will automatically encode and merge them:

iex> req = Req.new(headers: %{point_x: 1})
iex> req = Req.update(req, headers: %{point_y: 2})
iex> req.headers
%{"point-x" => ["1"], "point-y" => ["2"]}

The same header names are overwritten however:

iex> req = Req.new(headers: %{authorization: "bearer foo"})
iex> req = Req.update(req, headers: %{authorization: "bearer bar"})
iex> req.headers
%{"authorization" => ["bearer bar"]}

Similarly to headers, :params are merged too:

req = Req.new(url: "https://httpbin.org/anything", params: [a: 1, b: 1])
req = Req.update(req, params: [a: 2])
Req.get!(req).body["args"]
#=> %{"a" => "2", "b" => "1"}