Peace/lib/Peace/Swagger.pm

283 lines
6.8 KiB
Perl
Raw Normal View History

package Peace::Swagger;
use v5.30.0;
use strict;
use warnings;
use Params::ValidationCompiler qw/validation_for/;
use Types::Standard qw/ArrayRef Str HashRef/;
use Const::Fast;
use Email::Valid;
const my $EMAIL_VALIDATOR => Type::Tiny->new(
name => 'Email',
constraint => sub {
return Email::Valid->address($_);
},
message => sub { return "$_ is not an email address."; },
);
sub new {
my $class = shift;
my $self = bless {}, $class;
}
sub schema {
return {
openapi => "3.1.0",
info => {
title => 'Peace API',
version => '0.0.1',
license => {
name => 'AGPLv3',
url => 'https://www.gnu.org/licenses/agpl-3.0.en.html',
}
},
paths => { developer(), }
};
}
{
my $validator = validation_for(
params => {
type => { type => Str },
}
);
sub _type_to_type_tiny {
my $self = shift;
my %params = $validator->(@_);
my ($type) = $params{type};
return Str if $type eq 'string';
die 'No such type declared.';
}
}
{
my $validator = validation_for(
params => {
format => { type => Str },
}
);
sub _format_to_type_tiny {
my $self = shift;
my %params = $validator->(@_);
my ($format) = $params{format};
return $EMAIL_VALIDATOR if $format eq 'email';
die "No such format declared.";
}
}
sub developer {
return (
"/developer" => {
summary => "Allows to work with developers.",
post => developer_post(),
}
);
}
{
my $validator = validation_for(
params => {
json => { type => HashRef },
spec => { type => HashRef },
}
);
sub validate_request {
my $self = shift;
my %params = $validator->(@_);
my $json = $params{json};
my $spec = $params{spec};
my $spec_parameters = $spec->{parameters};
for my $parameter_spec (@$spec_parameters) {
$self->_validate_parameter(
parameter_spec => $parameter_spec,
json => $json,
);
}
}
}
{
my $validator = validation_for(
params => {
parameter_spec => { type => HashRef },
json => { type => HashRef },
}
);
sub _validate_parameter {
my $self = shift;
my %params = $validator->(@_);
my ( $parameter_spec, $json ) = @params{
qw/
parameter_spec json/
};
my $name = $parameter_spec->{name};
my $schema = $parameter_spec->{schema};
my $required = $parameter_spec->{required};
my $type = $schema->{type};
my $format = $schema->{format};
my $pattern = $schema->{pattern};
if ( !exists $json->{$name} ) {
die "$name is required." if $required;
return;
}
my $value = $json->{$name};
unless ( $self->_type_to_type_tiny( type => $type )->check($value) ) {
die "$value is not $type.";
}
if ( defined $format ) {
my $type_format = $self->_format_to_type_tiny( format => $format );
unless ( $type_format->check( $json->{$name} ) ) {
die "$value is not $format.";
}
}
if ( defined $pattern ) {
die "$value doesn\'t match $pattern." if $value !~ /^$pattern$/;
}
}
}
sub developer_post {
return {
summary => 'Creates a developer',
parameters => [
{
name => 'secret',
required => 1,
in => 'query',
description =>
'Access credential for Authenticate latter as the created developer.',
schema => {
type => "string",
# Bcrypt limit is 72 characters.
pattern => ".{10,72}"
}
},
{
name => 'name',
required => 1,
in => 'query',
description => 'Developer\'s real name',
schema => {
type => "string",
}
},
{
name => 'surname',
required => 1,
in => 'query',
description => 'Developer\'s real surname',
schema => {
type => "string",
}
},
{
name => 'surname',
required => 1,
in => 'query',
description => 'Developer\'s real surname',
schema => {
type => "string",
}
},
{
name => 'email',
required => 1,
in => 'query',
description => 'Developer\'s email',
schema => {
type => "string",
format => 'email',
}
},
{
name => 'country',
description => 'Developer\'s country in iso3166format',
required => 1,
in => 'query',
schema => {
type => "string",
pattern => '[A-Z]{2}',
}
}
]
};
}
1;
=encoding utf8
=head1 NAME
Peace::Swagger - OpenAPI definitions for the Peace API.
=head1 SYNOPSIS
my $swagger = Peace::Swagger->new;
my $spec = $swagger->schema;
=head1 DESCRIPTION
This module aims to help in the programmatic description
of all API endpoints in a way that makes possible to
reuse those schemas in the code and in the documentation.
=head1 INSTANCE METHODS
Peace::Swagger implements the following instance methods:
=head2 new
my $swagger = Peace::Swagger->new;
Instances a Peace::Swagger.
=head1 METHODS
Peace::Swagger implements the following methods:
=head2 schema
my $schema = $swagger->schema;
Returns the complete openapi schema.
=head2 validate_request
$swagger->validate_request(json => $json, spec => $spec);
Validates the spec for a specific endpoint say
developer_post against the json got from the
user and dies if the check is unsuccesful.
=head2 developer
my $developer_schema = $swagger->developer;
Returns the schemas associated with the
L<Peace::Model::Developer> object.
=head2 developer_post
my $developer_post = $swagger->developer_post
Returns the schema of the post request
to the /developer enpoint.
=cut