Perl Module(s) Of The Week - 2019 Week 11 - HTTP::AnyUA

In Perl, Tim Toady is a well known way of coding, which is there's more way to do it. Similarly in CPAN context, there's more modules that provides similar features. Good example is available of HTTP client or user agent modules where we have the de facto standard LWP::UserAgent, the modern non-blocking I/O and WebSocket Mojo::UserAgent, the small and tiny HTTP::Tiny, the lighting fast Furl, the event loop AnyEvent::HTTP, the legacy Curl-based wrapper Net::Curl::Easy, and numerous other modules that extend or wrap over the mentioned modules.

This the where HTTP::AnyUA module comes in. It provides a unification programming interface for all common HTTP requests based on the HTTP::Tiny interface. Think of this as the Database Independent Interface (DBI) for HTTP programming.

The installation as usual.
$ cpanm HTTP::AnyUA

Using the sample code below, we iterate using different HTTP client modules and request your truly website.
use strict;
use warnings;

use AnyEvent::HTTP;
use Furl;
use HTTP::AnyUA;
use HTTP::Tiny;
use LWP::UserAgent;
use Mojo::UserAgent;
use Net::Curl::Easy;

foreach my $ua (qw(Furl HTTP::Tiny LWP::UserAgent Mojo::UserAgent Net::Curl::Easy)) {
    my $any_ua = HTTP::AnyUA->new(ua => $ua->new, response_is_future => 1);
    print "Using: $ua\n";

    my $future = $any_ua->get('');
    $future->on_done(sub {
        my $response = shift;
        print "$response->{status} $response->{reason}\n\n";

    $future->on_fail(sub {
        my $response = shift;
        print STDERR "ERROR: $response->{status}\n\n"

Unfortunately, we can't seem to get consistent result from all different HTTP clients. This makes us wonder, while this module claimed to have unified interfaces but does it provides consistent results? If we have inconsistent HTTP response, wouldn't it be better we just use the individual HTTP client module instead?
$ perl 
Using: Furl
200 OK

Using: HTTP::Tiny
200 OK

Using: LWP::UserAgent
ERROR: 403

Using: Mojo::UserAgent
Using: Net::Curl::Easy
ERROR: 301

Nevertheless, let's continue with some code reading. Some interesting code that caught my attention.

Instead of using the environment variable, `PERL_HTTP_ANYUA_DEBUG` everywhere in the code to determine whether to print debugging info, just centralized in the logging subroutine. Good to use the environment variable to toggle this.
sub _debug_log { print STDERR join(' ', @_), "\n" if $ENV{PERL_HTTP_ANYUA_DEBUG} }
$self->_debug_log('Created with user agent', $self->ua);

The implementation on handling exception through `eval` that implement something similar like try and catch block.
my $resp = eval { $self->backend->request(uc($method) => $url, $args) };
if (my $err = [email protected]) {
    return $self->_wrap_internal_exception($err);

Check if the `_module_loader` object exists, if not just instantiate it.
# get a module loader object
sub _module_loader { shift->{_module_loader} ||= Module::Loader->new }

No comments:

Post a Comment