File Coverage

blib/lib/WWW/JSON.pm
Criterion Covered Total %
statement 73 82 89.0
branch 23 28 82.1
condition 9 16 56.2
subroutine 19 24 79.1
pod 6 7 85.7
total 130 157 82.8


line stmt bran cond sub pod time code
1             package WWW::JSON;
2 8     8   461760 use 5.008005;
  8         26  
  8         294  
3 8     8   36 use strict;
  8         12  
  8         214  
4 8     8   42 use warnings;
  8         9  
  8         333  
5              
6             our $VERSION = "1.01";
7 8     8   651 use LWP::UserAgent;
  8         33310  
  8         199  
8 8     8   24376 use Moo;
  8         98015  
  8         45  
9 8     8   33227 use Try::Tiny;
  8         9129  
  8         409  
10 8     8   43 use URI;
  8         12  
  8         132  
11 8     8   2993 use WWW::JSON::Response;
  8         25  
  8         280  
12 8     8   4051 use Safe::Isa;
  8         2867  
  8         953  
13 8     8   40 use JSON::XS;
  8         13  
  8         338  
14 8     8   3822 use HTTP::Request::Common;
  8         13051  
  8         9077  
15              
16             has ua => (
17             is => 'lazy',
18             handles => [qw/timeout default_header/],
19             default => sub { LWP::UserAgent->new( %{ $_[0]->ua_options } ) }
20             );
21             has base_url => (
22             is => 'rw',
23             coerce => sub {
24             my $base_url = shift;
25             my $u;
26             if ( ref($base_url) eq 'ARRAY' ) {
27             my ( $url, $params ) = @{$base_url};
28             $u = URI->new($url);
29             $u->query_form(%$params);
30             }
31             else {
32             $u = URI->new($base_url);
33             }
34             if ( my $path = $u->path ) {
35             unless ( $path =~ m|/$| ) {
36             $path =~ s|$|/|;
37             $u->path($path);
38             }
39             }
40             return $u;
41             }
42             );
43             has body_params => ( is => 'rw', default => sub { +{} } );
44             has query_params => ( is => 'rw', default => sub { +{} } );
45             has post_body_format => (
46             is => 'rw',
47             default => sub { 'serialized' },
48             clearer => 1,
49             isa => sub {
50             die "Invalid post_body_format $_[0]"
51             unless ( $_[0] eq 'serialized' || $_[0] eq 'JSON' );
52             }
53             );
54             has json =>
55             ( is => 'ro', default => sub { JSON::XS->new->utf8->allow_nonref } );
56              
57             has content_type => ( is => 'rw', clearer => 1 );
58              
59             has default_response_transform => (
60             is => 'rw',
61             clearer => 1,
62             isa => sub {
63             die "default_response_transform takes a coderef"
64             unless ref( $_[0] ) eq 'CODE';
65             }
66             );
67              
68             has ua_options => ( is => 'lazy', default => sub { +{} } );
69              
70             with 'WWW::JSON::Role::Authentication';
71             my %METHOD_DISPATCH = (
72             GET => \&HTTP::Request::Common::GET,
73             POST => \&HTTP::Request::Common::POST,
74             PUT => \&HTTP::Request::Common::PUT,
75             DELETE => \&HTTP::Request::Common::DELETE,
76             HEAD => \&HTTP::Request::Common::HEAD
77             );
78              
79 7     7 1 3301 sub get { shift->req( 'GET', @_ ) }
80 10     10 1 5272 sub post { shift->req( 'POST', @_ ) }
81 0     0 1 0 sub put { shift->req( 'PUT', @_ ) }
82 0     0 1 0 sub delete { shift->req( 'DELETE', @_ ) }
83 0     0 0 0 sub head { shift->req( 'HEAD', @_ ) }
84              
85              
86             sub _http_method_uses_post_body {
87 44     44   266 my ($self,$method) = @_;
88 44   66     276 return ($method eq 'POST' || $method eq 'PUT');
89             }
90              
91             sub req {
92 17     17 1 43 my ( $self, $method, $path, $params, $opts ) = @_;
93 17 100       68 $params = {} unless defined($params);
94 17 100       55 $opts = {} unless defined($opts);
95 17         23 my $body_params;
96 17 100       48 $body_params = { %{ $self->body_params }, %{$params} }
  10         62  
  10         30  
97             if $self->_http_method_uses_post_body($method);
98 17 100       82 ( $path, $params ) = $self->_do_templating( $path, $params )
99             if ( $path =~ /\[\%.*\%\]/ );
100 17 50 33     74 unless ( $path->$_isa('URI') && $path->scheme ) {
101 17         242 $path =~ s|^/|./|;
102 17         89 $path = URI->new($path);
103             }
104              
105 17 100       807 my $abs_uri =
106             ( $path->scheme ) ? $path : URI->new_abs( $path, $self->base_url );
107              
108 17         8982 $abs_uri->query_form(
109             $self->_determine_query_params( $method, $path, $params,
110             $opts->{query_params} )
111             );
112              
113 17         537 my $request_obj = $self->_create_request_obj( $method, $abs_uri, $body_params );
114              
115 17         5176 return $self->http_request( $request_obj);
116             }
117              
118             sub _determine_query_params {
119 17     17   41 my ( $self, $method, $path, $params, $opt_params ) = @_;
120 17         490 my %query_params = (
121             $self->base_url->query_form,
122 17 50 66     358 ($self->query_params) ? %{$self->query_params} : (),
    100          
    100          
123             $path->query_form,
124             ( $params && ! $self->_http_method_uses_post_body($method) ) ? %$params : (),
125             ($opt_params) ? (%$opt_params) : ()
126             );
127 17         73 return %query_params;
128             }
129              
130             sub _do_templating {
131 3     3   6 my ( $self, $path, $params ) = @_;
132 3         10 my %modified_params = %$params;
133 3         7 for my $key ( grep { $_ =~ /^-/ } keys(%$params) ) {
  6         40  
134 4         12 (my $search_key = $key) =~ s/^-//;
135 4 50       69 delete $modified_params{$key}
136             if ( $path =~ s/\[\%\s*$search_key\s*\%\]/$params->{$key}/g );
137             }
138 3         11 return ( $path, \%modified_params );
139             }
140              
141             sub body_param {
142 0     0 1 0 my ( $self, $k, $v ) = @_;
143 0         0 $self->body_param->{$k} = $v;
144             }
145              
146             sub _create_post_body {
147 10     10   30 my ( $self, $method, $p ) = @_;
148 10 100       117 if ( $self->post_body_format eq 'JSON' ) {
149             return (
150 1   50     22 'Content-Type' => $self->content_type || 'application/json',
151             Content => $self->json->encode($p)
152             );
153             }
154             return (
155             # If this is a POST, let HTTP::Request::Common take care of it
156             # for the sake of form uploads.
157 9 50 50     2467 Content => ($method eq 'POST') ? $p : $self->_encode_content_body($p),
158             'Content-Type' => $self->content_type || 'application/x-www-form-urlencoded'
159             );
160             }
161              
162             sub _encode_content_body {
163 0     0   0 my ($self,$p) = @_;
164 0         0 my $u = URI->new;
165 0         0 $u->query_form(%$p);
166 0         0 return $u->query;
167             }
168              
169             sub _create_request_obj {
170 17     17   38 my ( $self, $method, $uri, $p ) = @_;
171 17 50       82 my $dispatch = $METHOD_DISPATCH{$method}
172             or die "Method $method not implemented";
173              
174 17         27 my %payload;
175              
176 17 100 66     65 if ( $p && $self->_http_method_uses_post_body($method)) {
177 10         34 %payload = $self->_create_post_body($method,$p);
178             }
179 17         97 return $dispatch->( $uri->as_string, %payload );
180             }
181              
182             sub http_request {
183             my ( $self, $request_obj ) = @_;
184             my $resp = $self->ua->request($request_obj);
185              
186             return WWW::JSON::Response->new(
187             {
188             http_response => $resp,
189             _response_transform => $self->default_response_transform,
190             json => $self->json,
191             request_object => $request_obj,
192             }
193             );
194             }
195              
196             1;
197             __END__