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   608641 use 5.008005;
  8         30  
  8         344  
3 8     8   41 use strict;
  8         14  
  8         270  
4 8     8   53 use warnings;
  8         11  
  8         479  
5              
6             our $VERSION = "1.02";
7 8     8   951 use LWP::UserAgent;
  8         53859  
  8         281  
8 8     8   5680 use Moo;
  8         115072  
  8         53  
9 8     8   17026 use Try::Tiny;
  8         10646  
  8         481  
10 8     8   54 use URI;
  8         11  
  8         176  
11 8     8   3118 use WWW::JSON::Response;
  8         28  
  8         346  
12 8     8   4951 use Safe::Isa;
  8         3316  
  8         1042  
13 8     8   46 use JSON::XS;
  8         12  
  8         404  
14 8     8   4471 use HTTP::Request::Common;
  8         17181  
  8         12078  
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 4050 sub get { shift->req( 'GET', @_ ) }
80 10     10 1 3932 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   342 my ($self,$method) = @_;
88 44   66     328 return ($method eq 'POST' || $method eq 'PUT');
89             }
90              
91             sub req {
92 17     17 1 49 my ( $self, $method, $path, $params, $opts ) = @_;
93 17 100       71 $params = {} unless defined($params);
94 17 100       54 $opts = {} unless defined($opts);
95 17 100       104 ( $path, $params ) = $self->_do_templating( $path, $params )
96             if ( $path =~ /\[\%.*\%\]/ );
97 17         22 my $body_params;
98 17 100       60 $body_params = { %{ $self->body_params }, %{$params} }
  10         76  
  10         33  
99             if $self->_http_method_uses_post_body($method);
100 17 50 33     96 unless ( $path->$_isa('URI') && $path->scheme ) {
101 17         285 $path =~ s|^/|./|;
102 17         106 $path = URI->new($path);
103             }
104              
105 17 100       928 my $abs_uri =
106             ( $path->scheme ) ? $path : URI->new_abs( $path, $self->base_url );
107              
108 17         11070 $abs_uri->query_form(
109             $self->_determine_query_params( $method, $path, $params,
110             $opts->{query_params} )
111             );
112              
113 17         564 my $request_obj = $self->_create_request_obj( $method, $abs_uri, $body_params );
114              
115 17         6186 return $self->http_request( $request_obj);
116             }
117              
118             sub _determine_query_params {
119 17     17   49 my ( $self, $method, $path, $params, $opt_params ) = @_;
120 17         598 my %query_params = (
121             $self->base_url->query_form,
122 17 50 66     433 ($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         76 return %query_params;
128             }
129              
130             sub _do_templating {
131 3     3   8 my ( $self, $path, $params ) = @_;
132 3         19 my %modified_params = %$params;
133 3         14 for my $key ( grep { $_ =~ /^-/ } keys(%$params) ) {
  6         28  
134 4         21 (my $search_key = $key) =~ s/^-//;
135 4 50       107 delete $modified_params{$key}
136             if ( $path =~ s/\[\%\s*$search_key\s*\%\]/$params->{$key}/g );
137             }
138 3         19 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   18 my ( $self, $method, $p ) = @_;
148 10 100       126 if ( $self->post_body_format eq 'JSON' ) {
149             return (
150 1   50     32 '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     3041 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   33 my ( $self, $method, $uri, $p ) = @_;
171 17 50       77 my $dispatch = $METHOD_DISPATCH{$method}
172             or die "Method $method not implemented";
173              
174 17         29 my %payload;
175              
176 17 100 66     74 if ( $p && $self->_http_method_uses_post_body($method)) {
177 10         41 %payload = $self->_create_post_body($method,$p);
178             }
179 17         115 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__