Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Intro to Dancer YAPC::NA 2012

Intro to Dancer YAPC::NA 2012

A short introduction to the Dancer micro web framework in Perl.

Jade Allen

June 13, 2012
Tweet

More Decks by Jade Allen

Other Decks in Programming

Transcript

  1. Introduction to Dancer! A Sinatra-inspired web framework for Perl! !

    ! Mark Allen! [email protected]! http://byte-me.org! https://github.com/mrallen1! https://bitbucket.org/mrallen1! https://metacpan.org/author/MALLEN!
  2. The Old Days Matt’s Script Archive (1995-2011)! ! Use instead:!

    http://nms-cgi.sourceforge.net/! (Thanks London.pm)! !
  3. 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!
  4. The Old Days .htaccess Hack! ! ! RewriteEngine On! RewriteBase

    /abc! ! RewriteRule ^(.*)/(.*)/(.*)$ !abc.pl?a=$1;b=$2;c=$3! !
  5. 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! !
  6. 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! !
  7. 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! !
  8. Move over bacon Perl 5 Renaissance:! •  Moose! •  DBIx::Class!

    •  Plack! •  Tons of great new stuff in core perl 5.10+! !
  9. Move over bacon Other Sinatra-inspired frameworks:! •  Mojo (Perl –

    TMTOWTDI)! •  Flask (Python)! •  Fitzgerald (PHP)! •  Express (Node.js)! !
  10. Easy to learn Basic Dancer concepts:! •  One (or more)

    HTTP verb(s)! •  A route! •  A handler!
  11. Easy to learn use Dancer;! ! get '/' => sub

    {! return 'Hello World!\n’;! };! ! start;!
  12. Easy to learn use Dancer;! ! get '/' => sub

    {! return 'Hello World!\n’;! };! ! start;!
  13. Easy to learn use Dancer;! ! get '/' => sub

    {! return 'Hello World!\n’;! };! ! start;!
  14. Easy to learn use Dancer;! ! get '/' => sub

    {! return 'Hello World!\n’;! };! ! start;!
  15. Easy to learn use Dancer;! ! get '/' => sub

    {! return 'Hello World!\n’;! };! ! start;!
  16. 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'),! };! };!
  17. 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'),! };! };!
  18. 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'),! };! };!
  19. 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'),! };! };!
  20. 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'),! };! };!
  21. 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'),! };! };!
  22. 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'),! };! };!
  23. 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'),! };! };!
  24. 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'),! };! };!
  25. 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>! 
 !
  26. 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>! 
 !
  27. 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>! 
 !
  28. 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>! 
 !
  29. 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'),! };! };!
  30. 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>! 
 !
  31. 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>! 
 !
  32. Easy to learn Directory structure
 ! dancr/! ├── dancr.pl! ├──

    public! │ └── css! │ └── style.css! └── views! ├── layouts! │ └── main.tt! ├── login.tt! └── show_entries.tt!
  33. Easy to learn Directory structure
 ! dancr/! ├── dancr.pl! ├──

    public! │ └── css! │ └── style.css! └── views! ├── layouts! │ └── main.tt! ├── login.tt! └── show_entries.tt!
  34. Easy to learn Directory structure
 ! dancr/! ├── dancr.pl! ├──

    public! │ └── css! │ └── style.css! └── views! ├── layouts! │ └── main.tt! ├── login.tt! └── show_entries.tt!
  35. Easy to learn Directory structure
 ! dancr/! ├── dancr.pl! ├──

    public! │ └── css! │ └── style.css! └── views! ├── layouts! │ └── main.tt! ├── login.tt! └── show_entries.tt!
  36. 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 '/’;! };!
  37. 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 '/’;! };!
  38. 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 '/’;! };!
  39. 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 '/’;! };!
  40. 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 '/’;! };!
  41. 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 '/’;! };!
  42. 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 '/’;! };!
  43. 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 '/’;! };!
  44. Expressive Configuration Examples! 
 
 set 'session' => 'Simple';
 set

    'template' =>'template_toolkit';
 set 'logger' => 'console';
 set 'log' => 'debug';
 set 'show_errors' => 1;
 !
  45. Expressive Configuration Examples! 
 
 set 'session' => 'Simple';
 set

    'template' =>'template_toolkit';
 set 'logger' => 'console';
 set 'log' => 'debug';
 set 'show_errors' => 1;
 !
  46. Expressive Configuration
 
 Use any non-reserved key/value pair.
 
 set

    'username' => 'admin';
 set 'password' => 'password';! !
  47. Expressive Routes with regex! ! 
 get qr{\A\/(?<code>[A-Za-z0-9]+)\Z} => sub

    {! my $decode = decode_base36(
 uc captures->{'code'}! );! ...;! };!
  48. Expressive Routes with regex! ! 
 get qr{\A\/(?<code>[A-Za-z0-9]+)\Z} => sub

    {! my $decode = decode_base36(
 uc captures->{'code'}! );! ...;! };!
  49. Expressive Routes with regex! ! use v5.10;
 get qr{\A\/(?<code>[A-Za-z0-9]+)\Z} =>

    sub {! my $decode = decode_base36(
 uc captures->{'code'}! );! ...;! };!
  50. Expressive Routes with regex! ! use v5.10;
 get qr{\A\/(?<code>[A-Za-z0-9]+)\Z} =>

    sub {! my $decode = decode_base36(
 uc captures->{'code'}! );! ...;! };!
  51. Expressive Routes with named params! ! get '/:code/stats' => sub

    {! my $decode = decode_base36(
 uc params->{'code'}
 );! ...;! };!
  52. Expressive Routes with named params! ! get '/:code/stats' => sub

    {! my $decode = decode_base36(
 uc params->{'code'}
 );! ...;! };!
  53. Expressive Routes with named params! ! get qr{^/(.+)/stats$} => sub

    {
 params(‘code’) = $1;
 # input sanity goes here
 ...;
 };!
  54. 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!
  55. 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
 ...;
 };! !
  56. 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,! };! };!
  57. 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,! };! };!
  58. 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,! };! };!
  59. 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,! };! };!
  60. 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,! };! };!
  61. 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,! };! };!
  62. 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,! };! };!
  63. 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,! };! };!
  64. Efficient Forward! ! get '/demo/foo/:bar' => sub {! my $bar

    = param->{'bar'};! # magically use demo DB! ...;! return forward "/foo/$bar";! };! !
  65. 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 { ...; };!
  66. Efficient Dancer Plugins add keywords
 ! •  Auto-create RSS feeds!

    •  Integrate Twitter for authN! •  DBIx::Class! •  DWIM CRUD apps! •  ...and more!
  67. Efficient Dancer::Plugin::Database
 ! database keyword gets $dbh! ! my $sth

    = database->prepare("SELECT * FROM mytable WHERE id = ?");! $sth->execute(42);! template 'userdetail.tt', {! row => $sth->fetchrow_hashref()! };!
  68. Efficient Sweet, sweet syntactic sugar:! ! ! database->quick_insert('mytable', \%data);! template

    'userdetail.tt', {! row => database->quick_select('mytable', { id => 42 })! };! !
  69. Awesome Source code:! { hg | git } clone https://bitbucket.org/mrallen1/dancr!

    ! See also:! https://metacpan.org/module/Dancer! https://metacpan.org/module/Dancer::Plugin::Database
 ! Install:! curl -L http://cpanmin.us | perl - Dancer YAML Template! !