Roles and monkeypatching Mojo::Message::Response

120 views Asked by At

I am trying to add a role to Mojo::UserAgent that handles queries to the wikidata SPARQL service.

In particular, I'd like to be able to munge the response so that the JSON that is delivered by the service is more usable.

The gist of it is that I'd like to be able to write

my $ua = Mojo::UserAgent->new->with_roles('+Wikidata');

my $tx = $ua->query($some_sparql); # ->query is defined by Mojo::UserAgent::Role::Wikidata

my $items = $tx->res->items; # this is the crux of the question

but this would mean - as far as I can tell:

  • catching transactions generated by a user agent with a Wikidata role
  • monkey-patch or add a role to the responses in those transactions

The questions are:

  1. is that a bad idea?
  2. if no, how do I do that?
3

There are 3 answers

0
brian d foy On BEST ANSWER

I'd just create a wrapper:

sub query {
    ... do whatever you need to make the request from the query ...
    my $tx = $ua->get( ... );
    ... do whatever you want to extract results ...
    }

I'd rather leave the user-agent level and the application level separate. Since your added functionally has nothing to do with being a user-agent, I don't think you should add it the user-agent object.

0
Maksym On

instead of adding a role to Mojo::UserAgent, you can create a custom wrapper as in the answer above or create a package:

package My::WikidataAgent;

use Mojo::UserAgent;
use Mojo::Base -base;

# Constructor
sub new {
    my $class = shift;
    my $self  = $class->SUPER::new(@_);
    $self->{ua} = Mojo::UserAgent->new;
    return $self;
}

# Perform a Wikidata query
sub query {
    my ($self, $sparql) = @_;
    my $tx = $self->{ua}->get($sparql);
    # Process the response here (e.g., munge JSON)
    return $tx;
}

1; 

Usage:

my $wikidata_agent = My::WikidataAgent->new;
my $tx = $wikidata_agent->query($some_sparql);
my $items = $tx->res->items;  # Process the response further
0
Rawley Fowler On

Although I think encapsulation is the best approach, you could also extend Mojo::UserAgent:

package Mojo::UserAgent::Wikidata;

use Mojo::Base 'Mojo::UserAgent';

sub query {
    my ($self, $sparql) = @_;
    # do whatever you need to make the request from the query ...
    my $response = $self->get(...);
    # do whatever you need with the response of the query...
    return $response;
}

1;