File Coverage

blib/lib/Mojolicious/Plugin/OpenAPI/Parameters.pm
Criterion Covered Total %
statement 82 82 100.0
branch 42 44 95.4
condition 13 16 81.2
subroutine 18 18 100.0
pod 1 1 100.0
total 156 161 96.8


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::OpenAPI::Parameters;
2 48     48   360 use Mojo::Base 'Mojolicious::Plugin';
  48         123  
  48         332  
3              
4 48     48   8513 use JSON::Validator::Util qw(is_bool schema_type);
  48         170  
  48         2691  
5 48     48   373 use Mojo::JSON qw(encode_json decode_json);
  48         143  
  48         82432  
6              
7             sub register {
8 59     59 1 816 my ($self, $app, $config) = @_;
9              
10             $app->helper('openapi.build_response_body' => $config->{renderer}
11 59   100     720 || \&_helper_build_response_body);
12 59         29303 $app->helper('openapi.build_schema_request' => \&_helper_build_schema_request);
13 59         27649 $app->helper('openapi.build_schema_response' => \&_helper_build_schema_response);
14 59         29030 $app->helper('openapi.coerce_request_parameters' => \&_helper_coerce_request_parameters);
15 59         30683 $app->helper('openapi.coerce_response_parameters' => \&_helper_coerce_response_parameters);
16 59         32195 $app->helper('openapi.parse_request_body' => \&_helper_parse_request_body);
17             }
18              
19             sub _bool {
20 19 100   19   163 return map { !is_bool($_) ? $_ : $_ ? 'true' : 'false' } @_;
  21 100       61  
21             }
22              
23             sub _helper_build_response_body {
24 171     171   3728 my $c = shift;
25 171 50       872 return $_[0]->slurp if UNIVERSAL::isa($_[0], 'Mojo::Asset');
26 171 50       704 $c->res->headers->content_type('application/json;charset=UTF-8')
27             unless $c->res->headers->content_type;
28 171         7535 return encode_json($_[0]);
29             }
30              
31             sub _helper_build_schema_request {
32 176     176   4173 my $c = shift;
33 176         636 my $req = $c->req;
34              
35 176         1847 $c->stash->{'openapi.evaluated_request_parameters'} = \my @evaluated;
36              
37             return {
38             body => sub {
39 53     53   25693 $evaluated[@evaluated] = $c->openapi->parse_request_body($_[1]);
40             },
41             formData => sub {
42 51     51   6153 my $name = shift;
43 51         148 my $value = $req->body_params->every_param($name);
44 51         2781 my $n = @$value;
45 51 100       162 return $evaluated[@evaluated] = {exists => 1, value => $n > 1 ? $value : $value->[0]}
    100          
46             if $n > 0;
47              
48 44         124 $value = $req->upload($name);
49 44   66     1118 return $evaluated[@evaluated] = {exists => !!$value, value => $value && $value->size};
50             },
51             header => sub {
52 38     38   5583 my $name = shift;
53 38         127 my $value = $req->headers->every_header($name);
54 38         626 return $evaluated[@evaluated] = {exists => !!@$value, value => $value};
55             },
56             path => sub {
57 27     27   12836 my $name = shift;
58 27         95 my $stash = $c->match->stack->[-1];
59 27         313 return $evaluated[@evaluated] = {exists => exists $stash->{$name}, value => $stash->{$name}};
60             },
61             query => sub {
62 186 100   186   40184 return $evaluated[@evaluated] = {exists => 1, value => $req->url->query->to_hash}
63             unless my $name = shift;
64 152         483 my $value = $req->url->query->every_param($name);
65 152         7100 my $n = @$value;
66 152 100       935 return $evaluated[@evaluated] = {exists => !!$n, value => $n > 1 ? $value : $value->[0]};
67             },
68 176         4838 };
69             }
70              
71             sub _helper_build_schema_response {
72 137     137   2945 my $c = shift;
73 137         548 my $res = $c->res;
74              
75 137         1622 $c->stash->{'openapi.evaluated_response_parameters'} = \my @evaluated;
76              
77             return {
78             body => sub {
79 130     130   8694 my $res = $c->stash('openapi');
80 130         1656 return $evaluated[@evaluated]
81             = {accept => $c->req->headers->accept, exists => !!$res, value => $res};
82             },
83             header => sub {
84 21     21   2419 my $name = shift;
85 21         73 my $value = $res->headers->every_header($name);
86 21         336 return $evaluated[@evaluated] = {exists => !!@$value, value => $value};
87             },
88 137         2599 };
89             }
90              
91             sub _helper_coerce_request_parameters {
92 176     176   5073 my ($c, $evaluated) = @_;
93 176         815 my $output = $c->validation->output;
94 176         89069 my $req = $c->req;
95              
96 176         1955 for my $i (@$evaluated) {
97 355 100       1478 next unless $i->{valid};
98 139         548 $output->{$i->{name}} = $i->{value};
99 139 100       600 $c->stash(@$i{qw(name value)}) if $i->{in} eq 'path';
100 3         47 $req->headers->header($i->{name}, ref $i->{value} eq 'ARRAY' ? @{$i->{value}} : $i->{value})
101 139 100       894 if $i->{in} eq 'header';
    100          
102 139 100       1023 $req->url->query->merge(@$i{qw(name value)}) if $i->{in} eq 'query';
103 139 100       4907 $req->params->merge(@$i{qw(name value)}) if $i->{in} eq 'query';
104 139 100       3740 $req->params->merge(@$i{qw(name value)}) if $i->{in} eq 'formData';
105 139 100       1108 $req->body_params->merge(@$i{qw(name value)}) if $i->{in} eq 'formData';
106             }
107             }
108              
109             sub _helper_coerce_response_parameters {
110 137     137   3136 my ($c, $evaluated) = @_;
111 137         471 my $res = $c->res;
112              
113 137         1586 for my $i (@$evaluated) {
114 151 100       1138 next unless $i->{valid};
115 137 100       782 $c->stash(openapi_negotiated_content_type => $i->{content_type}) if $i->{in} eq 'body';
116             $res->headers->header($i->{name},
117 6         70 _bool(ref $i->{value} eq 'ARRAY' ? @{$i->{value}} : $i->{value}))
118 137 100       2602 if $i->{in} eq 'header';
    100          
119             }
120             }
121              
122             sub _helper_parse_request_body {
123 53     53   970 my ($c, $param) = @_;
124              
125 53   100     184 my $content_type = $c->req->headers->content_type || '';
126 53         1559 my $res = {content_type => $content_type, exists => !!$c->req->body_size};
127              
128             eval {
129             $res->{value} //= $c->req->body_params->to_hash
130 53 100 33     139 if grep { $content_type eq $_ } qw(application/x-www-form-urlencoded multipart/form-data);
  106         403  
131              
132             # Trying to use the already parsed json() or fallback to manually decoding the request
133             # since it will make the eval {} fail on invalid json.
134 53   100     853 $res->{value} //= $c->req->json // decode_json $c->req->body;
      100        
135 37         5275 1;
136 53 100       1755 } or do {
137 16         34078 $res->{value} = $c->req->body;
138             };
139              
140 53         732 return $res;
141             }
142              
143             1;
144              
145             =encoding utf8
146              
147             =head1 NAME
148              
149             Mojolicious::Plugin::OpenAPI::Parameters - Methods for transforming data from/to JSON::Validator::Schema
150              
151             =head1 DESCRIPTION
152              
153             L adds helpers to your L
154             application, required by L. These helpers can be
155             redefined in case you have special needs.
156              
157             =head1 HELPERS
158              
159             =head2 openapi.build_response_body
160              
161             $bytes = $c->openapi->build_response_body(Mojo::Asset->new);
162             $bytes = $c->openapi->build_response_body($data);
163              
164             Takes validated data and turns it into bytes that will be used as HTTP response
165             body. This method is useful to override, in case you want to render some other
166             structure than JSON.
167              
168             =head2 openapi.build_schema_request
169              
170             $hash_ref = $c->openapi->build_schema_request;
171              
172             Builds input data for L.
173              
174             =head2 openapi.build_schema_response
175              
176             $hash_ref = $c->openapi->build_schema_response;
177              
178             Builds input data for L.
179              
180             =head2 openapi.coerce_request_parameters
181              
182             $c->openapi->coerce_request_parameters(\@evaluated_parameters);
183              
184             Used by L to write the validated data back to
185             L and
186             L.
187              
188             =head2 openapi.coerce_response_parameters
189              
190             $c->openapi->coerce_response_parameters(\@evaluated_parameters);
191              
192             Used by L to write the validated data to
193             L.
194              
195             =head2 openapi.parse_request_body
196              
197             $hash_ref = $c->openapi->parse_request_body;
198              
199             Returns a structure representing the request body. The default is to parse the
200             input as JSON:
201              
202             {content_type => "application/json", exists => !!$c->req->body_size, value => $c->req->json};
203              
204             This method is useful to override, in case you want to parse some other
205             structure than JSON.
206              
207             =head1 METHODS
208              
209             =head2 register
210              
211             $self->register($app, \%config);
212              
213             This method will add the L to your L C<$app>.
214              
215             =head1 SEE ALSO
216              
217             L.
218              
219             =cut