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.

Avatar for Jade Allen

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! !