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   2478 use strict;
  1         2  
  1         32  
3 1     1   4 use warnings;
  1         3  
  1         31  
4              
5 1     1   5 use parent qw(Plack::Middleware);
  1         2  
  1         6  
6 1     1   6245 use HTTP::Status qw(:constants);
  1         3  
  1         406  
7 1     1   7 use Plack::Util::Accessor qw(schema validator);
  1         3  
  1         3  
8 1     1   321 use Plack::Request;
  1         40892  
  1         42  
9 1     1   359 use APISchema::Generator::Router::Simple;
  1         3  
  1         31  
10 1     1   240 use APISchema::Validator;
  1         4  
  1         30  
11 1     1   297 use APISchema::JSON;
  1         2  
  1         49  
12              
13 1     1   5 use constant DEFAULT_VALIDATOR_CLASS => 'Valiemon';
  1         1  
  1         310  
14              
15             sub call {
16 13     13 1 113164 my ($self, $env) = @_;
17 13         114 my $req = Plack::Request->new($env);
18              
19 13         171 my ($matched, $route) = $self->router->routematch($env);
20 13 100       772 $matched or return $self->app->($env);
21              
22 12   50     62 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         3280 my $field = lc($_) =~ s/[-]/_/gr;
28 39         127 ( $field => $req->header($_) );
29             } $req->headers->header_field_names },
30             parameter => $env->{QUERY_STRING},
31 12         54 body => $req->content,
32             content_type => $req->content_type,
33             }, $self->schema);
34              
35 12         90 my $errors = $result->errors;
36 12         41 my $status_code = $self->_resolve_status_code($result);
37             return [
38 12 100       72 $status_code,
39             [ 'Content-Type' => 'application/json' ],
40             [ encode_json_canonical($errors) ],
41             ] if scalar keys %$errors;
42              
43 5         31 $self->app->($env);
44             }
45              
46             sub router {
47 14     14 0 930 my ($self) = @_;
48              
49 14   66     117 $self->{router} //= do {
50 3         25 my $generator = APISchema::Generator::Router::Simple->new;
51 3         28 $generator->generate_router($self->schema);
52             };
53             }
54              
55             sub _resolve_status_code {
56 12     12   24 my ($self, $validation_result) = @_;
57 12   100     35 my $error_message = $validation_result->errors->{body}->{message} // '';
58 12 100       50 return $error_message =~ m/Wrong content-type/ ? HTTP_UNSUPPORTED_MEDIA_TYPE : HTTP_UNPROCESSABLE_ENTITY;
59             }
60              
61              
62             1;