Slide 1

Slide 1 text

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!

Slide 2

Slide 2 text

The Old Days!

Slide 3

Slide 3 text

The Old Days cgi-lib.pl (1994-1998)! !

Slide 4

Slide 4 text

The Old Days CGI.pm (1995-2011)! !

Slide 5

Slide 5 text

The Old Days mod_perl (1996-2011)! !

Slide 6

Slide 6 text

The Old Days Matt’s Script Archive (1995-2011)! ! Use instead:! http://nms-cgi.sourceforge.net/! (Thanks London.pm)! !

Slide 7

Slide 7 text

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 “

Value of ‘a’ ($a) is not an integer

”;! !exit 0;! }! # yada, yada!

Slide 8

Slide 8 text

The Old Days .htaccess Hack! ! ! RewriteEngine On! RewriteBase /abc! ! RewriteRule ^(.*)/(.*)/(.*)$ !abc.pl?a=$1;b=$2;c=$3! !

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

The Old Days h"p://flic.kr/p/5TWTR4  

Slide 13

Slide 13 text

The Old Days h"p://flic.kr/p/5TWTR4  

Slide 14

Slide 14 text

Move over bacon, now there’s something leaner.! !

Slide 15

Slide 15 text

Move over bacon Perl 5 Renaissance:! •  Moose! •  DBIx::Class! •  Plack! •  Tons of great new stuff in core perl 5.10+! !

Slide 16

Slide 16 text

Move over bacon Do you find Catalyst too ! heavyweight or intimidating?! !

Slide 17

Slide 17 text

Move over bacon ! Me too!! ! !

Slide 18

Slide 18 text

Move over bacon Enter Dancer! !

Slide 19

Slide 19 text

Move over bacon Other Sinatra-inspired frameworks:! •  Mojo (Perl – TMTOWTDI)! •  Flask (Python)! •  Fitzgerald (PHP)! •  Express (Node.js)! !

Slide 20

Slide 20 text

Move over bacon Dancer is:! •  Easy to learn! •  Expressive! •  Efficient!

Slide 21

Slide 21 text

Dancer is ...! ! Easy to learn!

Slide 22

Slide 22 text

Easy to learn Basic Dancer concepts:! •  One (or more) HTTP verb(s)! •  A route! •  A handler!

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Easy to learn

Slide 29

Slide 29 text

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'),! };! };!

Slide 30

Slide 30 text

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'),! };! };!

Slide 31

Slide 31 text

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'),! };! };!

Slide 32

Slide 32 text

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'),! };! };!

Slide 33

Slide 33 text

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'),! };! };!

Slide 34

Slide 34 text

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'),! };! };!

Slide 35

Slide 35 text

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'),! };! };!

Slide 36

Slide 36 text

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'),! };! };!

Slide 37

Slide 37 text

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'),! };! };!

Slide 38

Slide 38 text

Easy to learn show_entries.tt! !
    ! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>!
  • <% entries.$id.title %>

    ! <% entries.$id.text %>! <% END %>! <% ELSE %>!
  • Unbelievable. No entries here so far! <% END %>!
! 
 !

Slide 39

Slide 39 text

Easy to learn show_entries.tt! !
    ! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>!
  • <% entries.$id.title %>

    ! <% entries.$id.text %>! <% END %>! <% ELSE %>!
  • Unbelievable. No entries here so far! <% END %>!
! 
 !

Slide 40

Slide 40 text

Easy to learn show_entries.tt! !
    ! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>!
  • <% entries.$id.title %>

    ! <% entries.$id.text %>! <% END %>! <% ELSE %>!
  • Unbelievable. No entries here so far! <% END %>!
! 
 !

Slide 41

Slide 41 text

Easy to learn show_entries.tt! !
    ! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>!
  • <% entries.$id.title %>

    ! <% entries.$id.text %>! <% END %>! <% ELSE %>!
  • Unbelievable. No entries here so far! <% END %>!
! 
 !

Slide 42

Slide 42 text

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'),! };! };!

Slide 43

Slide 43 text

Easy to learn show_entries.tt! !
    ! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>!
  • <% entries.$id.title %>

    ! <% entries.$id.text %>! <% END %>! <% ELSE %>!
  • Unbelievable. No entries here so far! <% END %>!
! 
 !

Slide 44

Slide 44 text

Easy to learn show_entries.tt! !
    ! <% IF entries.size %>! <% FOREACH id IN entries.keys.nsort %>!
  • <% entries.$id.title %>

    ! <% entries.$id.text %>! <% END %>! <% ELSE %>!
  • Unbelievable. No entries here so far! <% END %>!
! 
 !

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

Dancer is...! ! Expressive!

Slide 50

Slide 50 text

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 '/’;! };!

Slide 51

Slide 51 text

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 '/’;! };!

Slide 52

Slide 52 text

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 '/’;! };!

Slide 53

Slide 53 text

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 '/’;! };!

Slide 54

Slide 54 text

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 '/’;! };!

Slide 55

Slide 55 text

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 '/’;! };!

Slide 56

Slide 56 text

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 '/’;! };!

Slide 57

Slide 57 text

Expressive Little Bobby Tables! h"p://xkcd.com/327/  

Slide 58

Slide 58 text

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 '/’;! };!

Slide 59

Slide 59 text

Expressive

Slide 60

Slide 60 text

Expressive Configuration
 ! •  Session Engine! •  Template Engine! •  Logging ! •  Plugins!

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

Expressive Configuration
 
 Use any non-reserved key/value pair.
 
 set 'username' => 'admin';
 set 'password' => 'password';! !

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

Expressive Routes with named params! ! get qr{^/(.+)/stats$} => sub {
 params(‘code’) = $1;
 # input sanity goes here
 ...;
 };!

Slide 71

Slide 71 text

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 “

Value of ‘a’ ($a) is not an integer

”;! !exit 0;! }! # yada, yada!

Slide 73

Slide 73 text

Dancer is...
 
 ! Efficient!

Slide 74

Slide 74 text

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,! };! };!

Slide 75

Slide 75 text

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,! };! };!

Slide 76

Slide 76 text

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,! };! };!

Slide 77

Slide 77 text

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,! };! };!

Slide 78

Slide 78 text

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,! };! };!

Slide 79

Slide 79 text

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,! };! };!

Slide 80

Slide 80 text

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,! };! };!

Slide 81

Slide 81 text

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,! };! };!

Slide 82

Slide 82 text

Efficient Hook Before / After! •  De/Serialization! •  Rendering! •  Template! •  Errors!

Slide 83

Slide 83 text

Efficient Forward! ! get '/demo/foo/:bar' => sub {! my $bar = param->{'bar'};! # magically use demo DB! ...;! return forward "/foo/$bar";! };! !

Slide 84

Slide 84 text

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 { ...; };!

Slide 85

Slide 85 text

Efficient Dancer Plugins add keywords
 ! •  Auto-create RSS feeds! •  Integrate Twitter for authN! •  DBIx::Class! •  DWIM CRUD apps! •  ...and more!

Slide 86

Slide 86 text

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()! };!

Slide 87

Slide 87 text

Efficient Sweet, sweet syntactic sugar:! ! ! database->quick_insert('mytable', \%data);! template 'userdetail.tt', {! row => database->quick_select('mytable', { id => 42 })! };! !

Slide 88

Slide 88 text

Dancer is...! ! Awesome! !

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

Awesome Thank You!! !