Mojolicious

 view release on metacpan or  search on metacpan

lib/Mojolicious/Guides/Cookbook.pod  view on Meta::CPAN

  my $url = Mojo::URL->new('http://fastapi.metacpan.org/v1/release/_search');
  $url->query({q => 'mojolicious', sort => 'date:desc'});
  for my $hit (@{$ua->get($url)->result->json->{hits}{hits}}) {
    say "$hit->{_source}{name} ($hit->{_source}{author})";
  }

=head2 Basic authentication

You can just add username and password to the URL, an C<Authorization> header will be automatically generated.

  use Mojo::UserAgent;

  my $ua = Mojo::UserAgent->new;
  say $ua->get('https://sri:secret@example.com/hideout')->result->body;

If you're using L<Mojo::URL> to build the URL, be aware that the userinfo part will not be included if the object is
stringified. You'll have to pass the object itself to L<Mojo::UserAgent> or use L<Mojo::URL/"to_unsafe_string">.

  use Mojo::UserAgent;
  use Mojo::URL;

  my $ua  = Mojo::UserAgent->new;
  my $url = Mojo::URL->new('https://example.com/hideout')->userinfo('sri:secret');
  say $ua->get($url)->result->body;

=head2 Decorating follow-up requests

L<Mojo::UserAgent> can automatically follow redirects, the event L<Mojo::UserAgent/"start"> allows you direct access to
each transaction right after they have been initialized and before a connection gets associated with them.

  use Mojo::UserAgent;

  # User agent following up to 10 redirects
  my $ua = Mojo::UserAgent->new(max_redirects => 10);

  # Add a witty header to every request
  $ua->on(start => sub ($ua, $tx) {
    $tx->req->headers->header('X-Bender' => 'Bite my shiny metal ass!');
    say 'Request: ', $tx->req->url->clone->to_abs;
  });

  # Request that will most likely get redirected
  say 'Title: ', $ua->get('google.com')->result->dom->at('head > title')->text;

This even works for proxy C<CONNECT> requests.

=head2 Content generators

Content generators can be registered with L<Mojo::UserAgent::Transactor/"add_generator"> to generate the same type of
content repeatedly for multiple requests.

  use Mojo::UserAgent;
  use Mojo::Asset::File;

  # Add "stream" generator
  my $ua = Mojo::UserAgent->new;
  $ua->transactor->add_generator(stream => sub ($transactor, $tx, $path) {
    $tx->req->content->asset(Mojo::Asset::File->new(path => $path));
  });

  # Send multiple files streaming via PUT and POST
  $ua->put('http://example.com/upload'  => stream => '/home/sri/mojo.png');
  $ua->post('http://example.com/upload' => stream => '/home/sri/minion.png');

The C<json>, C<form> and C<multipart> content generators are always available.

  use Mojo::UserAgent;

  # Send "application/json" content via PATCH
  my $ua = Mojo::UserAgent->new;
  my $tx = $ua->patch('http://api.example.com' => json => {foo => 'bar'});

  # Send query parameters via GET
  my $tx2 = $ua->get('search.example.com' => form => {q => 'test'});

  # Send "application/x-www-form-urlencoded" content via POST
  my $tx3 = $ua->post('http://search.example.com' => form => {q => 'test'});

  # Send "multipart/form-data" content via PUT
  my $tx4 = $ua->put('upload.example.com' => form => {test => {content => 'Hello World!'}});

  # Send custom multipart content via PUT
  my $tx5 = $ua->put('api.example.com' => multipart => ['Hello', 'World!']);

For more information about available content generators see also L<Mojo::UserAgent::Transactor/"tx">.

=head2 Large file downloads

When downloading large files with L<Mojo::UserAgent> you don't have to worry about memory usage at all, because it will
automatically stream everything above 250KiB into a temporary file, which can then be moved into a permanent file with
L<Mojo::Message/"save_to">.

  use Mojo::UserAgent;

  # Fetch the latest Mojolicious tarball
  my $ua = Mojo::UserAgent->new(max_redirects => 5);
  my $tx = $ua->get('https://www.github.com/mojolicious/mojo/tarball/main');
  $tx->result->save_to('mojo.tar.gz');

With L<Mojo::File/"download"> you can also stream file downloads directly into the target file. This allows for
interrupted downloads to be resumed at a later time.

  use Mojo::File qw(path);

  # Download the latest Mojolicious tarball directly into a file
  path('/home/sri/mojo.tar.gz')->download('https://www.github.com/mojolicious/mojo/tarball/main');

To protect you from excessively large files there is also a limit of 2GiB by default, which you can tweak with the
attribute L<Mojo::UserAgent/"max_response_size">.

  # Increase limit to 10GiB
  $ua->max_response_size(10737418240);

=head2 Large file upload

Uploading a large file is even easier.

  use Mojo::UserAgent;

  # Upload file via POST and "multipart/form-data"
  my $ua = Mojo::UserAgent->new;
  $ua->post('example.com/upload' => form => {image => {file => '/home/sri/hello.png'}});

And once again you don't have to worry about memory usage, all data will be streamed directly from the file.

=head2 Streaming response

Receiving a streaming response can be really tricky in most HTTP clients, but L<Mojo::UserAgent> makes it actually
easy.

  use Mojo::UserAgent;

  # Accept responses of indefinite size
  my $ua = Mojo::UserAgent->new(max_response_size => 0);

  # Build a normal transaction
  my $tx = $ua->build_tx(GET => 'http://example.com');

  # Replace "read" events to disable default content parser
  $tx->res->content->unsubscribe('read')->on(read => sub ($content, $bytes) {
    say "Streaming: $bytes";
  });

  # Process transaction
  $tx = $ua->start($tx);

The event L<Mojo::Content/"read"> will be emitted for every chunk of data that is received, even chunked transfer
encoding and gzip content encoding will be handled transparently if necessary.

=head2 Streaming request

Sending a streaming request is almost just as easy.

  use Mojo::UserAgent;

  # Build a normal transaction
  my $ua = Mojo::UserAgent->new;
  my $tx = $ua->build_tx(POST => 'http://example.com');

  # Prepare body
  my $body = 'Hello World!';
  $tx->req->headers->content_length(length $body);

  # Start writing directly with a drain callback
  my $drain = sub ($content) {
    my $chunk = substr $body, 0, 1, '';
    $content->write($chunk, length $body ? __SUB__ : undef);
  };
  $tx->req->content->$drain;

  # Process transaction
  $tx = $ua->start($tx);

The drain callback passed to L<Mojo::Content/"write"> will be executed whenever the entire previous chunk of data has
actually been written.

=head2 Non-blocking

L<Mojo::UserAgent> has been designed from the ground up to be non-blocking, the whole blocking API is just a simple
convenience wrapper. Especially for high latency tasks like web crawling this can be extremely useful, because you can
keep many concurrent connections active at the same time.

  use Mojo::UserAgent;
  use Mojo::IOLoop;

  # Concurrent non-blocking requests
  my $ua = Mojo::UserAgent->new;
  $ua->get('https://metacpan.org/search?q=mojo' => sub ($ua, $mojo) {
    say $mojo->result->dom->at('title')->text;
  });
  $ua->get('https://metacpan.org/search?q=minion' => sub ($ua, $minion) {
    say $minion->result->dom->at('title')->text;
  });

  # Start event loop if necessary
  Mojo::IOLoop->start unless Mojo::IOLoop->is_running;

But don't try to open too many connections to one server at the same time, it might get overwhelmed. Better use a queue
to process requests in smaller batches.

  use Mojo::Promise;
  use Mojo::UserAgent;

  my @urls = (
    'https://docs.mojolicious.org/Mojo/DOM',  'https://docs.mojolicious.org/Mojo',
    'https://docs.mojolicious.org/Mojo/File', 'https://docs.mojolicious.org/Mojo/URL'
  );

  # User agent with a custom name, following up to 5 redirects
  my $ua = Mojo::UserAgent->new(max_redirects => 5);
  $ua->transactor->name('MyParallelCrawler 1.0');



( run in 0.891 second using v1.01-cache-2.11-cpan-5a3173703d6 )