Req (req v0.8.0-rc.0)

Copy Markdown View Source

The high-level API.

Req is composed of:

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."

The request that was sent is available in resp.request:

iex> resp = Req.get!("https://httpbingo.org/basic-auth/foo/bar", auth: {:basic, "foo:bar"})
iex> resp.request.headers["authorization"]
["Basic Zm9vOmJhcg=="]
iex> resp.status
200

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

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

Set connection timeout:

iex> resp = Req.get!("https://httpbingo.org", connect_options: [timeout: 100])
iex> resp.status
200

See Req.Finch for more connection related options and usage examples.

Stream request body:

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

Stream response body using Req.stream/4:

iex> {:ok, resp, acc} =
...> Req.stream(
...>   "http://httpbingo.org/stream/2",
...>   [],
...>   fn data, _resp, acc ->
...>     IO.inspect(data)
...>     {:cont, acc}
...>   end,
...>   decoders: [text: :ndjson] # endpoint sends content-type: text/plain
...>                             # so let's force ndjson.
...> )
# Output: %{"id" => 0, ...}
# Output: %{"id" => 1, ...}
iex> resp.status
200
iex> resp.body
nil

Stream response body into a Collectable:

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

Stream response body to the current process and parse incoming messages using Req.parse_message/2.

iex> resp = Req.get!("http://httpbingo.org/stream/2", into: :self)
iex> Req.parse_message(resp, receive do message -> message end)
{:ok, [data: "{\"url\": \"http://httpbingo.org/stream/2\", ..., \"id\": 0}\n"]}
iex> Req.parse_message(resp, receive do message -> message end)
{:ok, [data: "{\"url\": \"http://httpbingo.org/stream/2\", ..., \"id\": 1}\n"]}
iex> Req.parse_message(resp, receive do message -> message end)
{:ok, [:done]}
""

Same as above, using enumerable API:

iex> resp = Req.get!("http://httpbingo.org/stream/2", into: :self)
iex> resp.body
#Req.Response.Async<...>
iex> Enum.each(resp.body, &IO.puts/1)
# {"url": "http://httpbingo.org/stream/2", ..., "id": 0}
# {"url": "http://httpbingo.org/stream/2", ..., "id": 1}
:ok

See :into option in Req.new/1 documentation for more information on response body streaming.

Headers

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:

Note

Most Elixir/Erlang HTTP clients represent headers as lists of tuples like:

[{"content-type", "text/plain"}]

For interoperability with those, use Req.get_headers_list/1.

Summary

Functions

Returns default options.

Sets default options for Req.new/1.

Returns request/response headers as list.

Updates a request struct.

Returns a new request struct with built-in steps.

Functions (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.

Streams an HTTP request.

Functions (Async Response)

Cancels an asynchronous response.

Parses asynchronous response body message.

Types

url()

@type url() :: URI.t() | String.t()

Functions

default_options()

@spec default_options() :: keyword()

Returns default options.

See default_options/1 for more information.

default_options(options)

@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://httpbingo.org")
iex> Req.get!("/statuses/201").status
201
iex> Req.new() |> Req.get!(url: "/statuses/201").status
201

get_headers_list(struct)

(since 0.5.10)
@spec get_headers_list(Req.Request.t() | Req.Response.t()) :: [{binary(), binary()}]

Returns request/response headers as list.

Examples

iex> req = Req.Request.new(headers: %{"accept" => ["application/json"]})
iex> Req.get_headers_list(req)
[{"accept", "application/json"}]

iex> resp = Req.Response.new(headers: %{"content-type" => ["application/json"]})
iex> Req.get_headers_list(resp)
[{"content-type", "application/json"}]

merge(request, options)

@spec merge(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://httpbingo.org")
iex> req = Req.merge(req, auth: {:basic, "alice:secret"})
iex> req.options[:base_url]
"https://httpbingo.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.merge(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.merge(req, headers: %{authorization: "bearer bar"})
iex> req.headers
%{"authorization" => ["bearer bar"]}

Similarly to headers, :params are merged too:

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

new(request \\ [], options \\ [])

@spec new(request :: url() | keyword() | Req.Request.t(), options :: keyword()) ::
  Req.Request.t()

Returns a new request struct with built-in steps.

See request/2, as well as get/2, post/2, and similar functions for making requests.

Also 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".

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

    See also "Headers" section in the module documentation.

  • :body - the request body.

    Can be one of:

    • nil - no body is sent with the request.

    • iodata - request body as "IO data".

    • enumerable - stream request body chunks emitted by the given Enumerable.

    • req_body_fun - stream request body chunks from a 1-arity function.

      Only supported in Req.stream/4.

      The function receives the accumulator passed to Req.stream/4 and should return one of:

      • {:data, chunk, acc} - Emit request body chunk and continue streaming.

      • {:done, chunk, acc} - emit the final request body chunk. acc is passed to the response streaming function.

      • {:done, acc} - request body streaming is done. acc is passed to the response streaming function.

      • {:halt, acc} - cancel request. On HTTP/1, this closes the connection.

      • {:error, exception, acc} - cancel request and return {:error, exception, resp, acc} from Req.stream/4.

  • :private - a map reserved for libraries and frameworks to use. The keys must be atoms.

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.)

  • :path_params_style (available since v0.5.1) - how path params are expressed (via put_path_params step). Can be one of:

    • :colon - (default) for Plug-style parameters, such as :code in https://httpbingo.org/status/:code.

    • :curly - for OpenAPI-style parameters, such as {code} in https://httpbingo.org/status/{code}.

Authentication options:

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

    Can be one of:

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

    • {:digest, userinfo} - uses Digest 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.

    • &fun/0 - a function that returns one of the above (such as a {:bearer, token}).

    • {mod, fun, args} - an MFArgs tuple that returns one of the above (such as a {:bearer, token}).

Request body encoding options (encode_body):

  • :form - if set, encodes the request body as application/x-www-form-urlencoded

  • :form_multipart - if set, encodes the request body as multipart/form-data.

  • :json - if set, encodes the request body as JSON

Other request body options:

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

Other request options:

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".

    • :datetime - the request datetime, defaults to DateTime.utc_now(:second).

Response body options:

  • :compressed - if set to true, asks the server to return a compressed response and decompresses it. Defaults to false.

    Note: the response body is decompressed with no size limit, so a small response can expand into many gigabytes. A malicious or compromised server can exploit this to exhaust memory and crash the client (a decompression bomb / denial of service), so only set compressed: true for endpoints you trust.

  • :raw - if set to true, disables body decompression and automatic decoding (see Req.Decompress and Req.Decode). Defaults to false.

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

  • :decoders - the list of decoders to use for automatic response body decoding. Defaults to [:json, :json_api, :ndjson, :sse]. See Req.Decode for the supported formats and how to add custom decoders.

  • :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.

    • collectable - stream response body into a Collectable.t/0. For example:

       into: File.stream!("path")

      Note that the collectable is only used, if the response status is 200. In other cases, the body is accumulated and processed as usual.

    • :self - stream response body into the current process mailbox.

      Received messages should be parsed with Req.parse_message/2.

      response.body is set to opaque data structure Req.Response.Async which implements Enumerable that receives and automatically parses messages. See module documentation for example usage.

      If the request is sent using HTTP/1, an extra process is spawned to consume messages from the underlying socket. On both HTTP/1 and HTTP/2 the messages are sent to the current process as soon as they arrive, as a firehose. If you wish to maximize request rate or have more control over how messages are streamed, use Req.stream/4 or into: collectable instead.

    Note: Req.stream/4 does not support :into option.

Response redirect options (Req.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. Defaults to false.

  • :redirect_log_level - the log level to emit redirect logs at. Can also be set to false to disable logging these messages. Defaults to :debug.

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

Other response options:

  • :expect - the expected HTTP response status (via Req.Expect step). Can be an integer, a range, or a list of integers/ranges.

  • :checksum - if set, this is the expected response body checksum, see Req.Checksum.

Retry options (Req.Retry step):

  • :retry - can be one of the following:

    • :safe_transient (default) - retry safe (GET/HEAD) requests on one of:

      • HTTP 408/429/500/502/503/504 responses

      • Req.TransportError with reason: :timeout | :econnrefused | :closed

      • Req.HTTPError with protocol: :http2, reason: :unprocessed | :pool_not_available

    • :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 using the default delay described under :retry_delay 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 the Retry-After header on HTTP 429/503 responses. If the header is not set, the default delay follows a simple exponential backoff with jitter, for example: 0.949s, 1.97s, 3.87s, 7.55s, ...

    :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 :warning.

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

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.

    The default is Req.Finch.

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

    The plug can be one of:

    • A function plug: a fun(conn) or fun(conn, options) function that takes a Plug.Conn and returns a Plug.Conn.

    • A module plug: a module name or a {module, options} tuple.

Finch options (Req.Finch adapter), see Finch.start_link/1 for options:

  • :finch - options for the Finch adapter. Defaults to a pool automatically started by Req. Can include:

    • :name - the name of the Finch pool.

    • Finch request options, e.g. :pool_tag, :pool_timeout, :receive_timeout. See Finch.Request.build_opt/0 and Finch.request_opt/0 for more information.

    • Finch pool options, e.g.: :conn_max_idle_time, :pool_max_idle_time, :conn_opts. See Finch.start_link/1 for more information.

      Finch pool options cannot be mixed with :name option.

    Examples:

    Req.get!("https://httpbingo.org/json", finch: [name: MyFinch])
    Req.get!("https://httpbingo.org/json", finch: [name: MyFinch, pool_tag: :bulk])
    Req.get!("https://httpbingo.org/json", finch: [conn_max_idle_time: 10_000])
  • :connect_options - dynamically starts (or re-uses already started) Finch pool with the given connection options (see Mint.HTTP.connect/4 for options):

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

    • :protocols - the HTTP protocols to use, defaults to [:http1].

    • :hostname - Mint explicit hostname.

    • :transport_opts - Mint transport options.

    • :proxy_headers - Mint proxy headers.

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

    • :client_settings - Mint HTTP/2 client settings.

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

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

  • :request_timeout - response timeout in milliseconds, defaults to :infinity. See Finch.request/3.

  • :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.

Examples

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

With a url and options:

iex> req = Req.new("https://elixir-lang.org", method: :head)
iex> req.method
:head

Functions (Making Requests)

delete(request, options \\ [])

@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://httpbingo.org/anything")
iex> resp.body["method"]
"DELETE"

With options:

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

With request struct:

iex> req = Req.new(url: "https://httpbingo.org/anything", headers: [content_type: "text/plain"])
iex> {:ok, resp} = Req.delete(req)
iex> resp.body["method"]
"DELETE"

delete!(request, options \\ [])

@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://httpbingo.org/anything").body["method"]
"DELETE"

With options:

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

With request struct:

iex> req = Req.new(url: "https://httpbingo.org/anything", headers: [content_type: "text/plain"])
iex> Req.delete!(req).body["method"]
"DELETE"

get(request, options \\ [])

@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

get!(request, options \\ [])

@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

head(request, options \\ [])

@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://httpbingo.org/status/201")
iex> resp.status
201

With options:

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

With request struct:

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

head!(request, options \\ [])

@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://httpbingo.org/status/201").status
201

With options:

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

With request struct:

iex> req = Req.new(base_url: "https://httpbingo.org")
iex> Req.head!(req, url: "/status/201").status
201

patch(request, options \\ [])

@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://httpbingo.org/anything", body: "hello!", headers: [content_type: "text/plain"])
iex> resp.body["data"]
"hello!"

With options:

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

With request struct:

iex> req = Req.new(url: "https://httpbingo.org/anything", headers: [content_type: "text/plain"])
iex> {:ok, resp} = Req.patch(req, body: "hello!")
iex> resp.body["data"]
"hello!"

patch!(request, options \\ [])

@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://httpbingo.org/anything", body: "hello!", headers: [content_type: "text/plain"]).body["data"]
"hello!"

With options:

iex> Req.patch!(url: "https://httpbingo.org/anything", body: "hello!", headers: [content_type: "text/plain"]).body["data"]
"hello!"

With request struct:

iex> req = Req.new(url: "https://httpbingo.org/anything", headers: [content_type: "text/plain"])
iex> Req.patch!(req, body: "hello!").body["data"]
"hello!"

post(request, options \\ [])

@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://httpbingo.org/anything",
...>     body: "hello!",
...>     headers: [content_type: "text/plain"]
...>   )
iex> resp.body["data"]
"hello!"

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

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

With options:

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

With request struct:

iex> req = Req.new(url: "https://httpbingo.org/anything", headers: [content_type: "text/plain"])
iex> {:ok, resp} = Req.post(req, body: "hello!")
iex> resp.body["data"]
"hello!"

post!(request, options \\ [])

@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://httpbingo.org/anything", body: "hello!", headers: [content_type: "text/plain"]).body["data"]
"hello!"

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

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

With options:

iex> Req.post!(url: "https://httpbingo.org/anything", body: "hello!", headers: [content_type: "text/plain"]).body["data"]
"hello!"

With request struct:

iex> req = Req.new(url: "https://httpbingo.org/anything", headers: [content_type: "text/plain"])
iex> Req.post!(req, body: "hello!").body["data"]
"hello!"

put(request, options \\ [])

@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://httpbingo.org/anything", body: "hello!", headers: [content_type: "text/plain"])
iex> resp.body["data"]
"hello!"

With options:

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

With request struct:

iex> req = Req.new(url: "https://httpbingo.org/anything", headers: [content_type: "text/plain"])
iex> {:ok, resp} = Req.put(req, body: "hello!")
iex> resp.body["data"]
"hello!"

put!(request, options \\ [])

@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://httpbingo.org/anything", body: "hello!", headers: [content_type: "text/plain"]).body["data"]
"hello!"

With options:

iex> Req.put!(url: "https://httpbingo.org/anything", body: "hello!", headers: [content_type: "text/plain"]).body["data"]
"hello!"

With request struct:

iex> req = Req.new(url: "https://httpbingo.org/anything", headers: [content_type: "text/plain"])
iex> Req.put!(req, body: "hello!").body["data"]
"hello!"

request(request, options \\ [])

@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

request!(request, options \\ [])

@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

stream(req, acc, fun, options \\ [])

@spec stream(req, acc, fun, options) :: {:ok, resp, acc} | {:error, err, resp, acc}
when req: url() | keyword() | Req.Request.t(),
     resp: Req.Response.t(),
     err: Exception.t(),
     acc: term(),
     fun: (data :: term(), resp, acc -> {:cont, acc} | {:halt, acc}),
     options: keyword()

Streams an HTTP request.

req can be one of:

acc is the initial accumulator. fun receives response body chunk, the response struct, and accumulator. fun must return {:cont, acc} to continue streaming or {:halt, acc} to cancel the request (on HTTP/1 cancelling the request closes the connection):

fn data, resp, acc ->
  {:cont, acc} | {:halt, acc}
end

data is automatically decoded for some formats, including NDJSON and SSE (Server-Sent Events). See Req.Decode for more information.

Req.stream/4 returns {:ok, resp, acc} or {:error, err, resp, acc}.

See new/1 for a list of available options.

Examples

Returns recent Wikipedia changes:

iex> {:ok, resp, acc} =
...>   Req.stream(
...>     "https://stream.wikimedia.org/v2/stream/recentchange",
...>     [],
...>     fn event, _resp, acc ->
...>       %{"type" => type, "title" => title} = JSON.decode!(event.data)
...>       event = {type, title}
...> 
...>       if length(acc) < 1 do
...>         {:cont, [event | acc]}
...>       else
...>         {:halt, [event | acc]}
...>       end
...>     end
...>   )
iex> resp.status
200
iex> resp.body
nil
iex> Enum.reverse(acc)
[
  {"edit", "File:Glacier National Park (GeoDIL number - 2068).jpg"},
  {"categorize", "Category:Coins of Merovingian dynasty from Gallica"}
]

Returns an error:

iex> {:error, err, resp, acc} =
...>   Req.stream(
...>     "http://localhost:9999",
...>     nil,
...>     fn data, _resp, acc -> dbg(data); {:cont, acc} end,
...>     retry: false
...>   )
iex> err
%Req.TransportError{reason: :econnrefused}
iex> resp.status
nil
iex> to_string(resp.request.url)
"http://localhost:9999"

Functions (Async Response)

cancel_async_response(response)

Cancels an asynchronous response.

An asynchronous response is a result of request with into: :self. See also Req.Response.Async.

Examples

iex> resp = Req.get!("http://httpbingo.org/stream/2", into: :self)
iex> Req.cancel_async_response(resp)
:ok

parse_message(response, message)

Parses asynchronous response body message.

A request with option :into set to :self returns response with asynchronous body. In that case, Req sends chunks to the calling process as messages. You'd typically get them using receive/1 or handle_info/2 in a GenServer. These messages should be parsed using this function. The possible return values are:

  • {:ok, chunks} - where a chunk can be {:data, binary}, {:trailers, trailers}, or :done.

  • {:error, reason} - an error occurred

  • :unknown - the message was not meant for this response.

See also Req.Response.Async.

Examples

iex> resp = Req.get!("http://httpbingo.org/stream/2", into: :self)
iex> Req.parse_message(resp, receive do message -> message end)
{:ok, [data: "{"url": "http://httpbingo.org/stream/2", ..., "id": 0}\n"]}
iex> Req.parse_message(resp, receive do message -> message end)
{:ok, [data: "{"url": "http://httpbingo.org/stream/2", ..., "id": 1}\n"]}
iex> Req.parse_message(resp, receive do message -> message end)
{:ok, [:done]}
iex> Req.parse_message(resp, :other)
:unknown