Intro to Dancer - OSCON 2011
-
Upload
mrallen1 -
Category
Technology
-
view
2.130 -
download
1
description
Transcript of Intro to Dancer - OSCON 2011
Introduction to Dancer!A Sinatra-inspired web framework for Perl!!!Mark [email protected]!http://byte-me.org!http://github.com/mrallen1!http://bitbucket.org/mrallen1!https://metacpan.org/author/MALLEN!
The Old Days!
The Old Days
cgi-lib.pl (1994-1998)!!
The Old Days
CGI.pm (1995-2011)!!
The Old Days
mod_perl (1996-2011)!!
The Old Days
Matt’s Script Archive (1995-2011)!
!Use instead:!
http://nms-cgi.sourceforge.net/!(Thanks London.pm)!
!
The Old Days
use CGI.pm;!!my $q = CGI->new();!my ($a, $b, $c) = $q->param();!!if ($a !~ /\d+/) {!!print $q->header(-status => ‘400 Bad request’);!!print “<h1>Value of ‘a’ ($a) is not an integer</h1>”;!!exit 0;!
}!# yada, yada!
The Old Days
.htaccess Hack!!!RewriteEngine On!RewriteBase /abc!!RewriteRule ^(.*)/(.*)/(.*)$ !abc.pl?a=$1;b=$2;c=$3!!
The Old Days
.htaccess Hack!!# Use Web 2.0 style URLs, but keep CGI interface!RewriteEngine On!RewriteBase /abc!!RewriteRule ^(.*)/(.*)/(.*)$ !abc.pl?a=$1;b=$2;c=$3!!
The Old Days
.htaccess Hack!!# Use Web 2.0 style URLs, but keep CGI interface!RewriteEngine On!RewriteBase /abc!!RewriteRule ^(.*)/(.*)/(.*)$ !abc.pl?a=$1;b=$2;c=$3!!
The Old Days
.htaccess Hack!!# Use Web 2.0 style URLs, but keep CGI interface!RewriteEngine On!RewriteBase /abc!!RewriteRule ^(.*)/(.*)/(.*)$ !abc.pl?a=$1;b=$2;c=$3!!
The Old Days
h"p://flic.kr/p/5TWTR4
The Old Days
h"p://flic.kr/p/5TWTR4
Move over bacon, now there’s something leaner.!
!
Move over bacon
Perl 5 Renaissance:!• Moose!• DBIx::Class!• Plack!• Tons of great new stuff in
core perl 5.10+!!!
Move over bacon
Do you find Catalyst too !heavyweight or intimidating?!
!
Move over bacon
!Me too!!
!!
Move over bacon
Enter Dancer!!
Move over bacon
Other Sinatra-inspired frameworks:!• Mojo (Perl – TMTOWTDI)!• Flask (Python)!• Fitzgerald (PHP)!• Express (Node.js)!!
Move over bacon
Dancer is:!• Easy to learn!• Expressive!• Efficient!
Dancer is ...!!
Easy to learn!
Easy to learn
Basic Dancer concepts:!• One (or more) HTTP verb(s)!• A route!• A handler!
Easy to learn
use Dancer;!!get '/' => sub {! return 'Hello World!\n’;!};!!start;!
Easy to learn
use Dancer;!!get '/' => sub {! return 'Hello World!\n’;!};!!start;!
Easy to learn
use Dancer;!!get '/' => sub {! return 'Hello World!\n’;!};!!start;!
Easy to learn
use Dancer;!!get '/' => sub {! return 'Hello World!\n’;!};!!start;!
Easy to learn
use Dancer;!!get '/' => sub {! return 'Hello World!\n’;!};!!start;!
Easy to learn
Easy to learn
get '/' => sub {! my $db = connect_db();! my $sql = 'select id, title, text from entries order by id desc’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute or die $sth->errstr;! template 'show_entries.tt', {! 'msg' => get_flash(),! 'add_entry_url' => uri_for('/add'),! 'entries' => $sth->fetchall_hashref('id'),! };!};!
Easy to learn
get '/' => sub {! my $db = connect_db();! my $sql = 'select id, title, text from entries order by id desc’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute or die $sth->errstr;! template 'show_entries.tt', {! 'msg' => get_flash(),! 'add_entry_url' => uri_for('/add'),! 'entries' => $sth->fetchall_hashref('id'),! };!};!
Easy to learn
get '/' => sub {! my $db = connect_db();! my $sql = 'select id, title, text from entries order by id desc’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute or die $sth->errstr;! template 'show_entries.tt', {! 'msg' => get_flash(),! 'add_entry_url' => uri_for('/add'),! 'entries' => $sth->fetchall_hashref('id'),! };!};!
Easy to learn
get '/' => sub {! my $db = connect_db();! my $sql = 'select id, title, text from entries order by id desc’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute or die $sth->errstr;! template 'show_entries.tt', {! 'msg' => get_flash(),! 'add_entry_url' => uri_for('/add'),! 'entries' => $sth->fetchall_hashref('id'),! };!};!
Easy to learn
get '/' => sub {! my $db = connect_db();! my $sql = 'select id, title, text from entries order by id desc’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute or die $sth->errstr;! template 'show_entries.tt', {! 'msg' => get_flash(),! 'add_entry_url' => uri_for('/add'),! 'entries' => $sth->fetchall_hashref('id'),! };!};!
Easy to learn
get '/' => sub {! my $db = connect_db();! my $sql = 'select id, title, text from entries order by id desc’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute or die $sth->errstr;! template 'show_entries.tt', {! 'msg' => get_flash(),! 'add_entry_url' => uri_for('/add'),! 'entries' => $sth->fetchall_hashref('id'),! };!};!
Easy to learn
get '/' => sub {! my $db = connect_db();! my $sql = 'select id, title, text from entries order by id desc’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute or die $sth->errstr;! template 'show_entries.tt', {! 'msg' => get_flash(),! 'add_entry_url' => uri_for('/add'),! 'entries' => $sth->fetchall_hashref('id'),! };!};!
Easy to learn
get '/' => sub {! my $db = connect_db();! my $sql = 'select id, title, text from entries order by id desc’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute or die $sth->errstr;! template 'show_entries.tt', {! 'msg' => get_flash(),! 'add_entry_url' => uri_for('/add'),! 'entries' => $sth->fetchall_hashref('id'),! };!};!
Easy to learn
get '/' => sub {! my $db = connect_db();! my $sql = 'select id, title, text from entries order by id desc’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute or die $sth->errstr;! template 'show_entries.tt', {! 'msg' => get_flash(),! 'add_entry_url' => uri_for('/add'),! 'entries' => $sth->fetchall_hashref('id'),! };!};!
Easy to learn
show_entries.tt!!<ul class=entries>! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>! <li><h2><% entries.$id.title %></h2>! <% entries.$id.text %>! <% END %>! <% ELSE %>! <li><em>Unbelievable. No entries here so far</em>! <% END %>!</ul>!!
Easy to learn
show_entries.tt!!<ul class=entries>! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>! <li><h2><% entries.$id.title %></h2>! <% entries.$id.text %>! <% END %>! <% ELSE %>! <li><em>Unbelievable. No entries here so far</em>! <% END %>!</ul>!!
Easy to learn
show_entries.tt!!<ul class=entries>! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>! <li><h2><% entries.$id.title %></h2>! <% entries.$id.text %>! <% END %>! <% ELSE %>! <li><em>Unbelievable. No entries here so far</em>! <% END %>!</ul>!!
Easy to learn
show_entries.tt!!<ul class=entries>! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>! <li><h2><% entries.$id.title %></h2>! <% entries.$id.text %>! <% END %>! <% ELSE %>! <li><em>Unbelievable. No entries here so far</em>! <% END %>!</ul>!!
Easy to learn
get '/' => sub {! my $db = connect_db();! my $sql = 'select id, title, text from entries order by id desc’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute or die $sth->errstr;! template 'show_entries.tt', {! 'msg' => get_flash(),! 'add_entry_url' => uri_for('/add'),! 'entries' => $sth->fetchall_hashref('id'),! };!};!
Easy to learn
show_entries.tt!!<ul class=entries>! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>! <li><h2><% entries.$id.title %></h2>! <% entries.$id.text %>! <% END %>! <% ELSE %>! <li><em>Unbelievable. No entries here so far</em>! <% END %>!</ul>!!
Easy to learn
show_entries.tt!!<ul class=entries> <!– CSS class -->! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>! <li><h2><% entries.$id.title %></h2>! <% entries.$id.text %>! <% END %>! <% ELSE %>! <li><em>Unbelievable. No entries here so far</em>! <% END %>!</ul>!!
Easy to learn
Directory structure !
dancr/!├── dancr.pl!├── public!│ └── css!│ └── style.css!└── views! ├── layouts! │ └── main.tt! ├── login.tt! └── show_entries.tt!
Easy to learn
Directory structure !
dancr/!├── dancr.pl!├── public!│ └── css!│ └── style.css!└── views! ├── layouts! │ └── main.tt! ├── login.tt! └── show_entries.tt!
Easy to learn
Directory structure !
dancr/!├── dancr.pl!├── public!│ └── css!│ └── style.css!└── views! ├── layouts! │ └── main.tt! ├── login.tt! └── show_entries.tt!
Easy to learn
Directory structure !
dancr/!├── dancr.pl!├── public!│ └── css!│ └── style.css!└── views! ├── layouts! │ └── main.tt! ├── login.tt! └── show_entries.tt!
Dancer is...!!
Expressive!
Expressive
post '/add' => sub {! if ( not session('logged_in') ) {! return send_error("Not logged in", 401);! }!! my $db = connect_db();! my $sql = 'insert into entries (title, text) values (?, ?)’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute(params->{'title'}, params->{'text'}) or die $sth->errstr;!! set_flash('New entry posted!');! redirect '/’;!};!
Expressive
post '/add' => sub {! if ( not session('logged_in') ) {! return send_error("Not logged in", 401);! }!! my $db = connect_db();! my $sql = 'insert into entries (title, text) values (?, ?)’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute(params->{'title'}, params->{'text'}) or die $sth->errstr;!! set_flash('New entry posted!');! redirect '/’;!};!
Expressive
post '/add' => sub {! if ( not session('logged_in') ) {! return send_error("Not logged in", 401);! }!! my $db = connect_db();! my $sql = 'insert into entries (title, text) values (?, ?)’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute(params->{'title'}, params->{'text'}) or die $sth->errstr;!! set_flash('New entry posted!');! redirect '/’;!};!
Expressive
post '/add' => sub {! if ( not session('logged_in') ) {! return send_error("Not logged in", 401);! }!! my $db = connect_db();! my $sql = 'insert into entries (title, text) values (?, ?)’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute(params->{'title'}, params->{'text'}) or die $sth->errstr;!! set_flash('New entry posted!');! redirect '/’;!};!
Expressive
post '/add' => sub {! if ( not session('logged_in') ) {! return send_error("Not logged in", 401);! }!! my $db = connect_db();! my $sql = 'insert into entries (title, text) values (?, ?)’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute(params->{'title'}, params->{'text'}) or die $sth->errstr;!! set_flash('New entry posted!');! redirect '/’;!};!
Expressive
post '/add' => sub {! if ( not session('logged_in') ) {! return send_error("Not logged in", 401);! }!! my $db = connect_db();! my $sql = 'insert into entries (title, text) values (?, ?)’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute(params->{'title'}, params->{'text'}) or die $sth->errstr;!! set_flash('New entry posted!');! redirect '/’;!};!
Expressive
post '/add' => sub {! if ( not session('logged_in') ) {! return send_error("Not logged in", 401);! }!! my $db = connect_db();! my $sql = 'insert into entries (title, text) values (?, ?)’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute(params->{'title'}, params->{'text'}) or die $sth->errstr;!! set_flash('New entry posted!');! redirect '/’;!};!
Expressive
Little Bobby Tables!
h"p://xkcd.com/327/
Expressive
post '/add' => sub {! if ( not session('logged_in') ) {! return send_error("Not logged in", 401);! }! # http://bobby-tables.com! my $db = connect_db();! my $sql = 'insert into entries (title, text) values (?, ?)’;! my $sth = $db->prepare($sql) or die $db->errstr;! $sth->execute(params->{'title'}, params->{'text'}) or die $sth->errstr;!! set_flash('New entry posted!');! redirect '/’;!};!
Expressive
Expressive
Configuration !• Session Engine!• Template Engine!• Logging !• Plugins!
Expressive
Configuration Examples!set 'session' => 'Simple'; set 'template' =>'template_toolkit'; set 'logger' => 'console'; set 'log' => 'debug'; set 'show_errors' => 1; !
Expressive
Configuration Examples!set 'session' => 'Simple'; set 'template' =>'template_toolkit'; set 'logger' => 'console'; set 'log' => 'debug'; set 'show_errors' => 1; !
Expressive
Configuration Use any non-reserved key/value pair.set 'username' => 'admin'; set 'password' => 'password';!!
Expressive
Routes with regex!!get qr{\A\/(?<code>[A-Za-z0-9]+)\Z} => sub {! my $decode = decode_base36( uc captures->{'code'}! );! ...;!};!
Expressive
Routes with regex!!get qr{\A\/(?<code>[A-Za-z0-9]+)\Z} => sub {! my $decode = decode_base36( uc captures->{'code'}! );! ...;!};!
Expressive
Routes with regex!!use v5.10; get qr{\A\/(?<code>[A-Za-z0-9]+)\Z} => sub {! my $decode = decode_base36( uc captures->{'code'}! );! ...;!};!
Expressive
Routes with regex!!use v5.10; get qr{\A\/(?<code>[A-Za-z0-9]+)\Z} => sub {! my $decode = decode_base36( uc captures->{'code'}! );! ...;!};!
Expressive
Routes with named params!!get '/:code/stats' => sub {! my $decode = decode_base36( uc params->{'code'} );! ...;!};!
Expressive
Routes with named params!!get '/:code/stats' => sub {! my $decode = decode_base36( uc params->{'code'} );! ...;!};!
Expressive
Routes with named params!!get qr{^/(.+)/stats$} => sub { params(‘code’) = $1; # input sanity goes here ...; };!
Expressive
use CGI.pm;!!my $q = CGI->new();!my ($a, $b, $c) = $q->param();!!if ($a !~ /\d+/) {!!print $q->header(-status => ‘400 Bad request’);!!print “<h1>Value of ‘a’ ($a) is not an integer</h1>”;!!exit 0;!
}!# yada, yada!
Expressive
!!!!use v5.10; use Dancer; !get qr{/(?<a>\d+)/(?<b>.+)/(?<c>.+)} => sub {! # Route will only match if a is an integer! # No more sanitation/validation necessary ...; };!!
Dancer is...!
Efficient!
Efficient
any ['get', 'post'] => '/login' => sub {! my $err;! if ( request->is_post ) {! if ( params->{'username'} ne setting('username') ) {! $err = "Invalid username”;! }! elsif ( params->{'password'} ne setting('password') ) {! $err = "Invalid password”;! }! else {! session 'logged_in' => true;! set_flash('You are logged in.');! redirect '/’;! }! }! template 'login.tt', {! 'err' => $err,! };!};!
Efficient
any ['get', 'post'] => '/login' => sub {! my $err;! if ( request->is_post ) {! if ( params->{'username'} ne setting('username') ) {! $err = "Invalid username”;! }! elsif ( params->{'password'} ne setting('password') ) {! $err = "Invalid password”;! }! else {! session 'logged_in' => true;! set_flash('You are logged in.');! redirect '/’;! }! }! template 'login.tt', {! 'err' => $err,! };!};!
Efficient
any ['get', 'post'] => '/login' => sub {! my $err;! if ( request->is_post ) {! if ( params->{'username'} ne setting('username') ) {! $err = "Invalid username”;! }! elsif ( params->{'password'} ne setting('password') ) {! $err = "Invalid password”;! }! else {! session 'logged_in' => true;! set_flash('You are logged in.');! redirect '/’;! }! }! template 'login.tt', {! 'err' => $err,! };!};!
Efficient
any ['get', 'post'] => '/login' => sub {! my $err;! if ( request->is_post ) {! if ( params->{'username'} ne setting('username') ) {! $err = "Invalid username”;! }! elsif ( params->{'password'} ne setting('password') ) {! $err = "Invalid password”;! }! else {! session 'logged_in' => true;! set_flash('You are logged in.');! redirect '/’;! }! }! template 'login.tt', {! 'err' => $err,! };!};!
Efficient
any ['get', 'post'] => '/login' => sub {! my $err;! if ( request->is_post ) {! if ( params->{'username'} ne setting('username') ) {! $err = "Invalid username”;! }! elsif ( params->{'password'} ne setting('password') ) {! $err = "Invalid password”;! }! else {! session 'logged_in' => true;! set_flash('You are logged in.');! redirect '/’;! }! }! template 'login.tt', {! 'err' => $err,! };!};!
Efficient
any ['get', 'post'] => '/login' => sub {! my $err;! if ( request->is_post ) {! if ( params->{'username'} ne setting('username') ) {! $err = "Invalid username”;! }! elsif ( params->{'password'} ne setting('password') ) {! $err = "Invalid password”;! }! else {! session 'logged_in' => true;! set_flash('You are logged in.');! redirect '/’;! }! }! template 'login.tt', {! 'err' => $err,! };!};!
Efficient
any ['get', 'post'] => '/login' => sub {! my $err;! if ( request->is_post ) {! if ( params->{'username'} ne setting('username') ) {! $err = "Invalid username”;! }! elsif ( params->{'password'} ne setting('password') ) {! $err = "Invalid password”;! }! else {! session 'logged_in' => true;! set_flash('You are logged in.');! redirect '/’;! }! }! template 'login.tt', {! 'err' => $err,! };!};!
Efficient
any ['get', 'post'] => '/login' => sub {! my $err;! if ( request->is_post ) {! if ( params->{'username'} ne setting('username') ) {! $err = "Invalid username”;! }! elsif ( params->{'password'} ne setting('password') ) {! $err = "Invalid password”;! }! else {! session 'logged_in' => true;! set_flash('You are logged in.');! redirect '/’;! }! }! template 'login.tt', {! 'err' => $err,! };!};!
Efficient
Hook Before / After!• De/Serialization!• Rendering!• Template!• Errors!
Efficient
Forward!!get '/demo/foo/:bar' => sub {! my $bar = param->{'bar'};! # magically use demo DB! ...;! return forward "/foo/$bar";!};! !
Efficient
Prefix!!prefix '/user'; # begins scope!!get '/view/:id' => sub { ...; };!post '/add' => sub { ...; };!any ['get', 'post'] => '/edit/:id' => sub { ...; };!!prefix undef; # ends scope!!get '/view/:id' => sub { ...; };!
Efficient
Dancer Plugins add keywords!• Auto-create RSS feeds!• Integrate Twitter for authN!• DBIx::Class!• DWIM CRUD apps!• ...and more!
Dancer is...!!
Awesome!!
Awesome
Source code:!hg clone https://bitbucket.org/mrallen1/dancr!!
See also:!https://metacpan.org/module/Dancer!!
Install:!curl -L http://cpanmin.us | perl - Dancer YAML Template !
!!
Awesome
Thank You!!!