line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Catalyst::TraitFor::Request::QueryFromJSONY; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
388415
|
use Moo::Role; |
|
2
|
|
|
|
|
56430
|
|
|
2
|
|
|
|
|
15
|
|
4
|
2
|
|
|
2
|
|
5480
|
use JSONY; |
|
2
|
|
|
|
|
71071
|
|
|
2
|
|
|
|
|
860
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.002'; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
has query_data_options => ( |
9
|
|
|
|
|
|
|
is=>'ro', |
10
|
|
|
|
|
|
|
required=>1, |
11
|
|
|
|
|
|
|
lazy=>1, |
12
|
|
|
|
|
|
|
builder=>'build_query_data_options'); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub build_query_data_options { |
15
|
|
|
|
|
|
|
return +{ |
16
|
1
|
|
|
1
|
|
11
|
param_missing => sub { my ($req, $param) = @_; return '{}' }, |
|
1
|
|
|
|
|
3
|
|
17
|
0
|
|
|
0
|
|
0
|
parse_error => sub { my ($req, $param, $err) = @_; die $err }, |
|
0
|
|
|
|
|
0
|
|
18
|
7
|
|
|
7
|
|
162
|
}; |
19
|
|
|
|
|
|
|
} |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
has _jsony => ( |
22
|
|
|
|
|
|
|
is=>'ro', |
23
|
|
|
|
|
|
|
required=>1, |
24
|
|
|
|
|
|
|
lazy=>1, |
25
|
|
|
|
|
|
|
builder=>'build_jsony'); |
26
|
|
|
|
|
|
|
|
27
|
7
|
|
|
7
|
|
154
|
sub build_jsony { JSONY->new } |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
has _query_data_cache => ( |
30
|
|
|
|
|
|
|
is=>'ro', |
31
|
|
|
|
|
|
|
required=>1, |
32
|
|
|
|
|
|
|
init_arg=>undef, |
33
|
|
|
|
|
|
|
lazy=>1, |
34
|
|
|
|
|
|
|
default=>sub { +{} }); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
sub query_data { |
37
|
7
|
|
|
7
|
|
210855
|
my ($self, @params) = @_; |
38
|
7
|
|
|
|
|
19
|
my $proto = +{}; |
39
|
|
|
|
|
|
|
|
40
|
7
|
100
|
66
|
|
|
95
|
$proto = pop @params if (@params && ref($params[-1]) eq 'HASH'); |
41
|
7
|
100
|
|
|
|
38
|
@params = ('q') unless @params; |
42
|
|
|
|
|
|
|
|
43
|
7
|
|
|
|
|
15
|
my %local_options = (%{$self->query_data_options}, %$proto); |
|
7
|
|
|
|
|
41
|
|
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
return map { |
46
|
7
|
|
|
|
|
72
|
my $val = exists $self->query_parameters->{$_} ? |
47
|
|
|
|
|
|
|
$self->query_parameters->{$_} : |
48
|
11
|
100
|
|
|
|
407
|
$local_options{param_missing}->($self, $_); |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
my $deserialized = eval { $self->_jsony->load($val) } |
51
|
11
|
|
66
|
|
|
383
|
|| $local_options{parse_error}->($self, $val, $@); |
52
|
|
|
|
|
|
|
|
53
|
11
|
|
33
|
|
|
53404
|
$self->_query_data_cache->{$_} ||= $deserialized; |
54
|
|
|
|
|
|
|
} @params; |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
1; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=head1 NAME |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Catalyst::TraitFor::Request::QueryFromJSONY - Handle complex query parameters using JSONY |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head1 SYNOPSIS |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
For L<Catalyst> v5.90090+ |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
package MyApp; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
use Catalyst; |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
MyApp->request_class_traits(['Catalyst::TraitFor::Request::QueryFromJSONY']); |
72
|
|
|
|
|
|
|
MyApp->setup; |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
For L<Catalyst> older than v5.90090 |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
package MyApp; |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
use Catalyst; |
79
|
|
|
|
|
|
|
use CatalystX::RoleApplicator; |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
MyApp->apply_request_class_roles('Catalyst::TraitFor::Request::QueryFromJSONY'); |
82
|
|
|
|
|
|
|
MyApp->setup; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
In a controller: |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
package MyApp::Controller::Example; |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
use Moose; |
89
|
|
|
|
|
|
|
use MooseX::MethodAttributes; |
90
|
|
|
|
|
|
|
use Data::Dumper; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub echo :Local { |
93
|
|
|
|
|
|
|
my ($self, $c) = @_; |
94
|
|
|
|
|
|
|
$c->res->body( Dumper $c->req->query_data ); |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Example test case: |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
ok my $res = request GET "/example/echo?q={'id':100,'age':['>',10]}"; |
100
|
|
|
|
|
|
|
is_deeply eval $res->content, { |
101
|
|
|
|
|
|
|
'id' => 100, |
102
|
|
|
|
|
|
|
'age' => [ '>', 10 ] |
103
|
|
|
|
|
|
|
}; |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=head1 DESCRIPTION |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
This is an early access release of this module. Experimentation as to the best |
108
|
|
|
|
|
|
|
approach is ongoing. |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
There are cases when you'd like to express complex data structures in your URL |
111
|
|
|
|
|
|
|
query part (tha bit after the '?'). There's been a number of attempts at this, |
112
|
|
|
|
|
|
|
this module is yet another. In this version we allow for a query parameter 'q' |
113
|
|
|
|
|
|
|
to be a L<JSONY> serialized string (L<JSONY> is basically JSON relaxed a bit to |
114
|
|
|
|
|
|
|
reduce a bit of verbosity and smooth over common errors that are more pedantic |
115
|
|
|
|
|
|
|
that useful). We deserialize this string and place its value in 'query_data'. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
This only happens if you request the query_data attribute, so there's no overhead |
118
|
|
|
|
|
|
|
to simply having this installed. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
You can have other 'classic' query parameters mixed in with the 'q' parameter, but |
121
|
|
|
|
|
|
|
for no only 'q' is deserialized. The original value of 'q' is preserved in the |
122
|
|
|
|
|
|
|
original query_parameter method. |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=head1 METHODS |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
This role defines the following methods. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=head2 query_data (?@query_params, ?\%options) |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
For each item in @query_params that exists in $request->query_parameters deserialize |
131
|
|
|
|
|
|
|
using L<JSONY> and return the data references (could be a hashref, or arrayref |
132
|
|
|
|
|
|
|
depending on the query construction. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
If no @query_params are submitted, assume 'q' as the default. |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
The %options hash allows you to set callback to handle exceptional conditions. All callbacks |
137
|
|
|
|
|
|
|
get invoked with two parameters, the current $request object, and the name of the |
138
|
|
|
|
|
|
|
query parameter that caused the condition. For example the follow substitutes the string |
139
|
|
|
|
|
|
|
'[]' when a $key is missing from %{$c->req->query_parameters}: |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
$c->req->query_data(qw/a b c/, +{ |
142
|
|
|
|
|
|
|
param_missing => sub { |
143
|
|
|
|
|
|
|
my ($req, $key) = @_; |
144
|
|
|
|
|
|
|
return '[]'; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
}); |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
Currently we support the following exceptional conditions: |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=head3 param_missing |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
Gets $request, $key |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
This is the callback that gets invoked when $c->req->query_paramerters->{$key} does not |
155
|
|
|
|
|
|
|
exist. The default behavior is to return an empty string, which JSONY deserialized into |
156
|
|
|
|
|
|
|
a hashref. This allows you to request parameters that are optional and not product an |
157
|
|
|
|
|
|
|
exception. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=head3 parse_error |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
Gets $request, $key, $error_message |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
This callback is called when JSONY throws an exception trying to parse the value |
164
|
|
|
|
|
|
|
associated with $key. The default is to just rethrow the error. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=head1 AUTHOR |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
John Napiorkowski L<email:jjnapiork@cpan.org> |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head1 SEE ALSO |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
L<Catalyst>, L<Catalyst::Request>, L<JSONY> |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Copyright 2015, John Napiorkowski L<email:jjnapiork@cpan.org> |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it under |
179
|
|
|
|
|
|
|
the same terms as Perl itself. |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=cut |