File Coverage

lib/Plack/Middleware/APISchema/ResponseValidator.pm
Criterion Covered Total %
statement 54 54 100.0
branch 4 4 100.0
condition 4 7 57.1
subroutine 13 13 100.0
pod 1 2 50.0
total 76 80 95.0


line stmt bran cond sub pod time code
1             package Plack::Middleware::APISchema::ResponseValidator;
2 1     1   3174 use strict;
  1         2  
  1         31  
3 1     1   5 use warnings;
  1         2  
  1         33  
4              
5 1     1   6 use parent qw(Plack::Middleware);
  1         2  
  1         6  
6 1     1   6449 use Plack::Util ();
  1         3  
  1         39  
7 1     1   6 use Plack::Util::Accessor qw(schema validator);
  1         2  
  1         4  
8 1     1   554 use Plack::Response;
  1         1281  
  1         41  
9 1     1   416 use APISchema::Generator::Router::Simple;
  1         5  
  1         44  
10 1     1   374 use APISchema::Validator;
  1         4  
  1         34  
11 1     1   384 use APISchema::JSON;
  1         2  
  1         51  
12              
13 1     1   7 use constant DEFAULT_VALIDATOR_CLASS => 'Valiemon';
  1         2  
  1         446  
14              
15             sub call {
16 15     15 1 128584 my ($self, $env) = @_;
17              
18             Plack::Util::response_cb($self->app->($env), sub {
19 15     15   1017 my $res = shift;
20              
21 15         41 my ($matched, $route) = $self->router->routematch($env);
22 15 100       786 $matched or return;
23              
24 14         116 my $plack_res = Plack::Response->new(@$res);
25 14         1507 my $body;
26 14   50     120 Plack::Util::foreach($res->[2] // [], sub { $body .= $_[0] });
  14         165  
27              
28 14   50     91 my $validator_class = $self->validator // DEFAULT_VALIDATOR_CLASS;
29 14         212 my $validator = APISchema::Validator->for_response(
30             validator_class => $validator_class,
31             );
32             my $result = $validator->validate($route->name => {
33             status_code => $res->[0],
34             header => +{ map {
35 14         56 my $field = lc($_) =~ s/[-]/_/gr;
  16         533  
36 16         68 ( $field => $plack_res->header($_) );
37             } $plack_res->headers->header_field_names },
38             body => $body,
39             content_type => scalar $plack_res->content_type,
40             }, $self->schema);
41              
42 14         96 my $errors = $result->errors;
43 14 100       56 if (scalar keys %$errors) {
44 8         29 my $error_cause = join '+', __PACKAGE__, $validator_class;
45 8         41 @$res = (
46             500,
47             [ 'Content-Type' => 'application/json', 'X-Error-Cause' => $error_cause ],
48             [ encode_json_canonical($errors) ],
49             );
50 8         70 return;
51             }
52              
53 6         71 $res->[2] = [ $body ];
54 15         72 });
55             }
56              
57             sub router {
58 16     16 0 1339 my ($self) = @_;
59              
60 16   66     96 $self->{router} //= do {
61 5         44 my $generator = APISchema::Generator::Router::Simple->new;
62 5         45 $generator->generate_router($self->schema);
63             };
64             }
65              
66              
67             1;