Modules · Web · 0.29
Fetch
An HTTP user agent for HTTP/3, HTTP/2 and HTTP/1.1, whose every request is a future.
Sockets, TLS, QUIC and the HTTP framing are vendored C. Every request returns a future, and ->get on it pumps whichever loop is running, its own if none is: one line for a single call, or a thousand requests multiplexed on one loop, in the same code.
use Fetch;
my $base = $ENV{BASE} || 'http://127.0.0.1:8080'; # the Hyperman beside it
# ->get awaits the future: there is no event loop to set up
my $res = Fetch->new(timeout => 5)->get("$base/")->get;
print $res->status, ' ', $res->content; # 200 hello
print $res->header('Content-Type'), "\n"; # text/plain
What you get
-
A future for every request
get,post,requestandwebsocketall return aFetch::Future, andneeds_allwaits for many at once. -
Any loop, or none
Fetch has its own loop and uses it when you give it nothing. Hand it an IO::Async loop, AnyEvent or Hyperman's and its requests share that loop without blocking it.
-
Three protocols
HTTP/2 by ALPN over TLS, HTTP/3 over QUIC when a server offers it with
Alt-Svc, and HTTP/1.1 otherwise, each with a keep-alive pool. -
What a client needs
Redirects, per-request timeouts, a cookie jar, streaming bodies,
json =>in and$res->jsonout, and WebSockets. -
Watch every request
Fetch->on_requestsees each request the process makes, even ones it did not write, and can add a header to it: a tracing layer'straceparent, for one.
In use
use Fetch;
use Time::HiRes qw(time);
my $base = $ENV{BASE} || 'http://127.0.0.1:8080';
my $ua = Fetch->new(timeout => 5);
# eight requests in flight at once, on one loop
my $t0 = time;
my @futs = map { $ua->get("$base/slow") } 1 .. 8;
Fetch::Future->needs_all(@futs)->get;
print sort map { $_->get->content } @futs; # slow request 1 .. 8
printf "8 requests in %.1fs\n", time - $t0; # about 0.2s, not 1.6s
For C
fetch_abi.h, vendored at a pinned version and resolved at boot through Fetch::_abi_ptr: another XS module builds and sends requests entirely in C, as Reverse::Proxy builds its upstream requests, and can observe every request the process makes with no Perl on the path.