WWW-GoDaddy-REST/lib/WWW/GoDaddy/REST/Util.pm
package WWW::GoDaddy::REST::Util;
use strict;
use warnings;
use JSON qw();
use Sub::Exporter -setup => {
exports => [
qw( abs_url
add_filters_to_url
build_complex_query_url
is_json
json_decode
json_encode
json_instance
)
]
};
use URI;
use URI::QueryParam;
sub is_json {
my $json = shift;
my $handler = json_instance(@_);
eval { my $perl = json_decode($json); };
if ($@) {
return 0;
}
else {
return 1;
}
}
sub json_encode {
my $perl = shift;
my $handler = json_instance(@_);
return $handler->encode($perl);
}
sub json_decode {
my $json = shift;
my $handler = json_instance(@_);
return $handler->decode($json);
}
sub json_instance {
my $inst = JSON->new;
if ( @_ == 1 && UNIVERSAL::isa( $_[0], "JSON" ) ) {
return $_[0];
}
elsif (@_) {
while ( my ( $key, $value ) = each %{@_} ) {
$inst->property( $key => $value );
}
}
else {
$inst->convert_blessed(1);
$inst->allow_nonref(1);
}
return $inst;
}
sub abs_url {
my $api_base = shift;
my $url = shift;
$url =~ s|^/||;
$api_base =~ s|/*$|/|;
return URI->new_abs( $url, $api_base );
}
sub add_filters_to_url {
my ( $url, $filters ) = @_;
my $uri = URI->new($url);
foreach my $field ( sort keys %{$filters} ) {
my $field_filters = $filters->{$field};
next unless $field_filters;
if ( ref($field_filters) eq 'ARRAY' ) {
# a query could look like so:
# {
# 'myField' => [
# { modifier => 'ne', value => 'apple' },
# { value => 'orange' } # implicit 'eq'
# ]
# }
foreach my $filter ( @{$field_filters} ) {
my $modifier = $filter->{modifier} || 'eq';
my $value = $filter->{value};
if ( $modifier eq 'eq' ) {
$uri->query_param_append( $field => $value );
}
else {
$uri->query_param_append( sprintf( '%s_%s', $field, $modifier ) => $value );
}
}
}
else {
# a query could look like so:
# {
# 'myField' => 'apple'
# }
$uri->query_param_append( $field => $field_filters );
}
}
return $uri->as_string;
}
sub build_complex_query_url {
my ( $url, $filter, $params ) = @_;
$filter ||= {};
$params ||= {};
$url = add_filters_to_url( $url, $filter );
if ( exists $params->{'sort'} ) {
$params->{'order'} ||= 'asc';
}
my $uri = URI->new($url);
while ( my ( $key, $value ) = each %{$params} ) {
$uri->query_param( $key => $value );
}
return $uri->as_string;
}
1;
=head1 NAME
WWW::GoDaddy::REST::Util - Mostly URL tweaking utilities for this package
=head1 SYNOPSIS
use WWW::GoDaddy::REST::Util qw/ abs_url add_filters_to_url /;
# http://example.com/v1/asdf
abs_url('http://example.com/v1','/asdf');
# http://example.com?sort=asc&fname=Fred
add_filters_to_url('http://example.com?sort=asc',{ 'fname' => [ { 'value': 'Fred' } ] });
=head1 DESCRIPTION
Utilities used commonly in this package. Most have to do with URL manipulation.
=head1 FUNCTIONS
=over 4
=item is_json
Given a json string, return true if it is parsable, false otherwise.
If you need to control the parameters to the L<JSON> module, simply
pass additional parameters. These will be passed unchanged to C<json_instance>.
Example:
my $yes = is_json('"asdf"');
my $yes = is_json('{"key":"value"}');
my $no = is_json('dafsafsadfsdaf');
=item json_decode
Given a json string, return the perl data structure. This will C<die()> if it
can not be parsed.
If you need to control the parameters to the L<JSON> module, simply
pass additional parameters. These will be passed unchanged to C<json_instance>.
Example:
my $hashref = json_decode('{"key":"value"}');
=item json_encode
Given a perl data structure, return the json string. This will C<die()> if it
can not be serialized.
If you need to control the parameters to the L<JSON> module, simply
pass additional parameters. These will be passed unchanged to C<json_instance>.
Example:
my $json = json_encode({ 'key' => 'value' });
=item json_instance
Returns C<JSON> instance. If no parameters are given the following
defaults are set: C<convert_blessed>, C<allow_nonref>.
If called with one parameter, it is assumed to be a C<JSON> instance
and this is returned instead of building a new one.
If called with more than one parameter, it is assumed to be key/value
pairs and will be passed to the JSON C<property> method two by two.
Example:
$j = json_instance(); #defaults
$j = json_instance( JSON->new ); #pass through
$j = json_instance( 'convert_blessed' => 1, 'allow_nonref' => 1 ); # set properies
=item abs_url
Given a base and path fragment, generate an absolute url with the two
joined.
Example:
# http://example.com/v1/asdf
abs_url('http://example.com/v1','/asdf');
=item add_filters_to_url
Given a url and a query filter, generate a url with the filter
query parameters added.
Filter syntax can be seen in the docs for L<WWW::GoDaddy::REST>.
Example:
add_filters_to_url('http://example.com?sort=asc',{ 'fname' => [ { 'value': 'Fred' } ] });
# http://example.com?sort=asc&fname=Fred
=item build_complex_query_url
Return a modified URL string given a URL, an optional filter spec, and optional
query parameter hash.
If you specify a sort, then an order parameter will be filled in if not present, and
and sort or order query parameters in the input string will be replaced.
All other query parameters (filters etc) will be appended to the query parameters
of the input URL instead of replacing.
Example:
build_complex_query_url(
'http://example.com',
{
'foo' => 'bar'
},
{
'sort' => 'surname'
}
);
# http://example.com?foo=bar&sort=surname&order=asc
=back
=head1 EXPORTS
None by default.
=head1 AUTHOR
David Bartle, C<< <davidb@mediatemple.net> >>
=head1 COPYRIGHT & LICENSE
Copyright (c) 2014 Go Daddy Operating Company, LLC
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
=cut