Kossy - Sinatra-ish Simple and Clear web application framework
% kossy-setup MyApp
% cd MyApp
% plackup app.psgi
## lib/MyApp/Web.pm
use Kossy;
get '/' => sub {
my ( $self, $c ) = @_;
$c->render('index.tx', { greeting => "Hello!" });
};
get '/json' => sub {
my ( $self, $c ) = @_;
my $result = $c->req->validator([
'q' => {
default => 'Hello',
rule => [
[['CHOICE',qw/Hello Bye/],'Hello or Bye']
],
}
]);
$c->render_json({ greeting => $result->valid->get('q') });
};
1;
## views/index.tx
: cascade base
: around content -> {
<: $greeting :>
: }
Kossy is Sinatra-ish Simple and Clear web application framework, which is based upon Plack, Router::Boom, Text::Xslate and build-in Form-Validator. That's suitable for small application and rapid development.
Kossy exports some methods to building application
-
my $kossy = Kossy->new( root_dir => $root_dir );
Create instance of the application object.
-
my $root_dir = $kossy->root_dir();
accessor to root directory of the application
-
my $app = $kossy->psgi();
return PSGI application
-
filter
makes application wrapper like plack::middlewares.
filter 'set_title' => sub { my $app:CODE = shift; sub { my ( $self:Kossy, $c:Kossy::Connection ) = @_; $c->stash->{site_name} = __PACKAGE__; $app->($self,$c); } };
-
get path:String => [[filters] =>] CODE
-
post path:String => [[filters] =>] CODE
setup router and dispatch code
get '/' => [qw/set_title/] => sub { my ( $self:Kossy, $c:Kossy::Connection ) = @_; $c->render('index.tx', { greeting => "Hello!" }); }; get '/json' => sub { my ( $self:Kossy, $c:Kossy::Connection ) = @_; $c->render_json({ greeting => "Hello!" }); };
dispatch code shall return Kossy::Response object or PSGI response ArrayRef or String.
-
router 'HTTP_METHOD'|['METHOD'[,'METHOD']] => path:String => [[filters] =>] CODE
adds routing rule other than GET and POST
router 'PUT' => '/put' => sub { my ( $self:Kossy, $c:Kossy::Connection ) = @_; $c->render_json({ greeting => "Hello!" }); };
per-request object, herds request and response
-
req:Kossy::Request
-
res:Kossy::Response
-
stash:HashRef
-
args:HashRef
path parameters captured by Router::Boom
get '/user/:id' => sub { my ($self, $c) = @_; my $id = $c->args->{id}; ... };
-
halt(status_code, message)
die and response immediately
-
redirect($uri,status_code): Kossy::Response
-
render($file,$args): Kossy::Response
calls Text::Xslate->render makes response. template files are searching in root_dir/views directory
template syntax is Text::Xslate::Syntax::Kolon, can use Kossy::Connection object and fillinform block.
## template.tx : block form | fillinform( $c.req ) -> { <head> <title><: $c.stash.title :></title> </head> <body> <form action="<: $c.req.uri_for('/post') :>"> <input type="text" size="10" name="title" /> <textarea name="body" rows="20" cols="90"></textarea> </form> </body> : }
also can use Text::Xslate::Bridge::TT2Like and Number::Format methods in your template
-
render_json($args): Kossy::Response
serializes arguments with JSON and makes response
This method escapes '<', '>', and '+' characters by "\uXXXX" form. Browser don't detects the JSON as HTML. And also this module outputs "X-Content-Type-Options: nosniff" header for IEs.
render_json have a JSON hijacking detection feature same as Amon2::Plugin::Web::JSON. This returns "403 Forbidden" response if following pattern request.
- The request have 'Cookie' header.
- The request doesn't have 'X-Requested-With' header.
- The request contains /android/i string in 'User-Agent' header.
- Request method is 'GET'
This class is child class of Plack::Request, decode query/body parameters automatically. Return value of $req->param(), $req->body_parameters, etc. is the decoded value.
-
uri_for($path,$args):String
build absolute URI with path and $args
my $uri = $c->req->uri_for('/login',[ arg => 'Hello']);
-
validator($rule):Kossy::Validator::Result
validate parameters using Kossy::Validator
my $result = $c->req->validator([ 'q' => [['NOT_NULL','query must be defined']], 'level' => { default => 'M', rule => [ [['CHOICE',qw/L M Q H/],'invalid level char'], ], }, ]); my $val = $result->valid('q'); my $val = $result->valid('level');
-
body_parameters_raw
-
query_parameters_raw
-
parameters_raw
-
param_raw
These methods are the accessor to raw values. 'raw' means the value is not decoded.
-
body_parameters
Accessor to decoded body parameters. It's Hash::MultiValue object.
-
query_parameters
Accessor to decoded query parameters. It's Hash::MultiValue object.
-
json_parameters
Accessor to decoded JSON body parameters. It's NOT Hash::MultiValue object.
post '/api' => sub { my ($self, $c) = @_; my $foo = $c->req->json_parameters->{foo}; # bar }; # requrest # $ua->requrest( # HTTP::Request->new( # "POST", # "http://example.com/api", # [ "Content-Type" => 'application/json', "Content-Length" => 13 ], # '{"foo":"bar"}' # ) # );
NOTE: Not need to set
kossy.request.parse_json_body
to 1
This class is child class of Plack::Response
-
X-Frame-Options
By default, Kossy outputs "X-Frame-Options: DENY". You can change this header
get '/iframe' => sub { my ($self, $c) = @_; $c->res->header('X-Frame-Options','SAMEORIGIN'); # or remove from response header # delete $c->res->headers->remove_header('X-Frame-Options'); .. }
(Default: DENY)
-
kossy.request.parse_json_body
If enabled, Kossy will decode json in the request body that has "application/json" content header
post '/api' => sub { my ($self, $c) = @_; $c->env->{'kossy.request.parse_json_body'} = 1; my val = $c->req->param('foo'); # bar } # requrest # $ua->requrest( # HTTP::Request->new( # "POST", # "http://example.com/api", # [ "Content-Type" => 'application/json', "Content-Length" => 13 ], # '{"foo":"bar"}' # ) # );
-
$XSLATE_CACHE, $XSLATE_CACHE_DIR
Change xslate's cache level and cache directory.
local $Kossy::XSLATE_CACHE = 2; local $Kossy::XSLATE_CACHE_DIR = $dir; my $app = MyApp::Web->psgi;
By default, $XSLATE_CACHE is 1, $XSLATE_CACHE_DIR is undef. use Xslate's default.
-
$SECURITY_HEADER
If disabled, Kossy does not set X-Frame-Options and X-XSS-Protection. enabled by default.
local $Kossy::SECURITY_HEADER = 0; my $app = MyApp::Web->psgi;
Can not change $Kossy::SECURITY_HEADER in your WebApp. It's need to set at build time.
This is useful for the benchmark :-)
-
$JSON_SERIALIZER
changes the JSON serializer:
use Cpanel::JSON::XS; use Cpanel::JSON::XS::Type; local $Kossy::JSON_SERIALIZER = Cpanel::JSON::XS->new()->allow_blessed(1)->convert_blessed(1)->ascii(0); get '/' => sub { my ($self, $c) = @_; return $c->render_json({ a => '234' }, { a => JSON_TYPE_INT }); }; my $app = __PACKAGE__->psgi;
Masahiro Nagano <kazeburo {at} gmail.com>
Kossy is small waf, that has only 400 lines code. so easy to reading framework code and customize it. Sinatra-ish router, build-in templating, validators and zero-configuration features are suitable for small application and rapid development.
Kossy::Headers uses HTTP::Headers::Fast code. Here is LICENSE of HTTP::Headers::Fast
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.