The POST /developer endpoint is created using the openapi definition to validate the fields. This will allow a way to create endpoints and their doc automatically.main
parent
3d9724b144
commit
16ac140f9d
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Peace::Controller::Developer - Developer's http endpoint.</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
|
||||
<link href="mailto:Alpine@build-edge-aarch64.nonet" rev="made" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
|
||||
<ul id="index">
|
||||
<li><a href="#NAME">NAME</a></li>
|
||||
<li><a href="#SYNOPSIS">SYNOPSIS</a></li>
|
||||
<li><a href="#DESCRIPTION">DESCRIPTION</a></li>
|
||||
<li><a href="#METHODS">METHODS</a>
|
||||
<ul>
|
||||
<li><a href="#post">post</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#SEE-ALSO">SEE ALSO</a></li>
|
||||
</ul>
|
||||
|
||||
<h1 id="NAME">NAME</h1>
|
||||
|
||||
<p>Peace::Controller::Developer - Developer's http endpoint.</p>
|
||||
|
||||
<h1 id="SYNOPSIS">SYNOPSIS</h1>
|
||||
|
||||
<pre><code># This object is used by mojolicious.</code></pre>
|
||||
|
||||
<h1 id="DESCRIPTION">DESCRIPTION</h1>
|
||||
|
||||
<p>Peace::Controller::Developer allows to interact using a json http api with the <a href="../Model/Developer.pm.html">Peace::Model::Developer</a> objects in Peace.</p>
|
||||
|
||||
<h1 id="METHODS">METHODS</h1>
|
||||
|
||||
<p>Peace::Controller::Developer implements the following methods:</p>
|
||||
|
||||
<h2 id="post">post</h2>
|
||||
|
||||
<pre><code># To be used by mojolicious.</code></pre>
|
||||
|
||||
<p>Creates a Developer in db with the data given by the user.</p>
|
||||
|
||||
<h1 id="SEE-ALSO">SEE ALSO</h1>
|
||||
|
||||
<p><a href="../Model/Developer.pm.html">Peace::Model::Developer</a>, <a href="../DAO/Developer.pm.html">Peace::DAO::Developer</a></p>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Peace::Swagger - OpenAPI definitions for the Peace API.</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
|
||||
<link href="mailto:Alpine@build-edge-aarch64.nonet" rev="made" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
|
||||
<ul id="index">
|
||||
<li><a href="#NAME">NAME</a></li>
|
||||
<li><a href="#SYNOPSIS">SYNOPSIS</a></li>
|
||||
<li><a href="#DESCRIPTION">DESCRIPTION</a></li>
|
||||
<li><a href="#INSTANCE-METHODS">INSTANCE METHODS</a>
|
||||
<ul>
|
||||
<li><a href="#new">new</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#METHODS">METHODS</a>
|
||||
<ul>
|
||||
<li><a href="#schema">schema</a></li>
|
||||
<li><a href="#validate_request">validate_request</a></li>
|
||||
<li><a href="#developer">developer</a></li>
|
||||
<li><a href="#developer_post">developer_post</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h1 id="NAME">NAME</h1>
|
||||
|
||||
<p>Peace::Swagger - OpenAPI definitions for the Peace API.</p>
|
||||
|
||||
<h1 id="SYNOPSIS">SYNOPSIS</h1>
|
||||
|
||||
<p>my $swagger = Peace::Swagger->new;</p>
|
||||
|
||||
<p>my $spec = $swagger->schema;</p>
|
||||
|
||||
<h1 id="DESCRIPTION">DESCRIPTION</h1>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h1 id="INSTANCE-METHODS">INSTANCE METHODS</h1>
|
||||
|
||||
<p>Peace::Swagger implements the following instance methods:</p>
|
||||
|
||||
<h2 id="new">new</h2>
|
||||
|
||||
<p>my $swagger = Peace::Swagger->new;</p>
|
||||
|
||||
<p>Instances a Peace::Swagger.</p>
|
||||
|
||||
<h1 id="METHODS">METHODS</h1>
|
||||
|
||||
<p>Peace::Swagger implements the following methods:</p>
|
||||
|
||||
<h2 id="schema">schema</h2>
|
||||
|
||||
<pre><code>my $schema = $swagger->schema;</code></pre>
|
||||
|
||||
<p>Returns the complete openapi schema.</p>
|
||||
|
||||
<h2 id="validate_request">validate_request</h2>
|
||||
|
||||
<pre><code>$swagger->validate_request(json => $json, spec => $spec);</code></pre>
|
||||
|
||||
<p>Validates the spec for a specific endpoint say developer_post against the json got from the user and dies if the check is unsuccesful.</p>
|
||||
|
||||
<h2 id="developer">developer</h2>
|
||||
|
||||
<pre><code>my $developer_schema = $swagger->developer;</code></pre>
|
||||
|
||||
<p>Returns the schemas associated with the <a href="Model/Developer.pm.html">Peace::Model::Developer</a> object.</p>
|
||||
|
||||
<h2 id="developer_post">developer_post</h2>
|
||||
|
||||
<pre><code>my $developer_post = $swagger->developer_post</code></pre>
|
||||
|
||||
<p>Returns the schema of the post request to the /developer enpoint.</p>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
@ -0,0 +1,90 @@
|
||||
package Peace::Controller::Developer;
|
||||
|
||||
use Mojo::Base 'Mojolicious::Controller';
|
||||
|
||||
use v5.30.0;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Const::Fast;
|
||||
|
||||
use Peace::Swagger;
|
||||
use Crypt::Bcrypt qw/bcrypt/;
|
||||
use Crypt::URandom qw/urandom/;
|
||||
|
||||
use Peace;
|
||||
use Peace::DB;
|
||||
|
||||
use Peace::Model::Developer;
|
||||
use Peace::DAO::Developer;
|
||||
|
||||
const my $swagger => Peace::Swagger->new;
|
||||
|
||||
sub post {
|
||||
my $self = shift;
|
||||
my $json = $self->req->json;
|
||||
my $peace = Peace->new;
|
||||
my $config = $peace->peace_config;
|
||||
print Data::Dumper::Dumper $config;
|
||||
|
||||
my $dbh = Peace::DB->dbh( config => $config );
|
||||
my $developer_dao = Peace::DAO::Developer->new( dbh => $dbh );
|
||||
unless ( defined $json ) {
|
||||
$self->render( text => 'body is not a json', status => '400' );
|
||||
return;
|
||||
}
|
||||
my $spec = $swagger->developer_post;
|
||||
eval { $swagger->validate_request( json => $json, spec => $spec, ); };
|
||||
if ($@) {
|
||||
$self->render( text => $@, status => '400' );
|
||||
return;
|
||||
}
|
||||
my $secret = delete $json->{secret};
|
||||
my $secret_bcrypt = bcrypt( $secret, '2b', 12, urandom(16) );
|
||||
$json->{secret_bcrypt} = $secret_bcrypt;
|
||||
$json->{verified} = 0;
|
||||
my $developer = Peace::Model::Developer->new(%$json);
|
||||
eval {
|
||||
$developer_dao->create( developer => $developer );
|
||||
};
|
||||
if ($@) {
|
||||
$self->render( status => 400, text => $@ );
|
||||
return;
|
||||
}
|
||||
$self->render( json => $developer->to_json() );
|
||||
}
|
||||
1;
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Peace::Controller::Developer - Developer's http endpoint.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# This object is used by mojolicious.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Peace::Controller::Developer allows to interact using
|
||||
a json http api with the L<Peace::Model::Developer> objects
|
||||
in Peace.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
Peace::Controller::Developer implements the following methods:
|
||||
|
||||
=head2 post
|
||||
|
||||
# To be used by mojolicious.
|
||||
|
||||
Creates a Developer in db with the data given by the user.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Peace::Model::Developer>, L<Peace::DAO::Developer>
|
||||
|
||||
=cut
|
@ -0,0 +1,282 @@
|
||||
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
|
Loading…
Reference in new issue