Rest-Client-Builder/lib/Rest/Client/Builder.pm
package Rest::Client::Builder;
use strict;
use warnings;
our $VERSION = '0.03';
our $AUTOLOAD;
sub new {
my ($class, $opts, $path) = @_;
return bless({
on_request => $opts->{on_request},
path => defined $path ? $path : '',
opts => { %$opts },
}, $class);
}
sub _construct {
my ($self, $path) = (shift, shift);
my $id = $path;
my $class = ref($self) . '::' . $path;
if (defined $self->{path}) {
$path = $self->{path} . '/' . $path;
}
if (@_) {
my $tail = '/' . join('/', @_);
$id .= $tail;
$path .= $tail;
}
unless ($self->{objects}->{$id}) {
$self->{objects}->{$id} = bless(Rest::Client::Builder->new($self->{opts}, $path), $class);
no strict 'refs';
push @{$class . '::ISA'}, 'Rest::Client::Builder';
}
return $self->{objects}->{$id};
}
sub AUTOLOAD {
my $self = shift;
(my $method = $AUTOLOAD) =~ s{.*::}{};
return undef if $method eq 'DESTROY';
no strict 'refs';
my $ref = ref($self);
*{$ref . '::' . $method} = sub {
my $self = shift;
$self->_construct($method, @_);
};
return $self->$method(@_);
}
sub get {
my $self = shift;
return $self->{on_request}->('GET', $self->{path}, @_);
}
sub post {
my $self = shift;
return $self->{on_request}->('POST', $self->{path}, @_);
}
sub put {
my $self = shift;
return $self->{on_request}->('PUT', $self->{path}, @_);
}
sub delete {
my $self = shift;
return $self->{on_request}->('DELETE', $self->{path}, @_);
}
sub patch {
my $self = shift;
return $self->{on_request}->('PATCH', $self->{path}, @_);
}
sub head {
my $self = shift;
return $self->{on_request}->('HEAD', $self->{path}, @_);
}
1;
__END__
=head1 NAME
Rest::Client::Builder - Base class to build simple object-oriented REST clients
=head1 SYNOPSIS
package Your::API;
use base qw(Rest::Client::Builder);
use JSON;
sub new {
my ($class) = @_;
my $self;
$self = $class->SUPER::new({
on_request => sub {
return $self->request(@_);
},
}, 'http://hostname/api');
return bless($self, $class);
};
sub request {
my ($self, $method, $path, $args) = @_;
return sprintf("%s %s %s\n", $method, $path, encode_json($args));
}
my $api = Your::API->new();
print $api->resource->get({ value => 1 });
# output: GET http://hostname/api/resource {"value":1}
print $api->resource(10)->post({ value => 1 });
# output: POST http://hostname/api/resource/10 {"value":1}
print $api->resource(10)->subresource('alfa', 'beta')->state->put({ value => 1 });
# output: PUT http://hostname/api/resource/10/subresource/alfa/beta/state {"value":1}
print $api->resource(10)->subresource->alfa('beta')->state->put({ value => 1 });
# output: PUT http://hostname/api/resource/10/subresource/alfa/beta/state {"value":1}
print $api->resource(10)->subresource->alfa->beta->state->put({ value => 1 });
# output: PUT http://hostname/api/resource/10/subresource/alfa/beta/state {"value":1}
print $api->resource(10)->delete();
# output: DELETE http://hostname/api/resource/10
=head1 METHODS
get put post delete patch head
=head1 ADDITIONAL ARGUMENTS
You can pass any additionals arguments to the on_request callback:
sub request {
my ($self, $method, $path, $args, $opts) = @_;
}
my $api = Your::API->new();
$api->resource->get({ value => 1 }, { timeout => 1 });
=head1 INHERITANCE
You can override any methods of any API object:
package Your::API;
use base qw(Rest::Client::Builder);
use JSON;
sub new {
my ($class) = @_;
my $self;
$self = $class->SUPER::new({
on_request => sub {
return $self->request(@_);
},
}, 'http://hostname/api');
return bless($self, $class);
};
sub request {
my ($self, $method, $path, $args) = @_;
return encode_json($args);
}
package Your::API::resource::state;
sub post {
my ($self, $args) = (shift, shift);
$args->{force} = 1;
return $self->SUPER::post($args, @_);
}
my $api = Your::API->new();
print $api->resource(1)->state->post();
# output: {"force":1}
=head1 SEE ALSO
L<WWW::REST> L<REST::Client>
=head1 SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Rest::Client::Builder
You can also look for information at:
=over
=item * Code Repository at GitHub
L<http://github.com/alexey-komarov/Rest-Client-Builder>
=item * GitHub Issue Tracker
L<http://github.com/alexey-komarov/Rest-Client-Builder/issues>
=item * RT, CPAN's request tracker
L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Rest-Client-Builder>
=back
=head1 AUTHOR
Alexey A. Komarov <alexkom@cpan.org>
=head1 COPYRIGHT
2014 Alexey A. Komarov
=head1 LICENSE
This library is free software; you may redistribute it and/or modify it under the same terms as Perl itself.
=cut