1# PODNAME: Dancer::Tutorial
2# ABSTRACT: An example to get you dancing
3
4__END__
5
6=pod
7
8=encoding UTF-8
9
10=head1 NAME
11
12Dancer::Tutorial - An example to get you dancing
13
14=head1 VERSION
15
16version 1.3513
17
18=head1 What is Dancer?
19
20Dancer is a "micro" web framework which is modeled after a Ruby framework called L<Sinatra|http://www.sinatrarb.com>
21that constructs web applications by building a list of HTTP verbs, URLs (called routes) and methods to handle
22that type of traffic to that specific URL.
23
24  use Dancer;
25
26  get '/' => sub {
27	return 'Hello World!';
28  };
29
30  start;
31
32This example shows a single HTTP verb "GET" followed by the root URL "/" and an anonymous subroutine which returns
33the string C<"Hello World!">  If you were to run this example, it would display "Hello World!" when you point your
34browser at C<http://localhost:3000>.
35
36=head1 How about a little more involved example?
37
38That's the reason I wrote this tutorial.  While I was investigating some Python web frameworks like L<Flask|http://flask.pocoo.org/>
39or L<Bottle|http://bottle.paws.de/docs/dev/index.html> I enjoyed the way they explained step by step how to build an example application
40which was a little more involved that a trivial example.
41
42Using the
43L<Flaskr|https://github.com/mitsuhiko/flask/tree/master/examples/flaskr/>
44sample application as my inspiration (OK, shamelessly plagiarised) I
45translated that application to the Dancer framework so I could better understand how Dancer worked. (I'm learning
46it too!)
47
48So "Dancr" was born.
49
50Dancr is a simple "micro" blog which uses the L<SQLite|http://www.sqlite.org> database engine for simplicity's sake.
51
52=head1 Required perl modules
53
54Obviously you need L<Dancer>.  You also need the L<Template Toolkit|Template>, L<File::Slurp>, and L<DBD::SQLite>.
55These all can be installed using your CPAN client, as in:
56
57  cpan Dancer Template File::Slurp DBD::SQLite
58
59=head1 The database
60
61We're not going to spend a lot of time on the database, as it's not really the point of this particular
62tutorial.
63
64Create the database by running the follow from the shell:
65
66    $ cat - | sqlite3 database
67    create table if not exists entries (
68        id integer primary key autoincrement,
69        title string not null,
70        text string not null
71    );
72    ^D
73
74The above creates a single table with three columns: I<id>, I<title>, and
75I<text>.  The 'I<id>' field is the primary key and will
76automatically get an ID assigned by the database engine when a row is inserted.
77
78We want our application to initialize the database automatically for us when we start it, so open your favorite
79L<text editor|http://www.vim.org> and create a file called 'dancr.pl'.  We're going to put the following subroutines
80in that file:
81
82  sub connect_db {
83    my $dbh = DBI->connect("dbi:SQLite:dbname=".setting('database')) or
84       die $DBI::errstr;
85
86    return $dbh;
87  }
88
89  sub init_db {
90    my $db = connect_db();
91    my $schema = read_file('./schema.sql');
92    $db->do($schema) or die $db->errstr;
93  }
94
95Nothing too fancy in here, I hope. Standard DBI except for the C<setting('database')> thing - more on that in a bit.
96For now, just assume that the expression evaluates to file location for the database file.
97
98(Note that you may want to look at the L<Dancer::Plugin::Database> module for an
99easy way to configure and manage database connections for your Dancer apps, but
100the above will suffice for this tutorial.)
101
102=head1 Our first route handler
103
104Let's tackle our first route handler now, the one for the root URL '/'. This is what it looks like:
105
106  get '/' => sub {
107    my $db = connect_db();
108    my $sql = 'select id, title, text from entries order by id desc';
109    my $sth = $db->prepare($sql) or die $db->errstr;
110    $sth->execute or die $sth->errstr;
111    template 'show_entries.tt', {
112       'msg' => get_flash(),
113       'add_entry_url' => uri_for('/add'),
114       'entries' => $sth->fetchall_hashref('id'),
115    };
116  };
117
118As you can see, the handler is created by specifying the HTTP verb 'get' and
119the URL to match, '/' and finally a subroutine to do something once those
120conditions have been satisfied.  Something you might not notice right away is
121the semicolon at the end of the route handler.  Since the subroutine actually
122is a coderef, it requires a semicolon.
123
124Let's take a closer look at the subroutine.  The first few lines are standard
125DBI. The only new concept as part of Dancer is that C<template> directive at
126the end of the handler.  That tells Dancer to process the output through one of
127its templating engines.  In this case, we're using L<Template Toolkit|Template>
128which offers a lot more flexibility than the simple default Dancer template
129engine.
130
131Templates all go into the C<views/> directory. Optionally, you can create a
132"layout" template which provides a consistent look and feel for all of your
133views.  We'll construct our own layout template cleverly named F<main.tt> a
134little later in this tutorial.
135
136What's going on with the hashref as the second argument to the template
137directive?  Those are all of the parameters we want to pass into our template.
138We have a C<msg> field which displays a message to the user when an event
139happens like a new entry is posted, or the user logs in or out.  It's called a
140"flash" message because we only want to display it one time, not every time the
141/ URL is rendered.
142
143The C<uri_for> directive tells Dancer to provide a URI for that specific route,
144in this case, it is the route to post a new entry into the database.  You might
145ask why we don't simply hardcode the C</add> URI in our application or
146templates.  The best reason B<not> to do that is because it removes a layer of
147flexibility on where to "mount" the web application. Although the application
148is coded to use the root URL C</> it might be better in the future to locate it
149under its own URL route (maybe C</dancr>?) - at that point we'd have to go
150through our application and the templates and update the URLs and hope we
151didn't miss any of them.  By using the C<uri_for> Dancer method, we can easily
152load the application wherever we like and not have to modify the application at
153all.
154
155Finally, the C<entries> field contains a hashref with the results from our
156database query.  Those results will be rendered in the template itself, so we
157just pass them in.
158
159So what does the F<show_entries.tt> template look like? This:
160
161  <% IF session.logged_in %>
162    <form action="<% add_entry_url %>" method=post class=add-entry>
163      <dl>
164        <dt>Title:
165        <dd><input type=text size=30 name=title>
166        <dt>Text:
167        <dd><textarea name=text rows=5 cols=40></textarea>
168        <dd><input type=submit value=Share>
169      </dl>
170    </form>
171  <% END %>
172  <ul class=entries>
173  <% IF entries.size %>
174    <% FOREACH id IN entries.keys.nsort %>
175      <li><h2><% entries.$id.title %></h2><% entries.$id.text %>
176    <% END %>
177  <% ELSE %>
178    <li><em>Unbelievable.  No entries here so far</em>
179  <% END %>
180  </ul>
181
182Again, since this isn't a tutorial specifically about Template Toolkit, I'm
183going to gloss over the syntax here and just point out the section which starts
184with C<E<lt>ul class=entriesE<gt>> - this is the section where the database
185query results are displayed.  You can also see at the very top some discussion
186about a session - more on that soon.
187
188=head1 Other HTTP verbs
189
190There are 8 defined HTTP verbs defined in L<RFC
1912616|http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9>: OPTIONS, GET,
192HEAD, POST, PUT, DELETE, TRACE, CONNECT.  Of these, the majority of web
193applications focus on the verbs which closely map to the CRUD (Create,
194Retrieve, Update, Delete) operations most database driven applications need to
195implement.
196
197In addition, the C<PATCH> verb was defined in
198L<RFC5789|http://tools.ietf.org/html/rfc5789>, and is intended as a
199"partial PUT" - sending just the changes required to the entity in question.
200How this would be handled is down to your app, it will vary depending on the
201type of entity in question and the serialization in use.
202
203Dancer currently supports GET, PUT/PATCH, POST, DELETE, OPTIONS which map to
204Retrieve, Update, Create, Delete respectively.  Let's take a look now at the
205C</add> route handler which handles a POST operation.
206
207  post '/add' => sub {
208     if ( not session('logged_in') ) {
209        send_error("Not logged in", 401);
210     }
211
212     my $db = connect_db();
213     my $sql = 'insert into entries (title, text) values (?, ?)';
214     my $sth = $db->prepare($sql) or die $db->errstr;
215     $sth->execute(params->{'title'}, params->{'text'}) or die $sth->errstr;
216
217     # note: 'flash' keyword imported by Dancer::Plugin::FlashMessage,
218     # not part of Dancer core
219     flash message => 'New entry posted!';
220
221     redirect '/';
222  };
223
224As before, the HTTP verb begins the handler, followed by the route, and a
225subroutine to do something - in this case, it will insert a new entry into the
226database.
227
228The first check in the subroutine is the make sure the user sending the data is
229logged in. If not, the application sends back an error and stops processing.
230Otherwise, we have standard DBI stuff. Let me insert (heh, heh) a blatant plug
231here for always, always using parameterized INSERTs in your application SQL
232statements.  It's the only way to be sure your application won't be vulnerable
233to SQL injection. (See L<http://www.bobby-tables.com> for correct INSERT
234examples in multiple languages.) Here we're using the C<params> convenience
235method to pull in the parameters in the current HTTP request. (You can see the
236'title' and 'text' form parameters in the F<show_entries.tt> template above.)
237Those values are inserted into the database, then we set a flash message for
238the user and redirect her back to the root URL.
239
240=head1 Logins and sessions
241
242Dancer comes with a simple in-memory session manager out of the box.  It
243supports a bunch of other session engines including YAML, memcached, browser
244cookies and others.  For this application we're going to stick with the
245in-memory model which works great for development and tutorials, but won't
246persist across server restarts or scale very well in "real world" production
247scenarios.
248
249=head2 Configuration options
250
251To use sessions in our application, we have to tell Dancer to activate the
252session handler and initialize a session manager.  To do that, we add some
253configuration directives toward the top of our dancr.pl file.  But there are
254more options than just the session engine we want to set.
255
256  set 'session'      => 'Simple';
257  set 'template'     => 'template_toolkit';
258  set 'logger'       => 'console';
259  set 'log'          => 'debug';
260  set 'show_errors'  => 1;
261  set 'startup_info' => 1;
262  set 'warnings'     => 1;
263  set 'database'     => database;
264
265Hopefully these are fairly self-explanatory. We want the Simple session engine,
266the Template Toolkit template engine, logging enabled (at the 'debug' level
267with output to the console instead of a file), we want to show errors to the
268web browser, log access attempts and log Dancer warnings (instead of silently
269ignoring them)
270
271In a more sophisticated application you would want to put these configuration
272options into a YAML file, but for this tutorial, we're going to keep it simple.
273Dancer also supports the notion of application environments meaning you can
274create a configuration file for your development instance, and another config
275file for the production environment (with things like debugging and showing
276errors disabled perhaps.) Dancer also doesn't impose any limits on what
277parameters you can set using the C<set> syntax.  For this application we're
278going to embed our single username and password into the application itself.
279
280  set 'username' => 'admin';
281  set 'password' => 'password';
282
283Hopefully no one will ever guess our clever password!  Obviously, you will want
284a more sophisticated user authentication scheme in any sort of non-tutorial
285application but this is good enough for our purposes.
286
287=head2 Logging in
288
289Now that Dancr is configured to handle sessions, let's take a look at the URL
290handler for the C</login> route.
291
292  any ['get', 'post'] => '/login' => sub {
293     my $err;
294
295     if ( request->method() eq "POST" ) {
296       # process form input
297       if ( params->{'username'} ne setting('username') ) {
298         $err = "Invalid username";
299       }
300       elsif ( params->{'password'} ne setting('password') ) {
301         $err = "Invalid password";
302       }
303       else {
304         session 'logged_in' => true;
305         set_flash('You are logged in.');
306         return redirect '/';
307       }
308    }
309
310    # display login form
311    template 'login.tt', {
312      'err' => $err,
313    };
314  };
315
316This is the first handler which accepts two different verb types, a GET for a
317human browsing to the URL and a POST for the browser to submit the user's input
318to the web application.  Since we're handling two different verbs, we check to
319see what verb is in the request.  If it's B<not> a POST, we drop down to the
320C<template> directive and display the F<login.tt> template.
321
322  <h2>Login</h2>
323  <% IF err %><p class=error><strong>Error:</strong> <% err %><% END %>
324  <form action="<% login_url %>" method=post>
325    <dl>
326      <dt>Username:
327      <dd><input type=text name=username>
328      <dt>Password:
329      <dd><input type=password name=password>
330      <dd><input type=submit value=Login>
331    </dl>
332  </form>
333
334This is even simpler than our F<show_entries.tt> template - but wait - there's
335a C<login_url> template parameter and we're only passing in the C<err>
336parameter. Where's the missing parameter?  It's being generated and sent to the
337template in a C<before_template_render> hook - we'll come back to that in a
338moment or two.
339
340So the user fills out the F<login.tt> template and submits it back to the
341C</login> route handler.  We now check the user input against our application
342settings and if they're incorrect, we alert the user, otherwise the application
343starts a session and sets the C<logged_in> session parameter to the C<true()>
344value. Dancer exports both a C<true()> and C<false()> convenience method which
345we use here.  After that, it's another flash message and back to the root URL
346handler.
347
348=head2 Logging out
349
350And finally, we need a way to clear our user's session with the customary
351logout procedure.
352
353  get '/logout' => sub {
354     session->destroy;
355     set_flash('You are logged out.');
356     redirect '/';
357  };
358
359C<session-E<gt>destroy;> is Dancer's way to remove a stored session.  We notify
360the user she is logged out and route her back to the root URL once again.
361
362=head1 Layout and static files
363
364We still have a missing puzzle piece or two.  First, how can we use Dancer to
365serve our CSS stylesheet? Second, where are flash messages displayed? Third,
366what about the C<before_template_render> hook?
367
368=head2 Serving static files
369
370In Dancer, static files should go into the C<public/> directory, but in the
371application be sure to omit the C<public/> element from the path.  For example,
372the stylesheet for Dancr lives in C<dancr/public/css/style.css> but is served
373from L<http://localhost:3000/css/style.css>.
374
375If you wanted to build a mostly static web site you could simply write route
376handlers like this one:
377
378  get '/' => sub {
379     send_file 'index.html';
380  };
381
382where index.html would live in your C<public/> directory.
383
384C<send_file> does exactly what it says: it loads a static file, then sends the
385contents of that file to the user.
386
387=head2 Layouts
388
389I mentioned near the beginning of this tutorial that it is possible to create a
390C<layout> template. In Dancr, that layout is called C<main> and it's set up by
391putting in a directive like this:
392
393  set layout => 'main';
394
395near the top of your web application.  What this tells Dancer's template engine
396is that it should look for a file called F<main.tt> in C<dancr/views/layouts/>
397and insert the calls from the C<template> directive into a template parameter
398called C<content>.
399
400For this web application, the layout template looks like this.
401
402  <!doctype html>
403  <html>
404  <head>
405    <title>Dancr</title>
406    <link rel=stylesheet type=text/css href="<% css_url %>">
407  </head>
408  <body>
409    <div class=page>
410    <h1>Dancr</h1>
411       <div class=metanav>
412       <% IF not session.logged_in %>
413         <a href="<% login_url %>">log in</a>
414       <% ELSE %>
415         <a href="<% logout_url %>">log out</a>
416       <% END %>
417    </div>
418    <% IF msg %>
419      <div class=flash> <% msg %> </div>
420    <% END %>
421    <% content %>
422  </div>
423  </body>
424  </html>
425
426Aha! You now see where the flash message C<msg> parameter gets rendered. You
427can also see where the content from the specific route handlers is inserted
428(the fourth line from the bottom in the C<content> template parameter.)
429
430But what about all those other C<*_url> template parameters?
431
432=head2 Using C<before_template_render>
433
434Dancer has various L<hooks|http://en.wikipedia.org/wiki/Hooking> which provide
435additional flexibility and power.  The hooks available are documented in the
436documentation for the L<hook keyword|Dancer/hook>; the one we're interested in
437here is C<before_template_render> which provides a way to manipulate the template
438parameters before they're passed to the engine for processing.
439
440Using this hook, we can generate and set the URIs for the C</login> and
441C</logout> route handlers and the URI for the stylesheet. This is handy for
442situations like this where there are values which are re-used consistently
443across all (or most) templates.
444This cuts down on code-duplication and makes your app easier to maintain over
445time since you only need to update the values in this one place instead of
446everywhere you render a template.
447
448  hook 'before_template_render' => sub {
449     my $tokens = shift;
450
451     $tokens->{'css_url'} = request->base . 'css/style.css';
452     $tokens->{'login_url'} = uri_for('/login');
453     $tokens->{'logout_url'} = uri_for('/logout');
454  };
455
456Here again I'm using C<uri_for> instead of hardcoding the routes.  This code
457block is executed before any of the templates are processed so that the
458template parameters have the appropriate values before being rendered.
459
460=head1 Putting it all together
461
462The complete tutorial code is available on GitHub:
463
464L<https://github.com/PerlDancer/dancer-tutorial>
465
466Assuming you have Git installed, you can clone the code:
467
468    git clone git://github.com/PerlDancer/dancer-tutorial.git
469
470... then run C<dancer.pl>.
471
472=head1 Advanced route moves
473
474There's a lot more to route matching than shown here. For example, you can
475match routes with regular expressions, or you can match pieces of a route like
476C</hello/:name> where the C<:name> piece magically turns into a named parameter
477in your handler for manipulation.
478
479=head1 Happy dancing!
480
481I hope this effort has been helpful and interesting enough to get you exploring
482Dancer on your own. The framework is still under heavy development but it's
483definitely mature enough to use in a production project.  Additionally, there
484are now a lot of great Dancer plugins which extend and enhance the capabilities
485of the platform.
486
487Happy dancing!
488
489=head1 SEE ALSO
490
491=over 4
492
493=item *
494
495L<http://perldancer.org>
496
497=item *
498
499L<https://github.com/PerlDancer/Dancer>
500
501=item *
502
503L<Dancer::Plugin>
504
505=back
506
507=head1 COPYRIGHT AND LICENSE
508
509Copyright (C) 2010 by Mark R. Allen.
510
511This is free software; you can redistribute it and/or modify it under the terms of either the Artistic License 2.0
512or the GNU Public License version 2.
513
514The CSS stylesheet is copied verbatim from the Flaskr example application and is subject to their license:
515
516Copyright (c) 2010 by Armin Ronacher and contributors.
517
518Some rights reserved.
519
520Redistribution and use in source and binary forms of the software as well
521as documentation, with or without modification, are permitted provided
522that the following conditions are met:
523
524=over 4
525
526=item *
527
528Redistributions of source code must retain the above copyright
529notice, this list of conditions and the following disclaimer.
530
531=item *
532
533Redistributions in binary form must reproduce the above
534copyright notice, this list of conditions and the following
535disclaimer in the documentation and/or other materials provided
536with the distribution.
537
538=item *
539
540The names of the contributors may not be used to endorse or
541promote products derived from this software without specific
542prior written permission.
543
544=back
545
546THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
547CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
548NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
549A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
550OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
551EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
552PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
553PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
554LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
555NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
556SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
557DAMAGE.
558
559=head1 AUTHOR
560
561Dancer Core Developers
562
563=head1 COPYRIGHT AND LICENSE
564
565This software is copyright (c) 2010 by Alexis Sukrieh.
566
567This is free software; you can redistribute it and/or modify it under
568the same terms as the Perl 5 programming language system itself.
569
570=cut
571