Raisin - REST-like API micro-framework for Perl.
use Raisin::API; my %USERS = ( 1 => { name => 'Darth Wader', password => 'deathstar', email => 'darth@deathstar.com', }, 2 => { name => 'Luke Skywalker', password => 'qwerty', email => 'l.skywalker@jedi.com', }, ); namespace '/user' => sub { params [ #required/optional => [name, type, default, regex] optional => ['start', 'Raisin::Types::Integer', 0], optional => ['count', 'Raisin::Types::Integer', 10], ], get => sub { my $params = shift; my ($start, $count) = ($params->{start}, $params->{count}); my @users = map { { id => $_, %{ $USERS{$_} } } } sort { $a <=> $b } keys %USERS; $start = $start > scalar @users ? scalar @users : $start; $count = $count > scalar @users ? scalar @users : $count; my @slice = @users[$start .. $count]; { data => \@slice } }; get 'all' => sub { my @users = map { { id => $_, %{ $USERS{$_} } } } sort { $a <=> $b } keys %USERS; { data => \@users } }; params [ required => ['name', 'Raisin::Types::String'], required => ['password', 'Raisin::Types::String'], optional => ['email', 'Raisin::Types::String', undef, qr/.+\@.+/], ], post => sub { my $params = shift; my $id = max(keys %USERS) + 1; $USERS{$id} = $params; { success => 1 } }; route_param 'id' => 'Raisin::Types::Integer', sub { get sub { my $params = shift; %USERS{ $params->{id} }; }; }; }; run;
Raisin is a REST-like API micro-framework for Perl. It's designed to run on Plack, providing a simple DSL to easily develop RESTful APIs. It was inspired by Grape.
Adds a route to application.
namespace user => sub { ... };
Define a route parameter as a namespace route_param.
route_param
route_param id => 'Raisin::Types::Integer', sub { ... };
It is are shortcuts to route restricted to the corresponding HTTP method.
route
Each method could consists of max three parameters:
params - optional only if didn't starts from params keyword, required otherwise;
path - optional;
subroutine - required;
Where only subroutine is required.
subroutine
get sub { 'GET' }; delete 'all' => sub { 'OK' }; params [ required => ['id', 'Raisin::Types::Integer'], optional => ['key', 'Raisin::Types::String'], ], get => sub { 'GET' }; params [ required => ['id', 'Raisin::Types::Integer'], optional => ['name', 'Raisin::Types::String'], ], put => 'all' => sub { 'PUT' };
An alias for $self->req, this provides quick access to the Raisin::Request object for the current route.
$self->req
Use req to get access to the request headers, params, etc.
req
use DDP; p req->headers; p req->params; say req->header('X-Header');
See also Plack::Request.
An alias for $self->res, this provides quick access to the Raisin::Response object for the current route.
$self->res
Use res to set up response parameters.
res
res->status(403); res->headers(['X-Application' => 'Raisin Application']);
See also Plack::Response.
An alias for $self->params that gets the GET and POST parameters. When used with no arguments, it will return an array with the names of all http parameters. Otherwise, it will return the value of the requested http parameter.
$self->params
Returns Hash::MultiValue object.
say param('key'); # -> value say param(); # -> { key => 'value' }
An alias for $self->session that returns (optional) psgix.session hash. When it exists, you can retrieve and store per-session data from and to this hash.
$self->session
# store param session->{hello} = 'World!'; # read param say session->{name};
Set an API version header.
api_version 1.23;
Loads a plugin from Raisin::Plugin::Format namespace.
Raisin::Plugin::Format
Already exists Raisin::Plugin::Format::JSON and Raisin::Plugin::Format::YAML.
api_format 'JSON';
Loads a Raisin module. The module options may be specified after the module name. Compatible with Kelp modules.
plugin 'Logger' => outputs => [['Screen', min_level => 'debug']];
Loads middleware to your application.
middleware '+Plack::Middleware::Session' => { store => 'File' }; middleware '+Plack::Middleware::ContentLength'; middleware 'Runtime'; # will be loaded Plack::Middleware::Runtime
Mount multiple API implementations inside another one. These don't have to be different versions, but may be components of the same API.
In RaisinApp.pm:
RaisinApp.pm
package RaisinApp; use Raisin::API; api_format 'JSON'; mount 'RaisinApp::User'; mount 'RaisinApp::Host'; 1;
Creates and returns a PSGI ready subroutine, and makes the app ready for Plack.
Plack
Request parameters are available through the params hash object. This includes GET, POST and PUT parameters, along with any named parameters you specify in your route strings.
Parameters are automatically populated from the request body on POST and PUT for form input, JSON and YAML content-types.
In the case of conflict between either of:
route string parameters
GET, POST and PUT parameters
the contents of the request body on POST and PUT
route string parameters will have precedence.
Query string and body parameters will be merged (see "parameters" in Plack::Request)
You can define validations and coercion options for your parameters using a params block.
Parameters can be required and optional. optional parameters can have a default value.
required
optional
get params => [ required => ['name', 'Raisin::Types::String'], optional => ['number', 'Raisin::Types::Integer', 10], ], sub { my $params = shift; "$params->{number}: $params->{name}"; };
Positional arguments:
name
type
default value
regex
Optional parameters can have a default value.
Here is built-in types
Raisin::Types::Float
Raisin::Types::Integer
Raisin::Types::String
Raisin::Types::Scalar
You can create your own types as well. See examples in Raisin::Types. Also see Raisin::Types::Base.
This blocks can be executed before or after every API call, using before, after, before_validation and after_validation.
before
after
before_validation
after_validation
Before and after callbacks execute in the following order:
The block applies to every API call
before sub { my $self = shift; say $self->req->method . "\t" . $self->req->path; }; after_validation sub { my $self = shift; say $self->res->body; };
Steps 3 and 4 only happen if validation succeeds.
By default, Raisin supports YAML, JSON, and TEXT content-types. The default format is TEXT.
YAML
JSON
TEXT
Response format can be determined by Accept header.
Serialization takes place automatically. For example, you do not have to call encode_json in each JSON API implementation.
encode_json
Your API can declare which types to support by using api_format.
api_format
Custom formatters for existing and additional types can be defined with a Raisin::Plugin::Format.
Call JSON::encode_json and JSON::decode_json.
JSON::encode_json
JSON::decode_json
Call YAML::Dump and JSON::Load.
YAML::Dump
JSON::Load
Call Data::Dumper->Dump if output data is not a string.
Data::Dumper->Dump
The order for choosing the format is the following.
Use the value of ther Accept header.
Accept
Use the api_format if specified.
Fallback to TEXT.
TODO Raisin::Plugin::Auth Raisin::Plugin::Auth::Basic Raisin::Plugin::Auth::Token
Raisin has a built-in logger based on Log::Dispatch. You can enable it by
Log::Dispatch
Exports logger subroutine.
logger
logger(debug => 'Debug!'); logger(warn => 'Warn!'); logger(error => 'Error!');
See Raisin::Plugin::Logger.
You can see application routes with the following command:
$ raisin --routes examples/singular/routes.pl GET /user GET /user/all POST /user GET /user/{id} PUT /user/{id} GET /user/{id}/bump PUT /user/{id}/bump GET /failed
Verbose output with route parameters:
$ raisin --routes --params examples/singular/routes.pl GET /user optional: `start', type: Integer, default: 0 optional: `count', type: Integer, default: 10 GET /user/all POST /user required: `name', type: String required: `password', type: String optional: `email', type: String GET /user/{id} required: `id', type: Integer PUT /user/{id} optional: `password', type: String optional: `email', type: String required: `id', type: Integer GET /user/{id}/bump required: `id', type: Integer PUT /user/{id}/bump required: `id', type: Integer GET /failed GET /params
Swagger compatible API documentations.
plugin 'APIDocs';
Documentation will be available on http://<url>/api-docs URL. So you can use this URL in Swagger UI.
http://<url>/api-docs
For more see Raisin::Plugin::APIDocs.
You can easily add any Plack middleware to your application using middleware keyword. See "middleware" in Raisin.
middleware
Raisin can be extended using custom modules. Each new module must be a subclass of the Raisin::Plugin namespace. Modules' job is to initialize and register new methods into the web application class.
Raisin::Plugin
For more see "plugin" in Raisin and Raisin::Plugin.
See Plack::Test, Test::More and etc.
my $app = Plack::Util::load_psgi("$Bin/../script/raisinapp.pl"); test_psgi $app, sub { my $cb = shift; my $res = $cb->(GET '/user'); subtest 'GET /user' => sub { if (!is $res->code, 200) { diag $res->content; BAIL_OUT 'FAILED!'; } my $got = Load($res->content); isdeeply $got, $expected, 'Data!'; }; };
Deploying a Raisin application is done the same way any other Plack application is deployed:
> plackup -E deployment -s Starman app.psgi
use Plack::Builder; use RaisinApp; use KelpApp; builder { mount '/' => KelpApp->new->run; mount '/api/rest' => RaisinApp->new; };
use Plack::Builder; use Dancer ':syntax'; use Dancer::Handler; use RaisinApp; my $dancer = sub { setting appdir => '/home/dotcloud/current'; load_app "My::App"; Dancer::App->set_running_app("My::App"); my $env = shift; Dancer::Handler->init_request_headers($env); my $req = Dancer::Request->new(env => $env); Dancer->dance($req); }; builder { mount "/" => $dancer; mount '/api/rest' => RaisinApp->new; };
use Plack::Builder; use RaisinApp; builder { mount '/' => builder { enable 'Deflater'; require 'my_mojolicious-lite_app.pl'; }; mount '/api/rest' => RaisinApp->new; };
Also see Plack::Builder, Plack::App::URLMap.
See examples.
https://github.com/khrt/Raisin
Artur Khabibullin - rtkh <at> cpan.org
This module was inspired both by Grape and Kelp, which was inspired by Dancer, which in its turn was inspired by Sinatra.
This module and all the modules in this package are governed by the same license as Perl itself.
To install Raisin, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Raisin
CPAN shell
perl -MCPAN -e shell install Raisin
For more information on module installation, please visit the detailed CPAN module installation guide.