File Coverage

lib/Plack/Middleware/APISchema/RequestValidator.pm
Criterion Covered Total %
statement 49 49 100.0
branch 6 6 100.0
condition 5 7 71.4
subroutine 13 13 100.0
pod 1 2 50.0
total 74 77 96.1


line stmt bran cond sub pod time code
1             package Plack::Middleware::APISchema::RequestValidator;
2 1     1   2190 use strict;
  1         2  
  1         22  
3 1     1   4 use warnings;
  1         2  
  1         22  
4              
5 1     1   4 use parent qw(Plack::Middleware);
  1         2  
  1         4  
6 1     1   4759 use HTTP::Status qw(:constants);
  1         2  
  1         349  
7 1     1   6 use Plack::Util::Accessor qw(schema validator);
  1         1  
  1         3  
8 1     1   447 use Plack::Request;
  1         37231  
  1         34  
9 1     1   329 use APISchema::Generator::Router::Simple;
  1         3  
  1         25  
10 1     1   288 use APISchema::Validator;
  1         2  
  1         30  
11 1     1   278 use APISchema::JSON;
  1         2  
  1         44  
12              
13 1     1   5 use constant DEFAULT_VALIDATOR_CLASS => 'Valiemon';
  1         2  
  1         368  
14              
15             sub call {
16 13     13 1 98478 my ($self, $env) = @_;
17 13         84 my $req = Plack::Request->new($env);
18              
19 13         130 my ($matched, $route) = $self->router->routematch($env);
20 13 100       661 $matched or return $self->app->($env);
21              
22 12   50     43 my $validator = APISchema::Validator->for_request(
23             validator_class => $self->validator // DEFAULT_VALIDATOR_CLASS,
24             );
25             my $result = $validator->validate($route->name => {
26             header => +{ map {
27 39         3021 my $field = lc($_) =~ s/[-]/_/gr;
28 39         88 ( $field => $req->header($_) );
29             } $req->headers->header_field_names },
30             parameter => $env->{QUERY_STRING},
31 12         47 body => $req->content,
32             content_type => $req->content_type,
33             }, $self->schema);
34              
35 12         78 my $errors = $result->errors;
36 12         36 my $status_code = $self->_resolve_status_code($result);
37             return [
38 12 100       69 $status_code,
39             [ 'Content-Type' => 'application/json' ],
40             [ encode_json_canonical($errors) ],
41             ] if scalar keys %$errors;
42              
43 5         27 $self->app->($env);
44             }
45              
46             sub router {
47 14     14 0 988 my ($self) = @_;
48              
49 14   66     69 $self->{router} //= do {
50 3         22 my $generator = APISchema::Generator::Router::Simple->new;
51 3         26 $generator->generate_router($self->schema);
52             };
53             }
54              
55             sub _resolve_status_code {
56 12     12   29 my ($self, $validation_result) = @_;
57 12   100     19 my $error_message = $validation_result->errors->{body}->{message} // '';
58 12 100       69 return $error_message =~ m/Wrong content-type/ ? HTTP_UNSUPPORTED_MEDIA_TYPE : HTTP_UNPROCESSABLE_ENTITY;
59             }
60              
61              
62             1;