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   2090 use strict;
  1         3  
  1         23  
3 1     1   5 use warnings;
  1         1  
  1         24  
4              
5 1     1   4 use parent qw(Plack::Middleware);
  1         2  
  1         4  
6 1     1   3795 use Plack::Util ();
  1         2  
  1         17  
7 1     1   3 use Plack::Util::Accessor qw(schema validator);
  1         2  
  1         3  
8 1     1   280 use Plack::Response;
  1         825  
  1         25  
9 1     1   203 use APISchema::Generator::Router::Simple;
  1         2  
  1         25  
10 1     1   227 use APISchema::Validator;
  1         3  
  1         29  
11 1     1   213 use APISchema::JSON;
  1         3  
  1         41  
12              
13 1     1   4 use constant DEFAULT_VALIDATOR_CLASS => 'Valiemon';
  1         2  
  1         325  
14              
15             sub call {
16 15     15 1 108234 my ($self, $env) = @_;
17              
18             Plack::Util::response_cb($self->app->($env), sub {
19 15     15   1038 my $res = shift;
20              
21 15         46 my ($matched, $route) = $self->router->routematch($env);
22 15 100       755 $matched or return;
23              
24 14         101 my $plack_res = Plack::Response->new(@$res);
25 14         1283 my $body;
26 14   50     116 Plack::Util::foreach($res->[2] // [], sub { $body .= $_[0] });
  14         147  
27              
28 14   50     75 my $validator_class = $self->validator // DEFAULT_VALIDATOR_CLASS;
29 14         173 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         52 my $field = lc($_) =~ s/[-]/_/gr;
  16         458  
36 16         61 ( $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         86 my $errors = $result->errors;
43 14 100       48 if (scalar keys %$errors) {
44 8         24 my $error_cause = join '+', __PACKAGE__, $validator_class;
45 8         33 @$res = (
46             500,
47             [ 'Content-Type' => 'application/json', 'X-Error-Cause' => $error_cause ],
48             [ encode_json_canonical($errors) ],
49             );
50 8         58 return;
51             }
52              
53 6         99 $res->[2] = [ $body ];
54 15         64 });
55             }
56              
57             sub router {
58 16     16 0 1748 my ($self) = @_;
59              
60 16   66     107 $self->{router} //= do {
61 5         45 my $generator = APISchema::Generator::Router::Simple->new;
62 5         48 $generator->generate_router($self->schema);
63             };
64             }
65              
66              
67             1;