View Source erqwest

Hex pm

An erlang wrapper for reqwest using rustler. Map-based interface inspired by katipo.

Features

  • HTTP/1.1 and HTTP/2 with connection keepalive/reuse
  • Configurable SSL support, uses system root certificates by default
  • Sync and async interfaces
  • Proxy support
  • Optional cookies support
  • Optional gzip support

Prerequisites

  • Erlang/OTP
  • Rust
  • OpenSSL (not required on mac)

Or use the provided shell.nix if you have nix installed.

Usage

Start a client

ok = application:ensure_started(erqwest),
ok = erqwest:start_client(default).

This registers a client under the name default. The client maintains an internal connection pool.

Synchronous interface

No streaming

 {ok, #{status := 200, body := Body}} = 
     erqwest:get(default, <<"https://httpbin.org/get">>),

 {ok, #{status := 200, body := Body1}} =
     erqwest:post(default, <<"https://httpbin.org/post">>,
                  #{body => <<"data">>}).

Stream request body

 {handle, H} = erqwest:post(default, <<"https://httpbin.org/post">>,
                            #{body => stream}),
 ok = erqwest:send(H, <<"data, ">>),
 ok = erqwest:send(H, <<"more data.">>),
 {ok, #{body := Body}} = erqwest:finish_send(H).

Stream response body

 {ok, #{body := Handle}} = erqwest:get(default, <<"https://httpbin.org/stream-bytes/1000">>,
                                       #{response_body => stream}),
 ReadAll = fun Self() ->
               case erqwest:read(Handle, #{length => 0}) of
                 {ok, Data} ->
                   [Data];
                 {more, Data} ->
                   [Data|Self()]
               end
           end,
 1000 = iolist_size(ReadAll()).

Conditionally consume response body

 {ok, Resp} = erqwest:get(default, <<"https://httpbin.org/status/200,500">>,
                          #{response_body => stream}),
 case Resp of
   #{status := 200, body := Handle} ->
     {ok, <<>>} = erqwest:read(Handle),
   #{status := BadStatus, body := Handle} ->
     %% ensures the connection is closed/can be reused immediately
     erqwest:cancel(Handle),
     io:format("Status is ~p, not interested~n", [BadStatus])
 end.

Asynchronous interface

erqwest_async:req(default, self(), Ref=make_ref(), 
                  #{method => get, url => <<"https://httpbin.org/get">>}),
receive
    {erqwest_response, Ref, reply, #{body := Body}} -> Body
end.

See the docs for more details and and the test suite for more examples.

Docs

Benchmarks