NAME
Fetch - HTTP/2 Future-based user agent
VERSION
Version 0.01
SYNOPSIS
use Fetch;
# works out of the box - no event loop to set up
my $res = Fetch->new->get('https://example.com')->get;
print $res->content if $res->is_success;
# every call returns a Fetch::Future; ->get awaits it
my $ua = Fetch->new(timeout => 10);
my $f = $ua->post('https://api/things',
headers => { 'Content-Type' => 'application/json' },
body => '{"name":"x"}');
my $res = $f->get;
# many requests concurrently on one loop
my @futs = map { $ua->get($_) } @urls;
Fetch::Future->needs_all(@futs)->get;
my @bodies = map { $_->get->content } @futs;
# a live WebSocket
my $ws = $ua->websocket('wss://host/socket')->get;
$ws->send('hello');
my $reply = $ws->next_message->get;
DESCRIPTION
Fetch is an HTTP user agent whose socket, TLS, HTTP/2 framing and HTTP/1.1 parsing hot path lives in vendored C, and whose asynchronous results are Fetch::Future objects that compose with the Hyperman event loop and other CPAN loops (IO::Async, AnyEvent) - or with nothing at all, since Fetch ships its own event loop (Fetch::Loop::Standalone) and uses it automatically.
HTTP/1.1 and HTTP/2 (ALPN-negotiated over TLS), over cleartext and TLS, with keep-alive connection pooling, redirect following, per-request timeouts, streaming response bodies, a cookie jar, JSON request/response helpers, and native WebSockets. Every request method returns a Fetch::Future; ->get on one awaits it, pumping whichever event loop is active (its own if none), so the same code serves both a simple synchronous call and thousands of requests multiplexed on one loop.
CONSTRUCTOR
new(%args)
my $ua = Fetch->new(
timeout => 10,
tls_verify => 1,
headers => { 'Accept' => 'application/json' },
cookie_jar => 1,
);
Create a user agent. All arguments are optional:
loop-
The event loop to run on. Omit it and Fetch uses its own Fetch::Loop::Standalone (so
->getjust works with no framework). Pass a raw IO::Async::Loop or Hyperman::Loop and it is wrapped automatically; pass the string'AnyEvent'to drive AnyEvent; or pass a ready-made Fetch::Loop adapter. See "EVENT LOOPS". headers-
Default headers sent on every request, as a hashref, an arrayref of
name => valuepairs (duplicates preserved), or a Fetch::Headers. Per-requestheadersare merged on top (see "REQUEST OPTIONS"). agent-
The
User-Agentstring. Defaults to"Fetch/$VERSION". tls_verify-
Whether to verify the peer certificate and hostname for
https. Default true. Overridable per request. timeout-
Default per-request deadline in seconds (fractional allowed).
0(the default) means no timeout. Overridable per request. max_redirects-
How many redirects to follow. Default
5;0disables following. Overridable per request. keep_alive-
Reuse connections via a keep-alive pool (default true). Set false to close every connection after one request.
pool_size-
Maximum idle connections the keep-alive pool parks (default
32). -
A Fetch::CookieJar to store and send cookies (applied across redirects), or a true scalar to create a fresh one. Default: no jar.
REQUEST METHODS
Each returns a Fetch::Future that resolves to a Fetch::Response (or fails with an error string). They never block; call ->get on the future to await the result.
get / head / delete
my $f = $ua->get($url, %opt);
post / put
my $f = $ua->post($url, body => $bytes, %opt);
request($method, $url, %opt)
my $f = $ua->request('PATCH', $url, body => $bytes, %opt);
The general form the verb helpers dispatch to; use it for any method.
REQUEST OPTIONS
Passed as a trailing key => value list to any request method:
headers-
Extra headers for this request - a hashref, an arrayref of pairs (keeping duplicate names, e.g. multiple
X-*values), or a Fetch::Headers. Each named field overrides the agent default of the same name. body-
The request body (bytes). Content-Length is added automatically unless you set it yourself.
json-
A Perl data structure to send as a JSON body: it is encoded and
Content-Type: application/jsonis set (unless you gave your own). Takes precedence overbody. Pair it with "json" in Fetch::Response to decode the reply. Encoding uses Cpanel::JSON::XS when installed, else core JSON::PP.my $res = $ua->post($url, json => { name => 'x', ok => \1 })->get; my $data = $res->json; timeout-
Override the agent timeout for this request (seconds;
0disables it). tls_verify-
Override certificate/hostname verification for this
httpsrequest. max_redirects-
Override how many redirects this request follows.
on_body-
A coderef called with each body chunk as it arrives, instead of buffering. Suits large downloads and server-sent events: the buffer is compacted so an endless stream does not grow memory, and the resolved response body is empty.
$ua->get($url, on_body => sub { my ($chunk) = @_; print $chunk })->get;
WEBSOCKETS
websocket($url, %opt)
my $ws = $ua->websocket('ws://host/echo')->get; # or wss://
Open a WebSocket (RFC 6455). Returns a Fetch::Future that resolves, after the 101 handshake, to a Fetch::WebSocket for sending and receiving messages. Accepts ws:///wss:// (and http/https); tls_verify and timeout options apply to the handshake.
ACCESSORS
loop
The event-loop adapter this agent runs on.
cookie_jar
The Fetch::CookieJar in use, or undef.
THE RESULT
Awaiting a request future yields a Fetch::Response with status, headers (a Fetch::Headers), content, header($name), is_success and is_redirect. A failed request (connection error, timeout, bad TLS, a rejected WebSocket upgrade) fails the future with a message; ->get rethrows it, or inspect $f->failure / $f->is_failed.
EVENT LOOPS
$future->get awaits by pumping the active loop, so a bare synchronous call needs no setup. Hand Fetch a loop to cooperate with an existing async program - requests then fly concurrently on that one loop without blocking it:
use IO::Async::Loop;
my $loop = IO::Async::Loop->new;
my $ua = Fetch->new(loop => $loop); # shares this loop
my $f = $ua->get('https://example.com/');
$loop->loop_once until $f->is_ready;
my $res = $f->get;
Supported loops: the built-in Fetch::Loop::Standalone, plus Fetch::Loop::IOAsync, Fetch::Loop::AnyEvent and Fetch::Loop::Hyperman.
SEE ALSO
Fetch::Response, Fetch::Headers, Fetch::CookieJar, Fetch::WebSocket, Fetch::Future, Fetch::Loop and the loop adapters Fetch::Loop::Standalone, Fetch::Loop::IOAsync, Fetch::Loop::AnyEvent, Fetch::Loop::Hyperman.
AUTHOR
LNATION <email@lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION.
This is free software, licensed under the Artistic License 2.0.