| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Role::REST::Client; |
|
2
|
|
|
|
|
|
|
$Role::REST::Client::VERSION = '0.22'; |
|
3
|
3
|
|
|
3
|
|
486115
|
use Moo::Role; |
|
|
3
|
|
|
|
|
14468
|
|
|
|
3
|
|
|
|
|
19
|
|
|
4
|
3
|
|
|
3
|
|
5336
|
use MooX::HandlesVia; |
|
|
3
|
|
|
|
|
3949
|
|
|
|
3
|
|
|
|
|
16
|
|
|
5
|
3
|
|
|
3
|
|
1610
|
use Types::Standard qw(HashRef Str Int Enum HasMethods); |
|
|
3
|
|
|
|
|
178303
|
|
|
|
3
|
|
|
|
|
33
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
3
|
|
|
3
|
|
6153
|
use HTTP::Tiny; |
|
|
3
|
|
|
|
|
81365
|
|
|
|
3
|
|
|
|
|
114
|
|
|
8
|
3
|
|
|
3
|
|
1209
|
use URI::Escape::XS 'uri_escape'; |
|
|
3
|
|
|
|
|
5550
|
|
|
|
3
|
|
|
|
|
180
|
|
|
9
|
3
|
|
|
3
|
|
397
|
use Try::Tiny; |
|
|
3
|
|
|
|
|
935
|
|
|
|
3
|
|
|
|
|
170
|
|
|
10
|
3
|
|
|
3
|
|
21
|
use Carp qw(confess); |
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
127
|
|
|
11
|
3
|
|
|
3
|
|
442
|
use HTTP::Response; |
|
|
3
|
|
|
|
|
13016
|
|
|
|
3
|
|
|
|
|
74
|
|
|
12
|
3
|
|
|
3
|
|
16
|
use HTTP::Status 'status_message'; |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
297
|
|
|
13
|
3
|
|
|
3
|
|
21
|
use HTTP::Headers; |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
58
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
3
|
|
|
3
|
|
1154
|
use Role::REST::Client::Serializer; |
|
|
3
|
|
|
|
|
10
|
|
|
|
3
|
|
|
|
|
92
|
|
|
16
|
3
|
|
|
3
|
|
1030
|
use Role::REST::Client::Response; |
|
|
3
|
|
|
|
|
11
|
|
|
|
3
|
|
|
|
|
3527
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
has 'server' => ( |
|
19
|
|
|
|
|
|
|
isa => Str, |
|
20
|
|
|
|
|
|
|
is => 'rw', |
|
21
|
|
|
|
|
|
|
default => '', |
|
22
|
|
|
|
|
|
|
); |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
has 'type' => ( |
|
25
|
|
|
|
|
|
|
isa => Enum[qw{application/json application/xml application/yaml application/x-www-form-urlencoded}], |
|
26
|
|
|
|
|
|
|
is => 'rw', |
|
27
|
|
|
|
|
|
|
default => sub { 'application/json' }, |
|
28
|
|
|
|
|
|
|
); |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
has clientattrs => ( |
|
31
|
|
|
|
|
|
|
isa => HashRef, |
|
32
|
|
|
|
|
|
|
is => 'ro', |
|
33
|
|
|
|
|
|
|
default => sub {return {} } |
|
34
|
|
|
|
|
|
|
); |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
has user_agent => ( |
|
37
|
|
|
|
|
|
|
isa => HasMethods['request'], |
|
38
|
|
|
|
|
|
|
is => 'ro', |
|
39
|
|
|
|
|
|
|
lazy => 1, |
|
40
|
|
|
|
|
|
|
builder => '_build_user_agent', |
|
41
|
|
|
|
|
|
|
); |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub _build_user_agent { |
|
44
|
2
|
|
|
2
|
|
43
|
my $self = shift; |
|
45
|
2
|
|
|
|
|
1299
|
require HTTP::Thin; |
|
46
|
2
|
|
|
|
|
6212
|
return HTTP::Thin->new(%{$self->clientattrs}); |
|
|
2
|
|
|
|
|
52
|
|
|
47
|
|
|
|
|
|
|
} |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
has persistent_headers => ( |
|
50
|
|
|
|
|
|
|
is => 'rw', |
|
51
|
|
|
|
|
|
|
# isa => HashRef[Str], |
|
52
|
|
|
|
|
|
|
default => sub { {} }, |
|
53
|
|
|
|
|
|
|
handles_via => 'Hash', |
|
54
|
|
|
|
|
|
|
handles => { |
|
55
|
|
|
|
|
|
|
set_persistent_header => 'set', |
|
56
|
|
|
|
|
|
|
get_persistent_header => 'get', |
|
57
|
|
|
|
|
|
|
has_no_persistent_headers => 'is_empty', |
|
58
|
|
|
|
|
|
|
clear_persistent_headers => 'clear', |
|
59
|
|
|
|
|
|
|
}, |
|
60
|
|
|
|
|
|
|
); |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
has _httpheaders => ( |
|
63
|
|
|
|
|
|
|
is => 'rw', |
|
64
|
|
|
|
|
|
|
isa => HashRef[Str], |
|
65
|
|
|
|
|
|
|
init_arg => 'httpheaders', |
|
66
|
|
|
|
|
|
|
default => sub { {} }, |
|
67
|
|
|
|
|
|
|
handles_via => 'Hash', |
|
68
|
|
|
|
|
|
|
handles => { |
|
69
|
|
|
|
|
|
|
set_header => 'set', |
|
70
|
|
|
|
|
|
|
get_header => 'get', |
|
71
|
|
|
|
|
|
|
exist_header => 'exists', |
|
72
|
|
|
|
|
|
|
has_no_headers => 'is_empty', |
|
73
|
|
|
|
|
|
|
clear_headers => 'clear', |
|
74
|
|
|
|
|
|
|
reset_headers => 'clear', |
|
75
|
|
|
|
|
|
|
}, |
|
76
|
|
|
|
|
|
|
); |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub httpheaders { |
|
79
|
20
|
|
|
20
|
1
|
10167
|
my $self = shift; |
|
80
|
20
|
|
|
|
|
39
|
return { %{$self->persistent_headers}, %{$self->_httpheaders} }; |
|
|
20
|
|
|
|
|
99
|
|
|
|
20
|
|
|
|
|
389
|
|
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub clear_all_headers { |
|
84
|
1
|
|
|
1
|
0
|
1201
|
my $self = shift; |
|
85
|
1
|
|
|
|
|
37
|
$self->clear_headers; |
|
86
|
1
|
|
|
|
|
111
|
$self->clear_persistent_headers; |
|
87
|
1
|
|
|
|
|
103
|
return {}; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
has serializer_class => ( |
|
91
|
|
|
|
|
|
|
isa => Str, |
|
92
|
|
|
|
|
|
|
is => 'ro', |
|
93
|
|
|
|
|
|
|
default => sub { 'Role::REST::Client::Serializer' }, |
|
94
|
|
|
|
|
|
|
); |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
has serializer_options => ( |
|
97
|
|
|
|
|
|
|
isa => HashRef, |
|
98
|
|
|
|
|
|
|
is => 'ro', |
|
99
|
|
|
|
|
|
|
default => sub { return {} }, |
|
100
|
|
|
|
|
|
|
); |
|
101
|
|
|
|
|
|
|
|
|
102
|
11
|
|
|
11
|
|
298
|
sub _rest_response_class { 'Role::REST::Client::Response' } |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# If the response is a hashref, we expect it to be in the format returned by |
|
105
|
|
|
|
|
|
|
# HTTP::Tiny->request() and convert it to an HTTP::Response object. Otherwise, |
|
106
|
|
|
|
|
|
|
# pass the response through unmodified. |
|
107
|
|
|
|
|
|
|
sub _handle_response { |
|
108
|
12
|
|
|
12
|
|
38799
|
my ( $self, $res ) = @_; |
|
109
|
12
|
50
|
|
|
|
53
|
if ( ref $res eq 'HASH' ) { |
|
110
|
0
|
|
|
|
|
0
|
my $code = $res->{'status'}; |
|
111
|
|
|
|
|
|
|
return HTTP::Response->new( |
|
112
|
|
|
|
|
|
|
$code, |
|
113
|
|
|
|
|
|
|
$res->{'reason'} || status_message($code), |
|
114
|
0
|
|
|
|
|
0
|
HTTP::Headers->new(%{$res->{'headers'}}), |
|
115
|
0
|
|
0
|
|
|
0
|
$res->{'content'}, |
|
116
|
|
|
|
|
|
|
); |
|
117
|
|
|
|
|
|
|
} else { |
|
118
|
12
|
|
|
|
|
37
|
return $res; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub _new_rest_response { |
|
123
|
12
|
|
|
12
|
|
444
|
my ($self, @args) = @_; |
|
124
|
12
|
|
|
|
|
51
|
return $self->_rest_response_class->new(@args); |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub new_serializer { |
|
128
|
1
|
|
|
1
|
0
|
8
|
my ($self, @args) = @_; |
|
129
|
1
|
|
|
|
|
3
|
my %args = (%{ $self->serializer_options }, @args); |
|
|
1
|
|
|
|
|
13
|
|
|
130
|
1
|
|
|
|
|
23
|
$self->serializer_class->new(%args); |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub _serializer { |
|
134
|
3
|
|
|
3
|
|
10
|
my ($self, $type) = @_; |
|
135
|
3
|
|
33
|
|
|
26
|
$type ||= $self->type; |
|
136
|
3
|
|
|
|
|
11
|
$type =~ s/;\s*?charset=.+$//i; #remove stuff like ;charset=utf8 |
|
137
|
|
|
|
|
|
|
try { |
|
138
|
3
|
|
66
|
3
|
|
329
|
$self->{serializer}{$type} ||= $self->new_serializer(type => $type); |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
catch { |
|
141
|
|
|
|
|
|
|
# Deal with real life content types like "text/xml;charset=ISO-8859-1" |
|
142
|
0
|
|
|
0
|
|
0
|
warn "No serializer available for " . $type . " content. Trying default " . $self->type; |
|
143
|
0
|
|
|
|
|
0
|
$self->{serializer}{$type} = $self->new_serializer(type => $self->type); |
|
144
|
3
|
|
|
|
|
107
|
}; |
|
145
|
3
|
|
|
|
|
3303
|
return $self->{serializer}{$type}; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub do_request { |
|
149
|
12
|
|
|
12
|
0
|
50
|
my ($self, $method, $uri, $opts) = @_; |
|
150
|
12
|
|
|
|
|
221
|
return $self->user_agent->request($method, $uri, $opts); |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub _call { |
|
154
|
12
|
|
|
12
|
|
37
|
my ($self, $method, $endpoint, $data, $args) = @_; |
|
155
|
12
|
|
|
|
|
290
|
my $uri = $self->server . $endpoint; |
|
156
|
|
|
|
|
|
|
# If no data, just call endpoint (or uri if GET w/parameters) |
|
157
|
|
|
|
|
|
|
# If data is a scalar, call endpoint with data as content (POST w/parameters) |
|
158
|
|
|
|
|
|
|
# Otherwise, encode data |
|
159
|
12
|
|
|
|
|
314
|
$self->set_header('content-type', $self->type); |
|
160
|
12
|
|
|
|
|
1831
|
my %options = (headers => $self->httpheaders); |
|
161
|
12
|
100
|
|
|
|
166
|
if ( defined $data ) { |
|
162
|
4
|
50
|
|
|
|
14
|
$options{content} = ref $data ? $self->_serializer->serialize($data) : $data; |
|
163
|
4
|
|
|
|
|
12
|
$options{'headers'}{'content-length'} = length($options{'content'}); |
|
164
|
|
|
|
|
|
|
} |
|
165
|
12
|
|
|
|
|
57
|
my $res = $self->_handle_response( $self->do_request($method, $uri, \%options) ); |
|
166
|
|
|
|
|
|
|
|
|
167
|
12
|
50
|
|
|
|
364
|
$self->reset_headers unless $args->{preserve_headers}; |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
my $use_serializer = exists $args->{deserializer} |
|
170
|
12
|
100
|
|
|
|
788
|
? defined $args->{deserializer} ? 1 : 0 |
|
|
|
100
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
: $res->header('Content-Type') !~ m{(?:text/(?:plain|html)|application/octet-stream)}; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
my $deserializer_cb = sub { |
|
174
|
|
|
|
|
|
|
# Try to find a serializer for the result content |
|
175
|
3
|
|
66
|
3
|
|
498
|
my $content_type = $args->{deserializer} || $res->header('Content-Type'); |
|
176
|
3
|
|
|
|
|
56
|
my $deserializer = $self->_serializer($content_type); |
|
177
|
|
|
|
|
|
|
# Try to deserialize |
|
178
|
3
|
|
|
|
|
14
|
my $content = $res->decoded_content; |
|
179
|
3
|
50
|
33
|
|
|
1076
|
$content = $deserializer->deserialize($content) if $deserializer && $content; |
|
180
|
3
|
|
50
|
|
|
40
|
$content ||= {}; |
|
181
|
12
|
|
|
|
|
630
|
}; |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
return $self->_new_rest_response( |
|
184
|
|
|
|
|
|
|
code => $res->code, |
|
185
|
|
|
|
|
|
|
response => $res, |
|
186
|
|
|
|
|
|
|
data => $use_serializer |
|
187
|
3
|
|
|
3
|
|
5814
|
? $deserializer_cb : sub { $res->decoded_content }, |
|
188
|
12
|
100
|
|
|
|
55
|
$res->is_error ? ( error => $res->message) : (), |
|
|
|
100
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
); |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub _urlencode_data { |
|
193
|
5
|
|
|
5
|
|
14
|
my ($self, $data) = @_; |
|
194
|
5
|
|
|
|
|
13
|
return join '&', map { uri_escape($_) . '=' . uri_escape($data->{$_})} keys %$data; |
|
|
6
|
|
|
|
|
56
|
|
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
sub _request_with_query { |
|
198
|
8
|
|
|
8
|
|
36
|
my ($self, $method, $endpoint, $data, $args) = @_; |
|
199
|
8
|
|
|
|
|
21
|
my $uri = $endpoint; |
|
200
|
8
|
50
|
100
|
|
|
48
|
if ($data && scalar keys %$data) { |
|
201
|
1
|
|
|
|
|
3
|
$uri .= '?' . $self->_urlencode_data($data); |
|
202
|
|
|
|
|
|
|
} |
|
203
|
8
|
|
|
|
|
61
|
return $self->_call($method, $uri, undef, $args); |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
|
|
206
|
8
|
|
|
8
|
0
|
11808
|
sub get { return shift->_request_with_query('GET', @_) } |
|
207
|
|
|
|
|
|
|
|
|
208
|
0
|
|
|
0
|
0
|
0
|
sub head { return shift->_request_with_query('HEAD', @_) } |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub _request_with_body { |
|
211
|
4
|
|
|
4
|
|
12
|
my ($self, $method, $endpoint, $data, $args) = @_; |
|
212
|
4
|
|
|
|
|
9
|
my $content = $data; |
|
213
|
4
|
50
|
|
|
|
89
|
if ( $self->type =~ /urlencoded/ ) { |
|
214
|
4
|
50
|
50
|
|
|
74
|
$content = ( $data && scalar keys %$data ) ? $self->_urlencode_data($data) : q{}; |
|
215
|
|
|
|
|
|
|
} |
|
216
|
4
|
|
|
|
|
119
|
return $self->_call($method, $endpoint, $content, $args); |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
|
|
219
|
4
|
|
|
4
|
0
|
3063
|
sub post { return shift->_request_with_body('POST', @_) } |
|
220
|
|
|
|
|
|
|
|
|
221
|
0
|
|
|
0
|
0
|
|
sub put { return shift->_request_with_body('PUT', @_) } |
|
222
|
|
|
|
|
|
|
|
|
223
|
0
|
|
|
0
|
0
|
|
sub options { return shift->_request_with_body('OPTIONS', @_) } |
|
224
|
|
|
|
|
|
|
|
|
225
|
0
|
|
|
0
|
0
|
|
sub delete { return shift->_request_with_query('DELETE', @_) } |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
1; |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=pod |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=encoding UTF-8 |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=head1 NAME |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Role::REST::Client - REST Client Role |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=head1 VERSION |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
version 0.22 |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
{ |
|
244
|
|
|
|
|
|
|
package RESTExample; |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
use Moose; |
|
247
|
|
|
|
|
|
|
with 'Role::REST::Client'; |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub bar { |
|
250
|
|
|
|
|
|
|
my ($self) = @_; |
|
251
|
|
|
|
|
|
|
my $res = $self->post('/foo/bar/baz', {foo => 'bar'}); |
|
252
|
|
|
|
|
|
|
my $code = $res->code; |
|
253
|
|
|
|
|
|
|
my $data = $res->data; |
|
254
|
|
|
|
|
|
|
return $data if $code == 200; |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
} |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
my $foo = RESTExample->new( |
|
260
|
|
|
|
|
|
|
server => 'http://localhost:3000', |
|
261
|
|
|
|
|
|
|
type => 'application/json', |
|
262
|
|
|
|
|
|
|
clientattrs => {timeout => 5}, |
|
263
|
|
|
|
|
|
|
); |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
$foo->bar; |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# controller |
|
268
|
|
|
|
|
|
|
sub foo : Local { |
|
269
|
|
|
|
|
|
|
my ($self, $c) = @_; |
|
270
|
|
|
|
|
|
|
my $res = $c->model('MyData')->post('/foo/bar/baz', {foo => 'bar'}); |
|
271
|
|
|
|
|
|
|
my $code = $res->code; |
|
272
|
|
|
|
|
|
|
my $data = $res->data; |
|
273
|
|
|
|
|
|
|
... |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
This REST Client role makes REST connectivity easy. |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
Role::REST::Client will handle encoding and decoding when using the HTTP verbs. |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
GET |
|
283
|
|
|
|
|
|
|
HEAD |
|
284
|
|
|
|
|
|
|
PUT |
|
285
|
|
|
|
|
|
|
POST |
|
286
|
|
|
|
|
|
|
DELETE |
|
287
|
|
|
|
|
|
|
OPTIONS |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
Currently Role::REST::Client supports these encodings |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
application/json |
|
292
|
|
|
|
|
|
|
application/x-www-form-urlencoded |
|
293
|
|
|
|
|
|
|
application/xml |
|
294
|
|
|
|
|
|
|
application/yaml |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
x-www-form-urlencoded only works for GET and POST, and only for encoding, not decoding. |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
Responses which claim to not be serialised data (eg C<text/plain>, |
|
299
|
|
|
|
|
|
|
C<application/octet-stream>) will by default not be serialised. When the |
|
300
|
|
|
|
|
|
|
response is none of these, and it is impossible to determine what encoding is |
|
301
|
|
|
|
|
|
|
used, the content will be treated as JSON by default. |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=head1 NAME |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
Role::REST::Client - REST Client Role |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=head1 METHODS |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=head2 methods |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
Role::REST::Client implements the standard HTTP 1.1 verbs as methods |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
These methods can NOT have a request body |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
get |
|
316
|
|
|
|
|
|
|
head |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
These methods can take a request body. |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
post |
|
321
|
|
|
|
|
|
|
put |
|
322
|
|
|
|
|
|
|
delete |
|
323
|
|
|
|
|
|
|
options |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
All methods take these parameters |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
url - The REST service |
|
328
|
|
|
|
|
|
|
data - The data structure (hashref, arrayref) to send. The data will be encoded |
|
329
|
|
|
|
|
|
|
according to the value of the I<type> attribute. |
|
330
|
|
|
|
|
|
|
args - hashref with arguments to augment the way the call is handled. |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
args - the optional argument parameter can have these entries |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
deserializer - if you KNOW that the content-type of the response is incorrect, |
|
335
|
|
|
|
|
|
|
you can supply the correct content type, like |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
my $res = $self->post('/foo/bar/baz', {foo => 'bar'}, {deserializer => 'application/yaml'}); |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Alternatively, if you KNOW that the response is not serial data, you can |
|
340
|
|
|
|
|
|
|
disable deserialization by setting this to undef. |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
preserve_headers - set this to true if you want to keep the headers between calls |
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
All methods return a response object dictated by _rest_response_class. Set to L<Role::REST::Client::Response> by default. |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=head2 user_agent |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub _build_user_agent { HTTP::Thin->new } |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
A User Agent object which has a C<< ->request >> method suitably compatible with L<HTTP::Tiny>. It should accept arguments like this: C<< $ua->request($method, $uri, $opts) >>, and needs to return a hashref as HTTP::Tiny does, or an L<HTTP::Response> object. To set your own default, use a C<_build_user_agent> method. |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=head2 server |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
URL of the REST server. |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
e.g. 'http://localhost:3000' |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
=head2 type |
|
361
|
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
MIME Content-Type header, |
|
363
|
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
e.g. application/json |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=head2 persistent_headers |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
$self->set_persistent_header('Header' => 'foo', ... ); |
|
369
|
|
|
|
|
|
|
$self->get_persistent_header('Header-Name'); |
|
370
|
|
|
|
|
|
|
$self->has_no_persistent_headers; |
|
371
|
|
|
|
|
|
|
$self->clear_persistent_headers; |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
A hashref containing headers you want to use for all requests. Use the methods |
|
374
|
|
|
|
|
|
|
described above to manipulate it. |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
To set your own defaults, override the default or call C<set_persistent_header()> in your |
|
377
|
|
|
|
|
|
|
C<BUILD> method. |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
has '+persistent_headers' => ( |
|
380
|
|
|
|
|
|
|
default => sub { ... }, |
|
381
|
|
|
|
|
|
|
); |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=head2 httpheaders |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
$self->set_header('Header' => 'foo', ... ); |
|
386
|
|
|
|
|
|
|
$self->get_header('Header-Name'); |
|
387
|
|
|
|
|
|
|
$self->has_no_headers; |
|
388
|
|
|
|
|
|
|
$self->clear_headers; |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
You can set any http header you like with set_header, e.g. |
|
391
|
|
|
|
|
|
|
$self->set_header($key, $value) but the content-type header will be overridden. |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
http_headers will be reset after each request, unless there's a reserve_headers |
|
394
|
|
|
|
|
|
|
argument, but it's a hack. The recommended way to keep headers across requests |
|
395
|
|
|
|
|
|
|
is to store them in the persistent_headers. |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
$self->httpheaders will return the combined hashref of persistent_headers and |
|
398
|
|
|
|
|
|
|
what's been added with set_header. |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
For historical reasons, the two methods clear_headers and reset_headers are |
|
401
|
|
|
|
|
|
|
equal. Both will clear the headers for the current request, but NOT the |
|
402
|
|
|
|
|
|
|
persistent headers. |
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
To clear ALL headers, use |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
$self->clear_all_headers; |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=head2 clientattrs |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
Attributes to feed the user agent object (which defaults to L<HTTP::Thin>) |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
e.g. {timeout => 10} |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=head2 serializer_class |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
You can override the serializer class and use your own. Default is 'Role::REST::Client::Serializer' |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=head2 serializer_options |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
Options for the serializer instantiation. |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=head1 CONTRIBUTORS |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
Breno G. de Oliveira, <garu@cpan.org> |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
Mark Stosberg, <mark@stosberg.com> |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
Matt Phillips, (cpan:MATTP) <mattp@cpan.org> |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
Wallace Reis, <wallace@reis.me> |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=head1 BUGS |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
Please report any bugs or feature requests to bug-role-rest-client at rt.cpan.org, or through the |
|
435
|
|
|
|
|
|
|
web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Role-REST-Client. |
|
436
|
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=head1 AUTHOR |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
Kaare Rasmussen <kaare at cpan dot org> |
|
440
|
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
This software is copyright (c) 2017 by Kaare Rasmussen. |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
446
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
=cut |
|
449
|
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
__END__ |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# ABSTRACT: REST Client Role |
|
453
|
|
|
|
|
|
|
|