view release on metacpan or search on metacpan
Holder, and derivatives of that collection of files created through
textual modification.
- "Standard Version" refers to such a Package if it has not been modified,
or has been modified in accordance with the wishes of the Copyright
Holder.
- "Copyright Holder" is whoever is named in the copyright or copyrights for
the package.
- "You" is you, if you're thinking about copying or distributing this Package.
- "Reasonable copying fee" is whatever you can justify on the basis of media
cost, duplication charges, time of people involved, and so on. (You will
not be required to justify it to the Copyright Holder, but only to the
computing community at large as a market that must bear the fee.)
- "Freely Available" means that no fee is charged for the item itself, though
there may be fees involved in handling the item. It also means that
recipients of the item may redistribute it under the same conditions they
received it.
1. You may make and give away verbatim copies of the source form of the
Standard Version of this Package without restriction, provided that you
duplicate all of the original copyright notices and associated disclaimers.
type => 'number',
description => 'Weight(kg)',
example => 50,
},
height => {
type => 'number',
description => 'Height(m)',
example => 1.6,
},
},
required => ['weight', 'height'],
};
resource bmi => {
type => 'object',
description => 'Body mass index',
properties => {
value => {
type => 'number',
description => 'bmi value',
example => 19.5,
},
},
required => ['value'],
};
POST '/bmi/' => {
title => 'BMI API',
description => 'This API calculates your BMI.',
destination => {
controller => 'BMI',
action => 'calculate',
},
request => 'figure',
eg/bmi.psgi view on Meta::CPAN
carton exec -- plackup bmi.psgi
Then,
% curl -X POST -H "Content-type: application/json" -d '{"weight": 60, "height": '1.7'}' http://localhost:5000/bmi
{"value":20.7612456747405}
Requests and Reponses to the API are validated by Middlewares.
% curl -X POST -H "Content-type: application/json" -d 'hello' http://localhost:5000/bmi
{"attribute":"Valiemon::Attributes::Required","position":"/required"}
% curl -X POST -H "Content-type: application/json" -d '{"weight": 60, "height": 'a'}' http://localhost:5000/bmi
{"attribute":"Valiemon::Attributes::Required","position":"/required"}
% curl -X POST -H "Content-type: application/json" -d '{"weight": 60, "height": 'a'}' http://localhost:5000/bmi
{"attribute":"Valiemon::Attributes::Required","position":"/required"}
% curl -X POST -H "Content-type: application/json" -d '{"weight": 60}' http://localhost:5000/bmi
{"attribute":"Valiemon::Attributes::Required","position":"/required"}
You can read the document of API at L<http://localhost:5000/doc/>
lib/APISchema.pm view on Meta::CPAN
type => 'number',
description => 'Weight(kg)',
example => 50,
},
height => {
type => 'number',
description => 'Height(m)',
example => 1.6,
},
},
required => ['weight', 'height'],
};
resource bmi => {
type => 'object',
description => 'Body mass index',
properties => {
value => {
type => 'number',
description => 'bmi value',
example => 19.5,
},
},
required => ['value'],
};
POST '/bmi/' => {
title => 'BMI API',
description => 'This API calculates your BMI.',
destination => {
controller => 'BMI',
action => 'calculate',
},
request => 'figure',
lib/APISchema/Generator/Markdown/Formatter.pm view on Meta::CPAN
use Exporter qw(import);
our @EXPORT = qw(type json pretty_json code restriction desc anchor method methods content_type http_status http_status_code);
# cpan
use HTTP::Status qw(status_message);
use URI::Escape qw(uri_escape_utf8);
use JSON::XS ();
my $JSON = JSON::XS->new->canonical(1);
use constant +{
RESTRICTIONS => [qw(required max_items min_items max_length min_length maximum minimum pattern)],
SHORT_DESCRIPTION_LENGTH => 100,
};
sub type ($); # type has recursive call
sub type ($) {
my $def = shift;
my $bar = '|';
if (ref $def) {
t/APISchema-DSL.t view on Meta::CPAN
type => 'number',
description => 'Weight(kg)',
example => 50,
},
height => {
type => 'number',
description => 'Height(m)',
example => 1.6,
},
},
required => ['weight', 'height'],
};
resource bmi => {
type => 'object',
description => 'Body mass index',
properties => {
value => {
type => 'number',
description => 'bmi value',
example => 19.5,
},
},
required => ['value'],
};
POST '/bmi' => {
title => 'BMI API',
description => 'This API calculates your BMI.',
destination => {
controller => 'BMI',
action => 'calculate',
},
request => 'figure',
t/APISchema-DSL.t view on Meta::CPAN
definition => {
type => 'object',
description => 'Body mass index',
properties => {
value => {
type => 'number',
description => 'bmi value',
example => 19.5,
},
},
required => ['value'],
},
}, {
title => 'figure',
definition => {
type => 'object',
description => 'Figure, which includes weight and height',
properties => {
weight => {
type => 'number',
description => 'Weight(kg)',
example => 50,
},
height => {
type => 'number',
description => 'Height(m)',
example => 1.6,
},
},
required => ['weight', 'height'],
},
} ];
is $schema->title, 'BMI API';
is $schema->description, 'The API to calculate BMI';
my $routes = $schema->get_routes;
is scalar @$routes, 1;
is $routes->[0]->route, '/bmi';
t/APISchema-DSL.t view on Meta::CPAN
definition => {
type => 'object',
description => 'Body mass index',
properties => {
value => {
type => 'number',
description => 'bmi value',
example => 19.5,
},
},
required => ['value'],
},
}, {
title => 'figure',
definition => {
type => 'object',
description => 'Figure, which includes weight and height',
properties => {
weight => {
type => 'number',
description => 'Weight(kg)',
example => 50,
},
height => {
type => 'number',
description => 'Height(m)',
example => 1.6,
},
},
required => ['weight', 'height'],
},
} ];
my $routes = $schema->get_routes;
is scalar @$routes, 1;
is $routes->[0]->route, '/bmi';
is $routes->[0]->title, 'BMI API';
is $routes->[0]->description, 'This API calculates your BMI.';
is_deeply $routes->[0]->destination, {
t/APISchema-DSL.t view on Meta::CPAN
type => 'string',
description => decode_utf8('å§'),
example => decode_utf8('å°é£¼'),
},
last_name => {
type => 'string',
description => decode_utf8('å'),
example => decode_utf8('å¼¾'),
},
},
required => ['first_name', 'last_name'],
};
}
t/APISchema-Generator-Markdown.t view on Meta::CPAN
sub generate : Tests {
subtest 'Simple' => sub {
my $schema = t::test::fixtures::prepare_bmi;
my $generator = APISchema::Generator::Markdown->new;
my $markdown = $generator->format_schema($schema);
like $markdown, qr{# BMI API};
like $markdown, qr{^\Q - [BMI API](#route-BMI%20API) - `POST` /bmi\E$}m;
like $markdown, qr!{"height":1.6,"weight":50}!;
like $markdown, qr!|`.` |`object` | | |`required["value"]` |Body mass index |!;
like $markdown, qr!|`.height` |`number` | |`1.6` | |Height(m) |!;
};
subtest 'Complex' => sub {
my $schema = t::test::fixtures::prepare_family;
my $generator = APISchema::Generator::Markdown->new;
my $markdown = $generator->format_schema($schema);
like $markdown, qr{# Family API};
t/APISchema-Resource.t view on Meta::CPAN
sub instantiate : Tests {
my $resource = APISchema::Resource->new(
title => 'Human',
definition => {
type => 'object',
properties => {
name => { type => 'string' },
age => { type => 'integer' },
},
required => ['name', 'age'],
},
);
cmp_deeply $resource, isa('APISchema::Resource') & methods(
title => 'Human',
definition => {
type => 'object',
properties => {
name => { type => 'string' },
age => { type => 'integer' },
},
required => ['name', 'age'],
},
);
}
t/APISchema-Schema.t view on Meta::CPAN
is $schema->get_resource_by_name('user'), undef;
cmp_deeply $schema->get_resources, [];
$schema->register_resource('user' => {
type => 'object',
properties => {
name => { type => 'string' },
age => { type => 'integer' },
},
required => ['name', 'age'],
});
cmp_deeply $schema->get_resource_by_name('user'), isa('APISchema::Resource') & methods(
title => 'user',
definition => {
type => 'object',
properties => {
name => { type => 'string' },
age => { type => 'integer' },
},
required => ['name', 'age'],
},
);
is $schema->get_resource_by_name('not_user'), undef;
cmp_deeply $schema->get_resources, [
$schema->get_resource_by_name('user'),
];
}
t/Plack-Middleware-APISchema-RequestValidator.t view on Meta::CPAN
request_resource => {
parameter => 'figure',
},
);
$schema->register_resource(figure_header => {
type => 'object',
properties => {
'x_weight' => { type => 'number' },
'x_height' => { type => 'number' },
},
required => ['x_weight', 'x_height'],
});
$schema->register_route(
method => 'POST',
route => '/bmi_by_header',
request_resource => {
header => 'figure_header',
},
);
my $middleware = Plack::Middleware::APISchema::RequestValidator->new(schema => $schema);
t/Plack-Middleware-APISchema-RequestValidator.t view on Meta::CPAN
my $server = shift;
my $res = $server->(
POST '/bmi',
Content_Type => 'application/json',
Content => encode_json({}),
);
is $res->code, HTTP_UNPROCESSABLE_ENTITY;
cmp_deeply $res->content, json({
body => {
attribute => 'Valiemon::Attributes::Required',
position => '/$ref/required',
message => "Contents do not match resource 'figure'",
encoding => 'json',
actual => {},
expected => $schema->get_resource_by_name('figure')->definition,
},
});
done_testing;
}
};
t/Plack-Middleware-APISchema-RequestValidator.t view on Meta::CPAN
my $content_type = 'application/x-www-form-urlencoded';
my $res = $server->(
POST '/bmi',
Content_Type => $content_type,
Content => encode_json({weight => 50, height => 1.6}),
);
is $res->code, HTTP_UNPROCESSABLE_ENTITY;
cmp_deeply $res->content, json({
body => {
attribute => 'Valiemon::Attributes::Required',
position => '/$ref/required',
message => "Contents do not match resource 'figure'",
encoding => 'url_parameter',
actual => isa('HASH'),
# XXX: Hash order randomization
# actual => { "{\"weight\":50,\"height\":1.6}" => undef }
expected => $schema->get_resource_by_name('figure')->definition,
},
});
done_testing;
}
t/Plack-Middleware-APISchema-RequestValidator.t view on Meta::CPAN
subtest 'when invalid request by parameter' => sub {
test_psgi $middleware => sub {
my $server = shift;
my $res = $server->(
POST '/bmi_by_parameter?weight=50',
);
is $res->code, HTTP_UNPROCESSABLE_ENTITY;
cmp_deeply $res->content, json({
parameter => {
attribute => 'Valiemon::Attributes::Required',
position => '/$ref/required',
message => "Contents do not match resource 'figure'",
encoding => 'url_parameter',
actual => {
weight => 50,
},
expected => $schema->get_resource_by_name('figure')->definition,
},
});
done_testing;
}
t/Plack-Middleware-APISchema-RequestValidator.t view on Meta::CPAN
test_psgi $middleware => sub {
my $server = shift;
my $res = $server->(
POST '/bmi_by_header',
X_Weight => 50,
);
is $res->code, HTTP_UNPROCESSABLE_ENTITY;
cmp_deeply $res->content, json({
header => {
attribute => 'Valiemon::Attributes::Required',
position => '/$ref/required',
message => "Contents do not match resource 'figure_header'",
encoding => 'perl',
actual => {
content_length => 0,
x_weight => 50,
content_type => "application/x-www-form-urlencoded",
host => "localhost",
},
expected => $schema->get_resource_by_name('figure_header')->definition,
},
t/Plack-Middleware-APISchema-ResponseValidator.t view on Meta::CPAN
response_resource => {
encoding => 'json',
body => 'bmi',
},
);
$schema->register_resource(bmi_header => {
type => 'object',
properties => {
'x_value' => { type => 'number' },
},
required => ['x_value'],
});
$schema->register_route(
method => 'POST',
route => '/bmi_by_header',
response_resource => {
header => 'bmi_header',
},
);
my $content_type;
t/Plack-Middleware-APISchema-ResponseValidator.t view on Meta::CPAN
$content_type = 'application/x-www-form-urlencoded';
$json = encode_json({value => 19.5});
$header = [];
my $server = shift;
my $res = $server->(POST '/bmi');
is $res->code, 500;
is $res->header('X-Error-Cause'), 'Plack::Middleware::APISchema::ResponseValidator+Valiemon';
cmp_deeply $res->content, json({
body => {
attribute => 'Valiemon::Attributes::Required',
position => '/$ref/required',
message => "Contents do not match resource 'bmi'",
encoding => 'url_parameter',
actual => {
'{"value":19.5}' => undef,
},
expected => $schema->get_resource_by_name('bmi')->definition,
},
});
done_testing;
}
t/Plack-Middleware-APISchema-ResponseValidator.t view on Meta::CPAN
$content_type = 'application/json';
$json = encode_json({});
$header = [ 'X-Foo' => 1 ];
my $server = shift;
my $res = $server->(POST '/bmi_by_header');
is $res->code, 500;
is $res->header('X-Error-Cause'), 'Plack::Middleware::APISchema::ResponseValidator+Valiemon';
cmp_deeply $res->content, json({
header => {
attribute => "Valiemon::Attributes::Required",
position => '/$ref/required',
message => "Contents do not match resource 'bmi_header'",
encoding => 'perl',
expected => $schema->get_resource_by_name('bmi_header')->definition,
actual => {
content_type => "application/json",
"x_foo" => 1,
},
},
});
done_testing;
t/fixtures/bmi.def view on Meta::CPAN
type => 'number',
description => 'Weight(kg)',
example => 50,
},
height => {
type => 'number',
description => 'Height(m)',
example => 1.6,
},
},
required => ['weight', 'height'],
};
resource bmi => {
type => 'object',
description => 'Body mass index',
properties => {
value => {
type => 'number',
description => 'bmi value',
example => 19.5,
},
},
required => ['value'],
};
POST '/bmi' => {
title => 'BMI API',
description => 'This API calculates your BMI.',
destination => {
controller => 'BMI',
action => 'calculate',
},
request => 'figure',
t/fixtures/boolean.def view on Meta::CPAN
resource value => {
type => 'object',
description => 'the result',
properties => {
value => {
type => 'boolean',
description => 'The Value',
example => \1,
},
},
required => ['value'],
};
t/fixtures/example-null.def view on Meta::CPAN
resource value => {
type => 'object',
description => 'the result',
properties => {
value => {
type => 'null',
description => 'The Value',
example => undef,
},
},
required => ['value'],
};
t/fixtures/family.def view on Meta::CPAN
type => 'string',
description => 'The name of the person',
example => 'Alice',
},
age => {
type => 'integer',
description => 'The age of the person',
example => 16,
},
},
required => ['name', 'age'],
};
resource target => {
type => 'object',
description => 'Target of retrieving information',
properties => {
name => { '$ref' => '#/resource/person/properties/name' },
},
};
t/fixtures/user.def view on Meta::CPAN
type => 'string',
description => 'å§',
example => 'å°é£¼',
},
last_name => {
type => 'string',
description => 'å',
example => 'å¼¾',
},
},
required => ['first_name', 'last_name'],
};