Dancer Advent Calendar 2010 http://advent.perldancer.org/ How to contribute to Dancer http://advent.perldancer.org/2010/24 perl http://advent.perldancer.org/2010/24 Fri, 24 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="how_to_contribute_to_dancer"></a>How to contribute to Dancer</h1> <p>For our development projects, we rely a lot on <a href="http://github.com/sukria/dancer">Github</a>. Lately, more and more people started contributing to Dancer (we've got nearly 40 contributors), but not all of them are familiar with Github or git. Here is a little step-by-step guide on how to contribute. You don't need to be a Perl expert to contribute, you can provide help by correcting documentation error, adding a new recipe to our cookbook, reporting bugs, adding tests, ...</p> <h2><a name="the_code"></a>The code</h2> <p>The main repository is hosted <a href="http://github.com/sukria/dancer">here</a>. Lately, we've decided to switch to a new workflow in our process. Our two main branches are:</p> <ul> <li><a name="item_master"></a><b>master</b> </li> <li><a name="item_devel"></a><b>devel</b> </li> </ul> <p>The <b>master</b> branch is stable and should be in a state that allow a release at any time. The <b>devel</b> branch is used to our development.</p> <p>Each new feature new to be created in a <b>feature/$name_of_the_feature</b> branch that will be merged into devel when it's done.</p> <p>For this, we're using <a href="https://github.com/nvie/gitflow/">gitflow</a>, waiting for our very own <a href="https://github.com/xsawyerx/gitflux">gitflux</a> to be ready.</p> <h2><a name="contributing"></a>Contributing</h2> <p>First, go to <a href="http://github.com/sukria/dancer">github.com/sukria/dancer</a> and click on the <b>fork</b> button. Now, here is a little tutorial on how to fetch the repository, list the local and remote branches, and track the remote devel branch.</p> <pre class="prettyprint">$ git clone git@github.com:your_user/Dancer.git Initialized empty Git repository in /tmp/Dancer/.git/ remote: Counting objects: 9299, done. remote: Compressing objects: 100% (4236/4236), done. remote: Total 9299 (delta 5740), reused 8015 (delta 4862) Receiving objects: 100% (9299/9299), 1.20 MiB | 111 KiB/s, done. Resolving deltas: 100% (5740/5740), done. $ cd Dancer $ git branch -l * master $ git branch -a * master remotes/origin/HEAD -&gt; origin/master remotes/origin/after_filter remotes/origin/devel remotes/origin/hooks remotes/origin/master remotes/origin/plack-middlewares remotes/origin/psgi-refactor remotes/origin/refactor/dtsimple-removal remotes/origin/refactoring/app $ git branch --track devel origin/devel $ git branch -l devel * master</pre> <p>Now that you know what the purpose of each branch is, you can decide to work on master or devel (<b>git checkout devel</b> to switch branch).</p> <h3><a name="sending_your_patch"></a>Sending your patch</h3> <p>As I've previously stated, we rely a lot on the github features and interface. So now you've written your patch. First, be sure to provide one or more tests, and to run the test suite (with <b>make test</b> or <b>prove -r t/</b>). If all the tests pass, you can send a pull request. For this, you go on your own fork on github (http://github.com/$user/dancer), and you click on the <b>Pull Request</b> button.</p> <p>You can at any time see all the commits done by others that have not yet been merged into one of our branches at <a href="http://github.com/sukria/Dancer/forkqueue">this URL</a>.</p> <h3><a name="reporting_and_or_fixing_bugs"></a>Reporting and/or fixing bugs</h3> <p>We prefer to use the github issue tracker instead of RT. So if you want to report a bug, go <b>there|http://github.com/sukria/dancer/issues</b>.</p> <p>If your commit fixes a bug reported there, please add in your commit message something like 'closes gh-xxx" where xxx is the bug id.</p> <h2><a name="community_work"></a>Community work</h2> <p>There is nearly 40 different contributors to Dancer. There is a lot of plugins and engines available on CPAN and github. This is a real community effort. Thank you to everyone who have contributed so far!</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Franck Cuny for the Perl Dancer Advent Calendar 2010.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by franck cuny <code>&lt;franck@lumberjaph.net&gt;</code></p> </div> Dancer's ecosystem http://advent.perldancer.org/2010/23 perl http://advent.perldancer.org/2010/23 Thu, 23 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="dancer_s_ecosystem"></a>Dancer's ecosystem</h1> <p>Dancer's community is getting more important every day. Today, we will see some useful plugin or engines contributed from the community.</p> <h2><a name="templates"></a>Templates</h2> <h3><a name="dancer__template__tenjin"></a>Dancer::Template::Tenjin</h3> <p><a href="https://metacpan.org/module/Tenjin">Tenjin</a> is a fast and feature-full templating engine that can be used by Dancer for production purposes. In comparison to <a href="https://metacpan.org/module/Template::Toolkit">Template::Toolkit</a>, it is much more lightweight, has almost no dependencies, and supports embedded Perl code instead of defining its own language.</p> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Template::Tenjin">http://search.cpan.org/perldoc?Dancer::Template::Tenjin</a>)</p> <h3><a name="dancer__template__tiny"></a>Dancer::Template::Tiny</h3> <p><a href="https://metacpan.org/module/Template::Tiny">Template::Tiny</a> is an implementation of a subset of <a href="https://metacpan.org/module/Template::Toolkit">Template::Toolkit</a> (the major parts) which takes much less memory and is faster. If you're only using the main functions of Template::Toolkit, you could use <a href="https://metacpan.org/module/Template::Tiny">Template::Tiny</a>. You can also seamlessly move back to <a href="https://metacpan.org/module/Template::Toolkit">Template::Toolkit</a> whenever you want.</p> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Template::Tiny">http://search.cpan.org/perldoc?Dancer::Template::Tiny</a>)</p> <h3><a name="dancer__template__semantic"></a>Dancer::Template::Semantic</h3> <p>Template::Semantic is a template engine for XHTML/XML based on XML::LibXML that doesn't use any template syntax. This module takes pure XHTML/XML as a template, and uses XPath or CSS selectors to assign values.</p> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Template::Semantic">http://search.cpan.org/perldoc?Dancer::Template::Semantic</a>)</p> <h3><a name="dancer__template__mason"></a>Dancer::Template::Mason</h3> <p>As you could have guessed, this is an interface between Dancer's template engine abstraction layer and the <a href="https://metacpan.org/module/HTML::Mason">HTML::Mason</a> templating system.</p> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Template::Mason">http://search.cpan.org/perldoc?Dancer::Template::Mason</a>)</p> <h3><a name="dancer__template__xslate"></a>Dancer::Template::Xslate</h3> <p><a href="https://metacpan.org/module/Text::Xslate">Text::Xslate</a> is a template engine, tuned for persistent applications, safe as an HTML generator, and with rich features.</p> <p>The concept of Xslate is strongly influenced by <a href="https://metacpan.org/module/Text::MicroTemplate">Text::MicroTemplate</a> and Template-Toolkit 2, but the central philosophy of Xslate is different from them. That is, the philosophy is sandboxing that the template logic should not have no access outside the template beyond your permission.</p> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Template::Xslate">http://search.cpan.org/perldoc?Dancer::Template::Xslate</a>)</p> <h2><a name="logger"></a>Logger</h2> <h3><a name="dancer__logger__syslog"></a>Dancer::Logger::Syslog</h3> <p>This module implements a logger engine that send log messages to <b>syslog</b>, through the <a href="https://metacpan.org/module/Sys::Syslog">Sys::Syslog</a> module.</p> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Logger::Syslog">http://search.cpan.org/perldoc?Dancer::Logger::Syslog</a>)</p> <h3><a name="dancer__logger__psgi"></a>Dancer::Logger::PSGI</h3> <p>This class is an interface between your Dancer's application and <code>psgix.logger</code>. Message will be logged in whatever logger you decided to use in your <a href="https://metacpan.org/module/Plack">Plack</a> handler. If no logger is defined, nothing will be logged.</p> <p>(on CPAN/ <a href="http://search.cpan.org/perldoc?Dancer::Logger::PSGI">http://search.cpan.org/perldoc?Dancer::Logger::PSGI</a>)</p> <h3><a name="dancer__logger__spinner"></a>Dancer::Logger::Spinner</h3> <p>When using this logger and running your application in the terminal, you will see a text spinner running on each message it gets. If you have a page with a lot of request, and they will come in fast, you'll see the spinner running. If you have an app with very little requests in each page or if it is slow, the spinner will run slowly.</p> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Logger::Spinner">http://search.cpan.org/perldoc?Dancer::Logger::Spinner</a>)</p> <h2><a name="plugins"></a>Plugins</h2> <h3><a name="dancer__plugin__rest"></a>Dancer::Plugin::REST</h3> <p>This plugin helps you write a RESTful web service with Dancer. This plugin will be detailed in another article about <b>REST</b>.</p> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Plugin::REST">http://search.cpan.org/perldoc?Dancer::Plugin::REST</a>)</p> <h3><a name="dancer__plugin__params__normalization"></a>Dancer::Plugin::Params::Normalization</h3> <p>This plugin helps you make automatic transformations on requests' parameters, for instance, make them all lowercase. It has easy-to-use defaults, but can do complex and precise normalisation upon configuration.</p> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Plugin::Params::Normalization">http://search.cpan.org/perldoc?Dancer::Plugin::Params::Normalization</a>)</p> <h3><a name="dancer__plugin__mongo"></a>Dancer::Plugin::Mongo</h3> <p><a href="https://metacpan.org/module/Dancer::Plugin::Mongo">Dancer::Plugin::Mongo</a> provides a wrapper around <b>MongoDB</b>. Add the appropriate configuration options to your <i>config.yml</i> and then you can access a MongoDB database using the <code>mongo</code> keyword.</p> <pre class="prettyprint">use Dancer; use Dancer::Plugin::Mongo; get '/widget/view/:id' =&gt; sub { my $widget = mongo-&gt;database-&gt;table-&gt;find_one({ id =&gt; params-&gt;{id} }); }</pre> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Plugin::Mongo">http://search.cpan.org/perldoc?Dancer::Plugin::Mongo</a>)</p> <h3><a name="dancer__plugin__database"></a>Dancer::Plugin::Database</h3> <p>Provides an easy way to obtain a connected DBI database handle by simply calling the database keyword within your Dancer application.</p> <pre class="prettyprint">use Dancer; use Dancer::Plugin::Database; get '/widget/view/:id' =&gt; sub { my $sth = database-&gt;prepare( 'select * from widgets where id = ?' ); $sth-&gt;execute(params-&gt;{id}); template 'display_widget', { widget =&gt; $sth-&gt;fetchrow_hashref }; };</pre> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Plugin::Database">http://search.cpan.org/perldoc?Dancer::Plugin::Database</a>)</p> <h3><a name="dancer__plugin__dbic"></a>Dancer::Plugin::DBIC</h3> <p>This plugin provides an easy way to obtain <a href="https://metacpan.org/module/DBIx::Class::ResultSet">DBIx::Class::ResultSet</a> instances via the the function schema(), which it automatically imports. You just need to point to a DSN in your Dancer configuration file. So you no longer have to write boilerplate DBIC setup code.</p> <pre class="prettyprint">use Dancer; use Dancer::Plugin::DBIC; get '/profile/:id' =&gt; sub { my $user = schema-&gt;resultset('Users')-&gt;find(params-&gt;{id}); template user_profile =&gt; { user =&gt; $user }; };</pre> <p>(On CPAN: <a href="http://search.cpan.org/perldoc?Dancer::Plugin::DBIC">http://search.cpan.org/perldoc?Dancer::Plugin::DBIC</a>)</p> <h3><a name="dancer__plugin__sitemap"></a>Dancer::Plugin::SiteMap</h3> <p>Basically, this plugin predefines a pair of routes for you saving you the work in your Dancer application.</p> <p>The two routes that are defined when called, obtain a list of routes that are in your Dancer application within Dancer's registry. This list is then simply formated appropriately for each route.</p> <p>For HTML an unordered list containing anchor tags is output within your applications main layout. This can then be styled with CSS to suit.</p> <p>For the XML site map, it outputs... Yep you guessed it! An XML site map.</p> <p>As these routes work on a on-demand principle, there is no need to continually update your site map, <a href="https://metacpan.org/module/Dancer::Plugin::SiteMap">Dancer::Plugin::SiteMap</a> keeps it up-to-date for you :-)</p> <pre class="prettyprint">use Dancer; use Dancer::Plugin::SiteMap;</pre> <p>That's it! Your Dancer App now has <code>/sitemap</code> and <code>/sitemap.xml</code> routes.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Franck Cuny for the Perl Dancer Advent Calendar 2010.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by Franck Cuny <code>&lt;franck@lumberjaph.net&gt;</code>, James Ronan <code>&lt;james@ronanweb.co.uk&gt;</code></p> </div> How to use Dancer with Plack middlewares http://advent.perldancer.org/2010/22 perl http://advent.perldancer.org/2010/22 Wed, 22 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="how_to_use_dancer_with_plack_middlewares"></a>How to use Dancer with Plack middlewares</h1> <p>Plack is an awesome addition to the Perl ecosystem. One of its key features is support for middlewares.</p> <p>You can see a middleware as a <a href="http://search.cpan.org/perldoc?Moose::Role">Role</a>: a reusable component shared between your applications. This component will act both as a client and as a server.</p> <p>This article doesn't aim to present in details how a middleware works. If you're not yet familiar with <a href="https://metacpan.org/module/Plack">Plack</a>'s middlewares, you can refer to these articles:</p> <ul> <li><a name="item__a_href__http___search_cpan_org__miyagawa_Plack_0_9951_lib_Plack_Middleware_pm__http___search_cpan_org__miyagawa_Plack_0_9951_lib_Plack_Middleware_pm__a_"></a><b><a href="http://search.cpan.org/~miyagawa/Plack-0.9951/lib/Plack/Middleware.pm">http://search.cpan.org/~miyagawa/Plack-0.9951/lib/Plack/Middleware.pm</a></b> </li> <li><a name="item__a_href__http___advent_plackperl_org_2009_12_day_10_using_plack_middleware_html__http___advent_plackperl_org_2009_12_day_10_using_plack_middleware_html__a_"></a><b><a href="http://advent.plackperl.org/2009/12/day-10-using-plack-middleware.html">http://advent.plackperl.org/2009/12/day-10-using-plack-middleware.html</a></b> </li> </ul> <h2><a name="dancer_and_plack"></a>Dancer and Plack</h2> <p>Let's start by creating a simple Dancer application:</p> <pre class="prettyprint">$ dancer -a myapp + myapp + myapp/bin + myapp/bin/app.pl ...</pre> <p>Every Dancer application is a valid Plack application. When you're starting your project, you can choose between a standalone server, or using Plack:</p> <pre class="prettyprint">$ ./bin/app.pl &gt;&gt; Dancer server 12481 listening on http://0.0.0.0:3000 == Entering the development dance floor ...</pre> <p>Doing this starts my application using Dancer's standalone server on port <b>3000</b> (by default; you can use the <code>--port</code> command-line argument to change this).</p> <p>Now, let's use Plack to start this application:</p> <pre class="prettyprint">$ plackup bin/app.pl HTTP::Server::PSGI: Accepting connections at http://0:5000/</pre> <p>This time, it's the PSGI's standalone server that serves our application, and it is listening on port <b>5000</b> (this is the default chosen by Plackup; again, you can use the <code>--port</code> argument to change this).</p> <h2><a name="adding_a_first_middleware"></a>Adding a first Middleware</h2> <p>For this example, we will add a basic middleware: <a href="https://metacpan.org/module/Plack::Middleware::ETag">Plack::Middleware::ETag</a>. This one will append to all our responses a new header: <b>ETag</b>. The ETag is a mechanism to control cache validation. Most of the time, the value of the ETag is a checksum of the page content returned to the client. The client will then store this value, and next time it requests the same page, it will request the content only if the checksum has changed.</p> <p>In your config.yml, add the following:</p> <pre class="prettyprint">plack_middlewares: - - ETag</pre> <p>Now restart your application (with plackup), and let's do a request:</p> <pre class="prettyprint">$ curl -D - http://localhost:5000 HTTP/1.0 200 OK Date: Tue, 09 Nov 2010 15:49:30 GMT Server: HTTP::Server::PSGI Content-Type: text/html; charset=UTF-8 X-Powered-By: Perl Dancer 1.1999_02 ETag: 5f6e450f378e384d4be6e0c081b9dd93026ff146 Content-Length: 5428</pre> <p>The ETag header has been added to your response. If you redo the request, you'll see that the ETag value is the same.</p> <p>Let's add another middleware: <a href="https://metacpan.org/module/Plack::Middleware::ConditionalGet">Plack::Middleware::ConditionalGet</a>. This middleware makes sure the application returns content to the client only if the content has been modified since the previous request:</p> <pre class="prettyprint">plack_middlewares: - - ConditionalGET - - ETag</pre> <p><i>Note that the order is important.</i></p> <pre class="prettyprint">$ curl -D - http://localhost:5000 \ -H "If-None-Match: 5f6e450f378e384d4be6e0c081b9dd93026ff146" HTTP/1.0 304 Not Modified Date: Tue, 09 Nov 2010 15:52:01 GMT Server: HTTP::Server::PSGI X-Powered-By: Perl Dancer 1.1999_02 ETag: 5f6e450f378e384d4be6e0c081b9dd93026ff146</pre> <p>This time there is no <b>Content-Length</b> header, because the value of the ETag header is the same, so we don't have any content returned for that request.</p> <h2><a name="content_compression"></a>Content compression</h2> <p>Another common use case is the need to send content from the server to the client in a compressed format. For this, you can use <a href="https://metacpan.org/module/Plack::Middleware::Deflater">Plack::Middleware::Deflater</a> which will compress the content on-the-fly with gzip if the client supports this feature.</p> <p>A simple:</p> <pre class="prettyprint">plack_middlewares: - - Deflater</pre> <p>will do the trick.</p> <h2><a name="using_the_debug_panels"></a>Using the Debug panels</h2> <p>Some very useful middlewares to use while debugging your application are <a href="https://metacpan.org/module/Plack::Middleware::Debug">Plack::Middleware::Debug</a> and <a href="https://metacpan.org/module/Dancer::Debug">Dancer::Debug</a>.</p> <p>Those middlewares will inject some HTML code in your page, providing lots of useful information about your application, the current request and the response returned. To activate their panels, add this to your configuration:</p> <pre class="prettyprint">plack_middlewares: - - Debug - panels - - Parameters - Dancer::Version - Dancer::Settings - Memory</pre> <p>Next time you'll visit your application, you should see this panel on the right:</p> <img src="/images/dancer_debug_01.png" /> <p>If you click on one of the element from the menu, the panel will open with something similar:</p> <img src="/images/dancer_debug_02.png" /> <h2><a name="more_complex"></a>More complex</h2> <p>Some middlewares require a more complex configuration, and you won't use them as in our previous examples. For this example, we want to add a simple authentication system to access our application.</p> <p>Edit your <code>bin/app.pl</code> application, and replace the code with this one:</p> <pre class="prettyprint">use Dancer; use myapp; use Plack::Builder; my $app = sub { my $env = shift; my $request = Dancer::Request-&gt;new($env); Dancer-&gt;dance($request); }; builder { enable "Auth::Basic", authenticator =&gt; sub { my ( $username, $password ) = @_; return $username eq 'admin' &amp;&amp; $password eq 's3cr3t'; }; $app; };</pre> <p>First, we create a PSGI application (line 5). This application processes the request and returns a PSGI-compatible result. Next, we use the <b>builder</b> keyword, provided by <a href="https://metacpan.org/module/Plack::Builder">Plack::Builder</a>. Here we enable a middleware (<b>Auth::Basic</b>), and we create a code ref for the authentication method.</p> <p>If you start your application with plackup, and load the page in your browser, you will be prompted for a username and a password to access the page.</p> <h2><a name="credits"></a>Credits</h2> <p>A huge thanks to Marcel Gr&#xfc;nauer and Tatsuhiko Miyagawa for the awesome <a href="https://metacpan.org/module/Plack::Middleware::Debug">Plack::Middleware::Debug</a>.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by franck cuny <code>&lt;franck@lumberjaph.net&gt;</code> for the Perl Dancer Advent Calendar 2010.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by franck cuny</p> </div> Writing a new Dancer session backend http://advent.perldancer.org/2010/21 perl http://advent.perldancer.org/2010/21 Tue, 21 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="writing_a_new_dancer_session_backend"></a>Writing a new Dancer session backend</h1> <p>Sessions are a crucial point in any smart web application and help maintain user data across the website.</p> <p>Various session backends exist for Dancer, but is there one that you wrote yourself? Probably not. So, to help get you started, we're going to write one together!</p> <h2><a name="how_do_sessions_work"></a>How do sessions work?</h2> <p>Sessions are basically storage compartments for the web programmer to store anything he or she want to. You decide what to store, ranging from the user details to calculated information.</p> <p>Sessions can be stored inside browser cookies, Memcache or other mechanisms.</p> <p>Dancer already has a few session backends, such as:</p> <ul> <li><a name="item_Simple"></a><b>Simple</b> <p>A very simple in-memory session backend that allows you to save session data in your memory. This helps when developing locally and allows you to clean all the sessions on an application restart.</p> <p>It also serves as a very quick proof-of-concept for Dancer session backends and should be very easy to understand.</p> </li> <li><a name="item_Cookie"></a><b>Cookie</b> <p>A pretty common way of saving user information, inside the browser's cookies.</p> <p>Usually this is what you would use with your applications.</p> <p><a href="https://metacpan.org/module/Dancer::Session::Cookie">Dancer::Session::Cookie</a> has a plus side of also being encrypted.</p> </li> <li><a name="item_Memcache"></a><b>Memcache</b> <p>A more interesting approach that puts the session data inside a running Memcache which allows all processes to access it, have it replicated or accessed very quickly locally (or through a remote Memcache).</p> </li> <li><a name="item_MongoDB"></a><b>MongoDB</b> <p>Even more interesting yet, saving the session data inside a MongoDB document, providing some candy for the Document-DB audience out there. :)</p> </li> <li><a name="item_PSGI"></a><b>PSGI</b> <p>The latest in PSGI-compatible technology, throwing all the session data handling on to PSGI to handle it.</p> </li> </ul> <h2><a name="deciding_on_the_session_backend"></a>Deciding on the session backend</h2> <p>I'll admit it took me some thought on what kind of session backend would be interesting for the article. At first I thought about having a backend that creates funny ASCII art for every session. Then I considered writing one that creates a directory structure of all the session data using <a href="https://metacpan.org/module/Data::Visitor">Data::Visitor</a> but in the end I decided to pick something that could actually be used later.</p> <p>Our session backend will be <a href="https://metacpan.org/module/KiokuDB">KiokuDB</a>, an advanced object store (document) frontend written using <a href="https://metacpan.org/module/Moose">Moose</a>. Hey, what not? :)</p> <h2><a name="module_skeleton"></a>Module skeleton</h2> <p>The skeleton starts like this:</p> <pre class="prettyprint">package Dancer::Session::KiokuDB; use strict; use warnings; use Carp; use base 'Dancer::Session::Abstract'; use KiokuDB; # to have access to configuration data and a helper for paths use Dancer::Logger; use Dancer::Config 'setting'; use Dancer::FileUtils 'path'; use Dancer::ModuleLoader; # ... 1;</pre> <p>You'll notice we're using <a href="https://metacpan.org/module/Dancer::Session::Abstract">Dancer::Session::Abstract</a>, which helps us ensure we implement the correct methods and helps us enforce present and future portability with Dancer itself. It also makes our module object oriented.</p> <p>KiokuDB works on backends and we're going to use <a href="https://metacpan.org/module/Dancer::ModuleLoader">Dancer::ModuleLoader</a> to dynamically load these backend modules.</p> <h2><a name="internal_variables"></a>Internal variables</h2> <p>We're going to use two variables in the scope of the file:</p> <ul> <li><a name="item__code__db__code_"></a><b><code>$db</code></b> <p>This variable will contain the KiokuDB database object.</p> </li> <li><a name="item__code__warned__code_"></a><b><code>$warned</code></b> <p>We're going to depend on the user being able to specify any KiokuDB backend they want, but we also want the user to have a default backend.</p> <p>In case the user does not provide one, we're going to warn him before using our default backend. However, we don't want to alert them <b>every</b> time they try to work with the session backend - only once. So this variable will contain a boolean of whether we've already warned the user before.</p> </li> </ul> <pre class="prettyprint">my ( $db, $warned );</pre> <h2><a name="methods"></a>Methods</h2> <p>Next, for our session backend, we'll need to implement the following methods:</p> <ul> <li><a name="item_init"></a><b>init</b> <p>This method initialises the session backend.</p> <p>We'll use this method to lazily load any additional modules.</p> <pre class="prettyprint">sub init { my $self = shift; my $backend = setting('kiokudb_backend') || 'Hash'; my $class = "KiokuDB::Backend::$backend"; my %opts = (); # making sure that if we get backend opts, they're a hashref if ( my $opts = setting('kiokudb_backend_opts') ) { if ( ref $opts and ref $opts eq 'HASH' ) { %opts = %{$opts}; } else { croak 'kiokudb_backend_opts must be a hash reference'; } } # default is be to create defined $opts{'create'} or $opts{'create'} = 1; if ( not $warned ) { Dancer::Logger::warning("No session KiokuDB backend, using 'Hash'"); $warned++; } Dancer::ModuleLoader-&gt;load($class) or croak "Cannot load $class: perhaps you need to install it?"; $db = KiokuDB-&gt;new( backend =&gt; $class-&gt;new(%opts), allow_classes =&gt; ['Dancer::Session::KiokuDB'], ); }</pre> <p>We're loading a dynamic backend, creating a new KiokuDB instance with the backend we loaded and options the user can give us. You'll notice we create by default. This is valid for backends that support creating files (BDB, DBI, etc.) and we've allowed basic recursive folding of our object using <i>allow_classes</i>.</p> <p><b>Important:</b> you should know that we're being very naive here by not providing any special <a href="https://metacpan.org/module/KiokuDB::TypeMap">KiokuDB::TypeMap</a> for our class. This means that if someone will use our KiokuDB session backend and try to store something KiokuDB does not know how to cleanly fold (such as more complex objects), it might fail. Not to worry, we'll document this behaviour in the POD. :)</p> </li> <li><a name="item_create"></a><b>create</b> <p>This method creates a new session (hence the name) and returns an object of the new session. We'll also flush new data to the KiokuDB backend using our (yet-to-be-written) <code>flush</code> method.</p> <pre class="prettyprint">sub create { my $class = shift; my $self = $class-&gt;new; $self-&gt;flush; return $self; }</pre> </li> <li><a name="item_retrieve"></a><b>retrieve</b> <p>This method retrieves the session data. We're getting an ID to fetch and, using KiokuDB, this method can't be easier:</p> <pre class="prettyprint">sub retrieve { my ( $self, $id ) = @_; my $scope = $db-&gt;new_scope; # return object return $db-&gt;lookup($id); }</pre> <p>We're creating a new scope (which KiokuDB requires) and then just looking up the ID.</p> </li> <li><a name="item_destroy"></a><b>destroy</b> <p>This method deletes the session object completely. Again, using KiokuDB, it's just too easy.</p> <pre class="prettyprint">sub destroy { my $self = shift; my $scope = $db-&gt;new_scope; $db-&gt;delete($self); }</pre> </li> <li><a name="item_flush"></a><b>flush</b> <p>This method is in charge of <i>flushing</i> the data to the session storage.</p> <pre class="prettyprint">sub flush { my $self = shift; my $id = $self-&gt;{'id'}; my $scope = $db-&gt;new_scope; $db-&gt;insert( $id =&gt; $self ); }</pre> <p>We're using an ID given in a hash key in the object as the ID for KiokuDB.</p> </li> </ul> <h2><a name="cpan__anyone"></a>CPAN, anyone?</h2> <p>While you've been reading this entry, I've taken the liberty to upload what we just wrote to CPAN and it should now be available as <a href="https://metacpan.org/module/Dancer::Session::KiokuDB">Dancer::Session::KiokuDB</a>. Nice, isn't it?</p> <p>Feel free to send me your names so I could add you to the CREDITS section in the POD! :)</p> <h2><a name="see_also"></a>See also</h2> <p>Previous articles</p> <ul> <li><a name="item__i_Dancer_Internals__i_"></a><b><i>Dancer Internals</i></b> </li> <li><a name="item__i_Writing_a_new_Dancer_serializer__i_"></a><b><i>Writing a new Dancer serializer</i></b> </li> <li><a name="item__i_Writing_a_new_Dancer_logger_backend__i_"></a><b><i>Writing a new Dancer logger backend</i></b> </li> </ul> <h2><a name="author"></a>Author</h2> <p>This article has been written by Sawyer X <code>&lt;xsawyerx@cpan.org&gt;</code> for the Perl Dancer Advent Calendar 2010.</p> </div> Writing a new Dancer logger backend http://advent.perldancer.org/2010/20 perl http://advent.perldancer.org/2010/20 Mon, 20 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="writing_a_new_dancer_logger_backend"></a>Writing a new Dancer logger backend</h1> <p>As you may have noticed by now, it's pretty simple to write backends to Dancer. This time we'll be writing a logger backend.</p> <h2><a name="how_do_loggers_work"></a>How do loggers work?</h2> <p>When Dancer passes all the information it wants (or is asked by you) to log, it will pass it on to the logger class which will then use the picked backend to actually do the correct thing with the information (such as presenting it on the screen or saving it to a file).</p> <p>Dancer already has a few logging backends, such as:</p> <ul> <li><a name="item_Console"></a><b>Console</b> <p>The new default for development environment, showing all the errors in the console from which you started the application. This helps you see everything right there on your screen while developing instead of making you check log files.</p> </li> <li><a name="item_File"></a><b>File</b> <p>The default for most production environments, saving all the information in a chosen specific log file. This is also the default behavior with many web servers such as Apache.</p> </li> <li><a name="item_Syslog"></a><b>Syslog</b> <p>This logger sends your message to the system logger, allowing for collection, storage and indexing your information along with the system information. This is used in heavy production environments to centralized all the logging data from machines to a major location which then uses it to monitor the servers and provide statistic information.</p> </li> </ul> <p>There are a few more loggers available on CPAN that you can download and configure your application to use. Feel free to explore.</p> <h2><a name="deciding_on_the_logger_backend"></a>Deciding on the logger backend</h2> <p>While writing log messages to a file is what most people do, that's just boring. Let's try to do something more interesting with <b>our</b> log messages!</p> <p>Do you like spinners? Of course you do, everyone does! Let's make a log backend that simply runs a spinner on our console. Every log message that comes in will make the spinner advance a bit.</p> <h2><a name="module_skeleton"></a>Module skeleton</h2> <p>This should be the simplest skeleton, including just the required modules:</p> <pre class="prettyprint">package Dancer::Logger::Spinner; use strict; use warnings; use base 'Dancer::Logger::Abstract'; sub _log { ... } 1;</pre> <p>If you've ever developed a Dancer engine or plugin, you'd notice that Dancer makes usage of abstract base classes. This ensures you implement the correct methods and helps you enforce present and future portability with Dancer itself. It also makes our module object oriented.</p> <h2><a name="methods"></a>Methods</h2> <p>There is only one subroutine we need to implement for our logger:</p> <ul> <li><a name="item__log"></a><b>_log</b> <p>This subroutine does the work. It gets two parameters: the level of the logging and the message itself. This helps you determine how important the message is.</p> <p>For our spinner, since we want to make it rock as much as possible, any message counts as another spin, so we won't differentiate between different levels.</p> <pre class="prettyprint">sub _log { my ( $self, $level, $message ) = @_; $self-&gt;advance_spinner(); }</pre> <p>Of course, if we aren't using the message level or the message itself, why are we expanding it out of <code>@_</code>? Just to show how it works. We could effectively write it the same as such:</p> <pre class="prettyprint">sub _log { my $self = shift; $self-&gt;advance_spinner(); }</pre> </li> </ul> <p>Of course we haven't really written the <code>advance_spinner</code> method yet. We're also missing one important thing, the initialization of the spinner, the characters used by it and the counter we'll use to keep track of the array of characters.</p> <p>We can use the <code>init</code> method in the base class we inherited (<a href="https://metacpan.org/module/Dancer::Logger::Abstract">Dancer::Logger::Abstract</a>, remember?) to take care of all these things at initialization.</p> <pre class="prettyprint">sub init { my $self = shift; $self-&gt;{'spinner_chars'} = [ '\\', '|', '/', '-', 'x' ]; $self-&gt;{'spinner_count'} = 0; }</pre> <p>Now we need to implement the <code>advance_spinner</code> subroutine:</p> <pre class="prettyprint">sub advance_spinner { my $self = shift; my $count = $self-&gt;{'spinner_count'}; my @chars = @{ $self-&gt;{'spinner_chars'} }; # these chars lifted from Brandon L. Black's Term::Spinner print STDERR "\010 \010"; print STDERR $chars[$count]; # if we reached over the array end, let's get back to the start # let's also increment the counter before doing the check ++$count &gt; $#chars and $count = 0; # update the hash $self-&gt;{'spinner_count'} = $count; }</pre> <p>One nice thing we can add is printing a newline when the code finishes so your terminal doesn't end up on the same line with the last printed character:</p> <pre class="prettyprint">sub DESTROY { print STDERR "\n"; }</pre> <p>And that's pretty much it.</p> <p><i>(we're printing to STDERR to enforce pipe flushing)</i></p> <h2><a name="cpan__anyone"></a>CPAN, anyone?</h2> <p>While you've been reading this entry, I've taken the liberty to upload what we just wrote to CPAN and it should now be available as <a href="https://metacpan.org/module/Dancer::Logger::Spinner">Dancer::Logger::Spinner</a>. Nice, isn't it?</p> <p>Feel free to send me your names so I could add you to the CREDITS section in the POD! :)</p> <h2><a name="see_also"></a>See also</h2> <ul> <li><a name="item_The_previous_article_on__i_Dancer_Internals__i_"></a><b>The previous article on <i>Dancer Internals</i></b> </li> <li><a name="item_The_previous_article_on__i_Writing_a_new_Dancer_serializer__i_"></a><b>The previous article on <i>Writing a new Dancer serializer</i></b> </li> <li><a name="item_The_following_article_on__i_Writing_a_new_Dancer_session_backend__i_"></a><b>The following article on <i>Writing a new Dancer session backend</i></b> </li> </ul> <h2><a name="author"></a>Author</h2> <p>This article has been written by Sawyer X <code>&lt;xsawyerx@cpan.org&gt;</code> for the Perl Dancer Advent Calendar 2010.</p> </div> Writing a new Dancer serializer backend http://advent.perldancer.org/2010/19 perl http://advent.perldancer.org/2010/19 Sun, 19 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="writing_a_new_dancer_serializer_backend"></a>Writing a new Dancer serializer backend</h1> <p>Writing serializers in <a href="https://metacpan.org/module/Dancer">Dancer</a> is so easy you can read this standing on your head!</p> <p>In this entry we'll be writing a new serializer for Dancer and upload it to CPAN! Feel free to add your own once you finish reading this. :)</p> <h2><a name="how_do_serializers_work"></a>How do serializers work?</h2> <p>Serializers basically do two things:</p> <ul> <li><a name="item_Serialize_a_data_structure"></a><b>Serialize a data structure</b> <p>Take a data structure as a parameter and return serialized data.</p> </li> <li><a name="item_Deserialize_serialized_data"></a><b>Deserialize serialized data</b> <p>Take serialized data as a parameter and return structured data.</p> </li> </ul> <h2><a name="deciding_on_the_serialization_format"></a>Deciding on the serialization format</h2> <p>Serializes are so easy to write, Dancer already includes a few, such as:</p> <ul> <li><a name="item_JSON"></a><b>JSON</b> <p>Using <a href="https://metacpan.org/module/JSON">JSON</a>.</p> </li> <li><a name="item_XML"></a><b>XML</b> <p>Using <a href="https://metacpan.org/module/XML::Simple">XML::Simple</a>.</p> </li> <li><a name="item_YAML"></a><b>YAML</b> <p>Using <a href="https://metacpan.org/module/YAML">YAML</a>.</p> </li> <li><a name="item_Dumper"></a><b>Dumper</b> <p>Using <a href="https://metacpan.org/module/Data::Dumper">Data::Dumper</a>.</p> </li> <li><a name="item_Mutable"></a><b>Mutable</b> <p>A self-adjusting serializer that uses the <i>content type</i> and <i>accept</i> headers.</p> </li> </ul> <p>Since these are already taken (unless you want to change one implementation with another, such as <a href="https://metacpan.org/module/YAML">YAML</a> for <a href="https://metacpan.org/module/YAML::Tiny">YAML::Tiny</a>), there's not much point to write them again.</p> <p>And since the recommended serialization formats are already mentioned above, it's a good reason to look into more nether regions, such as... UU encoding!</p> <p>Of course, UU encoding isn't a format in its own, just an encoding so it isn't recursive and we need to encode an entire structure recursively. We'll cheat around it but using <a href="https://metacpan.org/module/Storable">Storable</a>'s <code>nfreeze</code> and then encoding it.</p> <p><i>(credit goes out to <a href="https://metacpan.org/module/Apache::Session">Apache::Session</a> for the idea)</i></p> <h2><a name="module_skeleton"></a>Module skeleton</h2> <p>This should be the simplest skeleton, including just the required modules:</p> <pre class="prettyprint">package Dancer::Serializer::UUEncode; use strict; use warnings; use Carp; use Storable qw/ nfreeze thaw /; use base 'Dancer::Serializer::Abstract'; # ... 1;</pre> <p>First, notice that we're using <a href="https://metacpan.org/module/Dancer::Serializer::Abstract">Dancer::Serializer::Abstract</a> as a base, that's because we already implemented the Dancer integration logic under that base class. It promises us less work and more present and future portability. It also makes our module object oriented.</p> <h2><a name="methods"></a>Methods</h2> <p>There are a three subroutines we should implement.</p> <ul> <li><a name="item_serialize"></a><b>serialize</b> <p>The subroutine that does the serialization process itself.</p> <pre class="prettyprint">sub serialize { my ( $self, $entity ) = @_; return pack( 'u', nfreeze($entity) ); }</pre> <p>Yes, that's it!</p> </li> <li><a name="item_deserialize"></a><b>deserialize</b> <p>The subroutine that does the deserialization process itself.</p> <pre class="prettyprint">sub deserialize { my ( $self, $content ) = @_; my $data = thaw( unpack( 'u', $content ) ); defined $data or croak "Couldn't thaw unpacked content '$content'"; return $data; }</pre> </li> <li><a name="item_content_type"></a><b>content_type</b> <p>This subroutine simply returns the content type of our serialization. This is good practice for web applications so we'll implement it. If we don't, it will default to <i>text/plain</i>, which is good too.</p> <pre class="prettyprint">sub content_type {'text/uuencode'}</pre> </li> </ul> <p>We pretty much finished the serializer.</p> <h2><a name="did_we_really_finish_it_so_quickly"></a>Did we really finish it so quickly?</h2> <p>Yes, we did!</p> <h2><a name="what_else_can_we_do"></a>What else can we do?</h2> <h3><a name="helpers"></a>helpers</h3> <p>You can add helpers that will make it easier to use the <code>serialize/deserialize</code> subroutines functionally outside of automatic serialization.</p> <pre class="prettyprint"># helpers sub from_uuencode { my ($uuencode) = @_; my $s = Dancer::Serializer::UUEncode-&gt;new; return $s-&gt;deserializer($uuencode); } sub to_uuencode { my ($data) = @_; my $s = Dancer::Serializer::UUEncode-&gt;new; return $s-&gt;serialize($data); }</pre> <h3><a name="initializer"></a>initializer</h3> <p>The <code>init</code> subroutine is run on initialize of our object, and helps you take care of initialize checks you might have.</p> <pre class="prettyprint">sub init { # do some checks }</pre> <h3><a name="loader"></a>loader</h3> <p>The <code>loaded</code> subroutine is not run by <a href="https://metacpan.org/module/Dancer">Dancer</a> itself but it is common practice to separate your lazy module loading to this subroutine and then run it using the initializer.</p> <p>If we would want to lazy load Storable, we could use these subroutines as such:</p> <pre class="prettyprint">sub loaded { require Storable; Storable-&gt;import('nfreeze'); } sub init { my ($self) = @_; $self-&gt;loaded; }</pre> <h2><a name="cpan__anyone"></a>CPAN, anyone?</h2> <p>While you've been reading this entry, I've taken the liberty to upload what we just wrote to CPAN and it should now be available as <a href="https://metacpan.org/module/Dancer::Serializer::UUEncode">Dancer::Serializer::UUEncode</a>. Nice, isn't it?</p> <p>Feel free to send me your names so I could add you to the CREDITS section in the POD! :)</p> <h2><a name="see_also"></a>See also</h2> <ul> <li><a name="item_The_previous_article_on__i_Dancer_Internals__i_"></a><b>The previous article on <i>Dancer Internals</i></b> </li> <li><a name="item_The_following_article_on__i_Writing_a_new_Dancer_logger_backend__i_"></a><b>The following article on <i>Writing a new Dancer logger backend</i></b> </li> <li><a name="item_The_article_after_that_on__i_Writing_a_new_Dancer_session_backend__i_"></a><b>The article after that on <i>Writing a new Dancer session backend</i></b> </li> </ul> <h2><a name="author"></a>Author</h2> <p>This article has been written by Sawyer X <code>&lt;xsawyerx@cpan.org&gt;</code> for the Perl Dancer Advent Calendar 2010.</p> </div> Dive into Dancer's internals http://advent.perldancer.org/2010/18 perl http://advent.perldancer.org/2010/18 Sat, 18 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="dive_into_dancer_s_internals"></a>Dive into Dancer's internals</h1> <p>This article is intended to describe how major parts of Dancer are designed, in order to help developers understand better the way it works.</p> <p>We'll see that we can basically split Dancer into four distinct scopes: the <b>DSL</b>, the <b>core</b>, <b>engines</b> and <b>plugins</b>. We'll see what are the differences between those parts and what are the concepts behind them.</p> <p>If you intend to contribute to Dancer, this article should be a good start to clarify how things fit together.</p> <h2><a name="a_word_about_the_concept_behind_dancer"></a>a word about the concept behind Dancer</h2> <p>As you may have read already, Dancer was first inspired by <a href="http://www.sintrarb.com">Sinatra</a>. It quickly evolved towards a complete micro-framework with its own personality and taste.</p> <p>The idea that remained our major guideline though is the <i>micro</i> concept: we want Dancer to remain lightweight. We want the user to be able to configure as little as possible and get things working with as little concepts to master as possible, avoiding unnecessary confusion.</p> <p>This quest of expressiveness and simplicity leads to a particular design I'll try to explain here.</p> <h2><a name="the_dsl"></a>The DSL</h2> <p>The first visible layer of Dancer is the set of keywords that are exported to the application that <i>use</i>s <a href="https://metacpan.org/module/Dancer">Dancer</a>.</p> <p>Those keywords let the user build their application. <code>get</code>, <code>redirect</code>, <code>params</code> or <code>request</code> are some of them. The main goal of Dancer is to provide the user with a new tiny language that is web-application-oriented, this is what we call a DSL (<i>Domain Specific Language</i>), a language that pertains to a specific concept, goal or domain.</p> <p>Dancer took an original path regarding the common Perl culture practices: the framework does not provide a direct Object-Oriented layer to the user. In a route handler, you don't unroll the <code>@_</code> variable. In a Dancer application, everything is declarative. Doing it this way allows for very expressive instructions and this is the reason why so many people liked Dancer in the first place. With Dancer every bit you write is necessary and it helps you tremendously avoid repetitive code.</p> <p>As this set of keywords is the very first thing a user will have to use to build a web application with Dancer, it's very important for it to be succinct, expressive and powerful. On the other hand, it should not become a huge bag of keywords as time goes. We don't want this set to be oversized, as the saying goes: <i>Less is more</i>. That's why I'm very picky when someone suggests to add a new keyword to the core DSL.</p> <p>Those keywords are intended to be the basic rock upon which your application is built. But of course, this set should be extendable, that is where plugins come into play.</p> <h2><a name="the_core"></a>The Core</h2> <p>The core is all that Dancer needs to register route handlers and dispatch any request to one of them.</p> <p>The core also contains classes that represent logical entities like <a href="https://metacpan.org/module/Dancer::Request">requests</a> or <a href="https://metacpan.org/module/Dancer::Route">route handlers</a>.</p> <p>In Dancer's implementation, anything is contained in a <a href="https://metacpan.org/module/Dancer::App">Dancer::App</a> object (yes, you can have multiple applications within the same application). An application object provides a route registry, where we can find <a href="https://metacpan.org/module/Dancer::Route">Dancer::Route</a> objects, that represents the route handlers.</p> <p>The application itself is powered by a <a href="https://metacpan.org/module/Dancer::Handler">Dancer::Handler</a> that takes a <a href="https://metacpan.org/module/Dancer::Request">Dancer::Request</a> and tries to match it against all route handlers of the current application. When a route handler is found, its code is executed, and the handler renders the result as a <a href="https://metacpan.org/module/PSGI">PSGI</a> response.</p> <p>This is the scope of the core: powering an application, registering route handlers and providing the tools for finding the appropriate handler for a given request.</p> <p>Anything outside of this scope should be handled either by an engine or a plugin.</p> <p>So what is the core actually, if all the important parts are handled by engines and if most of the specific needs should be addressed by plugins? Well, the core is what you see when you look at Dancer's soul: it's a dispatcher provided as a DSL.</p> <p>A dead-simple dispatcher whose only real internal job is to register route handlers with a powerful syntactic sugar.</p> <h2><a name="engines"></a>Engines</h2> <p>We also introduced another layer, between the core and plugins, that we call engines. Indeed, there are some very common use-cases we wanted to address within Dancer without touching the core, and with more standardisation than simple plugins can provide. Those fields are: loggers, template engines, serializers and session engines.</p> <p>Engines were introduced quickly in Dancer's development. The main idea behind this concept was to allow Dancer to be as extensible as possible.</p> <p>For instance, the engine design allows Dancer to handle different template or session engines transparently. You can change the backend you use with a simple configuration update.</p> <p>Basically, any engine in Dancer is built upon the Abstract Class design pattern: if you want to write your own engine for Dancer, all you have to do is to <i>implement</i> the right abstract class.</p> <p><a href="http://blogs.perl.org/user/Ovid/">Ovid</a> explained on his blog <a href="http://blogs.perl.org/users/ovid/2010/11/perl101-encapsulation-via-protected-abstract-methods.html">the concept of the abstract-class pattern</a>, the article is part of his Perl 101 series and explained the concept very well.</p> <p>In Dancer you'll find four kinds of engine:</p> <ul> <li><a name="item__a_href__https___metacpan_org_module_Dancer__Logger__Abstract__Dancer__Logger__Abstract__a_"></a><b><a href="https://metacpan.org/module/Dancer::Logger::Abstract">Dancer::Logger::Abstract</a></b> </li> <li><a name="item__a_href__https___metacpan_org_module_Dancer__Session__Abstract__Dancer__Session__Abstract__a_"></a><b><a href="https://metacpan.org/module/Dancer::Session::Abstract">Dancer::Session::Abstract</a></b> </li> <li><a name="item__a_href__https___metacpan_org_module_Dancer__Template__Abstract__Dancer__Template__Abstract__a_"></a><b><a href="https://metacpan.org/module/Dancer::Template::Abstract">Dancer::Template::Abstract</a></b> </li> <li><a name="item__a_href__https___metacpan_org_module_Dancer__Serializer__Abstract__Dancer__Serializer__Abstract__a_"></a><b><a href="https://metacpan.org/module/Dancer::Serializer::Abstract">Dancer::Serializer::Abstract</a></b> </li> </ul> <p>For instance, writing a new template engine would be that simple:</p> <pre class="prettyprint">package Dancer::Template::MyGreatEngine; # we implement the 'Template' interface use base 'Dancer::Template::Abstract'; sub init { # we can do init stuff here # like creating our template renderer object } sub render { my ($self, $template, $tokens) = @_; # we just need to process $template with $tokens and return # the expanded string } 1;</pre> <p>The same idea goes for session, logger and serializer.</p> <p>Thanks to this design, Dancer has already many template, session and logger backends available on the CPAN. This showcases one of the ideas behind Dancer's philosophy: being as open as possible for the developer and for the Perl community.</p> <p>The developer has the freedom to choose virtually any template or logger engine she likes, the community can contribute easily to the project, thanks to a portable design.</p> <h2><a name="plugins"></a>Plugins</h2> <p>Finally, we have plugins. As explained in a previous article, plugins are the most simple way to extend Dancer on a particular need. If you plan to contribute code to Dancer, you probably want to consider writing a plugin.</p> <p>A plugin can do anything that a regular Dancer application can; but on top of that, it can alias actions under a name which will be added to the DSL.</p> <p>A good plugin example is <a href="https://metacpan.org/module/Dancer::Plugin::Database">Dancer::Plugin::Database</a>: a keyword <code>database</code> is added to the DSL, providing a valid <a href="https://metacpan.org/module/DBI">DBI</a> handle over the database specified via Dancer's configuration.</p> <p>Writing a plugin for Dancer is a piece of cake:</p> <pre class="prettyprint">package Dancer::Plguin::MyGreatPlugin; # we want to import Dancer's DSL use Dancer ':syntax'; # we want tools to build our plugin use Dancer::Plugin; register 'some_word' =&gt; sub { # so something }; register_plugin;</pre> <h2><a name="conclusion"></a>Conclusion</h2> <p>That's it, you know all the main ideas behind Dancer's design, you should now better understand <i>where</i> your contribution should go, if you want to provide some.</p> <p>The next step for us is now to design a whole new layer, whose main job will be to provide a unified access to the internals. We'll probably call that layer <code>Dancer::Internal</code>. The idea will be to provide a full access to all the meta-information of a Dancer application, this will allows for more power and possibilities for plugins and engines.</p> <p>This will be done through a process of refactoring that will occur in the Dancer 1.3xx releases. When finalised, it will be released as a 1.4 version. This is our major target for this release.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Alexis Sukrieh for the Perl Dancer advent calendar 2010.</p> </div> Authentication with Twitter OAuth http://advent.perldancer.org/2010/17 perl http://advent.perldancer.org/2010/17 Fri, 17 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="authentication_with_twitter_oauth"></a>Authentication with Twitter OAuth</h1> <p>In this article we'll see how to authenticate our users via Twitter's OAuth mechanism, using <a href="https://metacpan.org/module/Dancer::Plugin::Auth::Twitter">Dancer::Plugin::Auth::Twitter</a>.</p> <p>This plugin is based on <a href="https://metacpan.org/module/Net::Twitter">Net::Twitter</a> and as a bonus side-effect exports a <code>twitter</code> keyword to the application's namespace, allowing other route handlers to access the whole Twitter API on behalf of the authenticated user.</p> <p>This article will show you how to use that plugin to build a Twitter app with Dancer.</p> <h2><a name="basic_oauth_principles"></a>Basic OAuth principles</h2> <p>Explaining how OAuth works is beyond the scope of this article, on the other hand, you don't really need to understand the underlying logic of it to follow what will be done in this article. All you need to understand is that authentication with OAuth works with such a workflow:</p> <ul> <li> <p>An unauthenticated user requests a page on your app</p> </li> <li> <p>The application requests an authentication URL from Twitter's API, providing its <code>consumer_key</code> and <code>consumer_secret</code> keys as well as a <code>callback URL</code>.</p> </li> <li> <p>The application bounces the user to the authentication URL it has got from Twitter.</p> </li> <li> <p>The user is redirected at Twitter and is prompted for allowing the application to access her profile and do actions on her behalf.</p> </li> <li> <p>When the user hits the <i>Allow</i> button, she's redirected back to the application, on the callback URL provided before.</p> </li> <li> <p>The user is back on the application, requesting the callback URL. The callback URL stores the user's information in a session and go back to the first route requested by the user.</p> </li> <li> <p>The user is now authenticated.</p> </li> </ul> <h2><a name="first_things_first"></a>First things first</h2> <p>Before starting we need to register a Twitter application so we can have our <code>consumer_key</code> and <code>consumer_secret</code> keys.</p> <p>Anyone can register a Twitter application at <a href="http://dev.twitter.com">http://dev.twitter.com</a>, just make sure it is a <i>Web</i> application.</p> <h2><a name="configuring_the_plugin"></a>Configuring the plugin</h2> <p>First, our plugin needs a bit of configuration, as the application will need to know these <code>consumer_key</code> and <code>consumer_secret</code> keys.</p> <p>Each Dancer plugin can store their configuration bits inside the main app's configuration, under <code>plugins/PluginName</code>. PluginName being the name of the plugin module minus the <code>Dancer::Plugin</code> namespace.</p> <p>So as our plugin is named <code>Dancer::Plugin::Auth::Twitter</code> we'll be able to store our configuration under <code>plugins/Auth::Twitter</code> :</p> <pre class="prettyprint"># config.yml .... plugins: "Auth::Twitter": consumer_key: "abcd..." consumer_secret: "1234..." callback_url: "http://localhost:3000/auth/twitter/callback"</pre> <p>That's it! Our plugin is configured. We can now use it in our code.</p> <h3><a name="initialization"></a>Initialization</h3> <p>At the very first, we must initialize the plugin (basically it needs to read the configuration and create its internal <a href="https://metacpan.org/module/Net::Twitter">Net::Twitter</a> object). So our application must start with something like the following:</p> <pre class="prettyprint">package MyApp; use Dancer; use Dancer::Plugin::Auth::Twitter; auth_twitter_init();</pre> <p>At this point, if your app doesn't provide all the configuration bits needed by the plugin, it will throw an exception.</p> <h3><a name="filtering_unauthenticated_users"></a>Filtering unauthenticated users</h3> <p>Implementing an authentication system basically relies on a before filter, where you check if the user is authenticated, and if not, redirect her to an authentication URL.</p> <p>That is what we need to do here, and as you can see it's pretty straight-forward:</p> <pre class="prettyprint">before sub { return if request-&gt;path =~ m{/auth/twitter/callback}; if (not session('twitter_user')) { redirect auth_twitter_authenticate_url; } };</pre> <p>This filter redirects any unauthenticated user to the authentication URL. Note that we don't want to do that redirection when the requested page is the callback URL defined by the plugin (this route handler is responsible for storing the authenticated user into the session).</p> <p>With our filter though, all our application routes expect an authenticated Twitter user, you could of course do something more clever to enable that filter only for a subset of your routes, but that is left as an exercise for the reader.</p> <h2><a name="playing_with_twitter"></a>Playing with Twitter</h2> <p>Well, at this point, we're done. Yes, it's that simple. The only work that is left to the developer is to provide a before filter that redirects unauthenticated users to <code>auth_twitter_authenticate_url</code> when appropriate. All the dirty work of communicating with Twitter is handled under the hood by <a href="https://metacpan.org/module/Dancer::Plugin::Auth::Twitter">Dancer::Plugin::Auth::Twitter</a>.</p> <p>So now, we can play with it, let's do a "Twitter hello world":</p> <pre class="prettyprint">get "/" =&gt; sub { "Hello, ".session('twitter_user')-&gt;{'screen_name'}; };</pre> <p>As our before filter will catch any unauthenticated user and redirect them to Twitter if needed, it's that simple.</p> <p>Note that the <a href="https://metacpan.org/module/Net::Twitter">Net::Twitter</a> object accessible via the <code>twitter</code> keyword allows you all that the Twitter ReST API provides, so your possibilities are endless.</p> <h2><a name="more_details"></a>More details</h2> <p>For more details about the plugin used in this article, you can check the example application that is shipped with <a href="https://metacpan.org/module/Dancer::Plugin::Auth::Twitter">Dancer::Plugin::Auth::Twitter</a> in the <code>example/</code> directory. It should be working out of the box.</p> <p>The plugin described in this article is a port of <a href="https://metacpan.org/module/Catalyst::Authentication::Credential::Twitter">Catalyst::Authentication::Credential::Twitter</a>, huge kudos go to its authors.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Alexis Sukrieh for the Perl Dancer advent calendar 2010.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 Alexis Sukrieh <code>&lt;sukria@sukria.net&gt;</code>.</p> </div> Use cool stuff to render a graph http://advent.perldancer.org/2010/16 perl http://advent.perldancer.org/2010/16 Thu, 16 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="use_cool_stuff_to_render_a_graph"></a>Use cool stuff to render a graph</h1> <p>Earlier this year I presented one of my project: <a href="http://lumberjaph.net/graph/2010/03/25/github-explorer.html">Github Explorer</a>. The idea was to graph the various communities on github, and show how peoples work together, by country and languages. I've started to work on a new version, and this time I want to let people generate their own graph.</p> <p>In this article I'll present a simple version of what I'm working on. Everything will be published as open source software in a few weeks.</p> <h2><a name="first__the_conclusion"></a>First, the conclusion</h2> <p>Let's see a graph first (and sorry if you're reading this with a smartphone!).</p> <iframe scrolling="no" style="border:solid 4px #ccc;height:450px;width:600px;" src="/demo/graph/github-graph.html"></iframe> <p>This is not the kind of graph I want to end up with (this one is buggy, some profiles are displayed twice for instance), but it gives you a good idea of what I want to achieve. Check the content of the iframe to see the html and javascript code.</p> <h2><a name="the_data"></a>The data</h2> <p>I'm collecting data using the GitHub API, and use <a href="http://www.mongodb.net/">mongodb</a> for storage, using the <a href="http://search.cpan.org/perldoc?Dancer::Plugin::Mongo">Dancer::Plugin::Mongo</a> plugin. I've got two collections:</p> <ul> <li><a name="item_profiles"></a><b>profiles</b> </li> <li><a name="item_relations"></a><b>relations</b> </li> </ul> <p>For each profile that follows another profile, a relation is created. Each time someone has worked with someone else, another relation is created. So, if you follow <a href="http://github.com/sukria">sukria</a> on GitHub, and you've already contributed to Dancer, there is a relation of weight 2 between you and him.</p> <h2><a name="generate_the_graph_server_side"></a>Generate the graph server side</h2> <p>I've built a simple Dancer website that will be used to display various statistics and informations about the graphs I'm going to create.</p> <p>Let's create a route that renders a simple HTML page with some javascript:</p> <pre class="prettyprint">get '/view/graph/:name' =&gt; sub { template 'graph', {name =&gt; params-&gt;{name}}, {layout =&gt; undef}; };</pre> <p>I set the layout to <code>undef</code> since I only want the graph and nothing else.</p> <p>The content for our template is mostly some javascript that will fetch the content of your graph from an API. The important lines are:</p> <pre class="prettyprint">var dataURL = "/api/graph/&lt;% name %&gt;"; var JSONdata = $.ajax({ type: "GET", url: dataURL, async: false }).responseText; var graph = JSON.parse(JSONdata);</pre> <p>This will query our JSON API to get a graph.</p> <p>Now, let's see our API:</p> <pre class="prettyprint">set serializer =&gt; 'JSON'; get '/api/graph/:profile' =&gt; sub { my $profile = params-&gt;{profile}; my $graph = GitHub::Explorer::Graph-&gt;new(); $graph-&gt;add_node( { nodeName =&gt; $profile, id =&gt; 0, group =&gt; 1 } ); _add_nodes($graph, ...); _add_links($graph, ...); my @nodes = $graph-&gt;all_nodes(); my @links = $graph-&gt;all_links(); return { nodes =&gt; \@nodes, links =&gt; \@links, }; };</pre> <p>Let's look at this route. This API will only render JSON, since it's what the javascript expects. The route matches for a given profile. The first thing it does is to create a <b>Graph</b> object, that implements a simple interface (<b>add_node</b>, <b>add_edge</b>, <b>all_nodes</b>, <b>all_edges</b>, ...). We create a first node with the requested profile. Now, for each relation, we fetch from mongo the name of the profile.</p> <p>The <b>_add_nodes</b> method looks something like the following:</p> <pre class="prettyprint">sub _add_nodes { ... my $rs = mongo-&gt;github-&gt;relations-&gt;find($query); while ( my $r = $rs-&gt;next ) { # add node to existing graph } }</pre> <p>Here I use <b>Dancer::Plugin::Mongo</b>. It imports the <b>mongo</b> keyword; <b>github</b> is the name of my database; <b>relations</b> is the name of the collection in the database. To finish, I call the <b>find</b> method with my query, to fetch the informations I need.</p> <p>The <b>_add_links</b> function is similar. Now that we have all our informations, we can ask for a list of nodes and edges, and return them to the javascript.</p> <p>For the graph rendering, I use the amazingly great <a href="http://vis.stanford.edu/protovis/">Protovis library</a>.</p> <h2><a name="caching"></a>Caching</h2> <p>Fetching the informations from MongoDB and generating the graph object can be really slow, depending on the size of the requested graph. A good idea is to cache the result before sending it back to the client. For this, we can use <a href="http://search.cpan.org/perldoc?Dancer::Plugin::Memcached">Dancer::Plugin::Memcached</a>.</p> <p>All I have to do is to change the route to something like:</p> <pre class="prettyprint">get '/api/graph/:profile' =&gt; sub { my $profile = params-&gt;{profile}; my $key = "gh_graph_".$profile; if (my $cached_graph = memcached_get($key)) { return $cached_graph; } my $graph = GitHub::Explorer::Graph-&gt;new(); ... my $finalized_graph = { nodes =&gt; \@nodes, links =&gt; \@links, }; memcached_store($key, $finalized_graph); return $finalized_graph; };</pre> <p>You can see the introduction of two new keywords: <b>memcached_get</b> and <b>memcached_store</b>.</p> <h2><a name="conclusion__bis_"></a>Conclusion (bis)</h2> <p>In this article I've shown two new plugins: <b>Dancer::Plugin::Mongo</b> (by Adam Taylor) and <b>Dancer::Plugin::Memcached</b> (by squeeks), and a nice Javascript library : <b>Protovis</b>.</p> <p>I'll continue to work on this app in the following months, and you can expect to see the code (and use the application) hopefully very soon.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Franck Cuny for the Perl Dancer Advent Calendar 2010.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by franck cuny <code>&lt;franck@lumberjaph.net&gt;</code></p> </div> Tutorial: Shrinkr, an URL shortener http://advent.perldancer.org/2010/15 perl http://advent.perldancer.org/2010/15 Wed, 15 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="tutorial__shrinkr__an_url_shortener"></a>Tutorial: Shrinkr, an URL shortener</h1> <p>This article will guide you through the writing of working URL shortener written with Dancer.</p> <h2><a name="required_perl_modules"></a>Required Perl modules</h2> <p>In addition to Dancer, you'll also need <a href="https://metacpan.org/module/Template">Template</a>, <a href="https://metacpan.org/module/DBD::SQLite">DBD::SQLite</a>, <a href="https://metacpan.org/module/Math::Base36">Math::Base36</a>, <a href="https://metacpan.org/module/File::Slurp">File::Slurp</a>. You can install these using your CPAN client.</p> <pre class="prettyprint">cpan Dancer Template DBD::SQLite Math::Base36 File::Slurp</pre> <p>Because I'm using a regular expression named capture (one of my favourite Python regex features) in this demo, you <b>must</b> use Perl 5.10 or later to run this example.</p> <p>I've tested the application on Windows 7, Fedora 13 Linux, and Mac OS 10.6, so it should work "out of the box" for you. If not, patches are welcome!</p> <h2><a name="setting_defaults_and_configuration"></a>Setting defaults and configuration</h2> <pre class="prettyprint">set 'database' =&gt; File::Spec-&gt;tmpdir() . '/shrinkr.db'; set 'template' =&gt; 'template_toolkit'; set 'logger' =&gt; 'console'; set 'log' =&gt; 'debug'; set 'show_errors' =&gt; 1; layout 'main'; before_template sub { my $tokens = shift; $tokens-&gt;{'base'} = request-&gt;base(); $tokens-&gt;{'css_url'} = 'css/style.css'; };</pre> <p>For this tutorial, I've decided to put all of the configuration settings into the main application file. For a more complex application it would be a better idea to use a separate YAML file to hold the configuration directives. (This technique is well documented in the primary Dancer docs.)</p> <p>The first line is not specific to Dancer, only to this application. It specifies the location of the SQLite database and mainly serves to point out that you can add your own arbitrary settings on top of the ones which Dancer already has defined.</p> <p>The second line tells Dancer to use <a href="https://metacpan.org/module/Template">Template Toolkit</a> as its template engine because the default Dancer template engine is a bit too simple for most applications. There are several other Dancer template engines if you prefer a different one.</p> <p>The third line tells Dancer to use the console for log output (instead of a file). We want the logger to output at the 'debug' level or higher, so that's the fourth line.</p> <p>In the last setting line, we tell Dancer to output errors directly to the web client. This is a fantastic option for development as it gives you a great stack trace and loads of context around the error, but its probably not a great option for production sites.</p> <p>There is also a <code>layout</code> directive which tells Dancer to look in <code>views/layouts</code> for a file named <i>main.tt</i>. Once the template engine renders the specified layout template, it will insert a specific view into a tag named &lt;% content %&gt;. This helps give your application a very consistent look and feel across all of the views in it.</p> <p>We also specify the default values for every template using the <code>before_template</code> directive which sets a value for a <code>base</code> value and the <code>css_url</code>.</p> <p>Note that the web-viewable location is <code>css/style.css</code> but the file location is <i>public/css/style.css</i> - make sure you omit the <i>public</i> part of the file path when you're constructing your templates or static page route handlers.</p> <h2><a name="database_set_up"></a>Database set up</h2> <pre class="prettyprint">create table if not exists link ( id integer primary key, code string not null, url string not null, count integer not null );</pre> <p>This is the schema for our database. We have an <code>id</code> field, a <code>code</code> field, a <code>url</code> field, and a <code>count</code> field. If this were a more sophisticated application the <code>count</code> field might be a part of an <code>analytics</code> table, but we're all about keeping things simple, so it's just tacked on to our simple table design here.</p> <p>Inside the application, the database routines are straightforward.</p> <pre class="prettyprint">sub connect_db { my $dbh = DBI-&gt;connect("dbi:SQLite:dbname=".setting('database')) or die $DBI::errstr; return $dbh; }</pre> <p>Here we define a routine to establish a connection to our database instance. Notice how the <code>database</code> setting is consumed here.</p> <pre class="prettyprint">my $id = 0; sub init_db { my $db = connect_db(); my $sql = read_file("./schema.sql"); $db-&gt;do($sql) or die $db-&gt;errstr; $sql = "SELECT MAX(id) FROM link"; my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute() or die $sth-&gt;errstr; ($id) = $sth-&gt;fetchrow_array() or die $sth-&gt;errstr; }</pre> <p>We define a global variable called <code>$id</code> and then execute our initial table set up and initialise the <code>$id</code> variable as the largest ID value from the database.</p> <pre class="prettyprint">sub get_next_id { return ++$id; }</pre> <p>Here we set up a routine to return a new ID value when a prospective URL is entered by a user. This is simple enough that it could be an inline function but we could enhance this function later with additional error checking or an alternate id generation scheme.</p> <h2><a name="the_____route_handler"></a>The '/' route handler</h2> <p>Let's unpack the root URL (/) route handler line by line.</p> <pre class="prettyprint">any ['get', 'post'] =&gt; '/' =&gt; sub {</pre> <p>We tell Dancer that this route handler works with both GET and POST requests. Next we specify the '/' URL to match and finally, begin an anonymous subroutine to do something when the first two conditions are met.</p> <pre class="prettyprint">my $msg; my $err; if ( request-&gt;method() eq "POST" ) {</pre> <p>Here we're going to process POST requests - these requests will be the user input from the form in the <code>template</code> directive below.</p> <pre class="prettyprint">my $uri = URI-&gt;new( params-&gt;{'url'} ); if ( $uri-&gt;scheme !~ /https?/ ) { $err = 'Error: Only HTTP or HTTPS URLs are accepted.'; }</pre> <p>We check the supplied URL to make sure it's something we want to add to the database - if the user inputs something like <code>ssh://example.com</code> we want to reject that input with a message explaining what we're looking for.</p> <pre class="prettyprint">else { my $nid = get_next_id(); my $code = encode_base36($nid); my $sql = 'INSERT INTO link (id, code, url, count) VALUES (?, ?, ?, 0)'; my $db = connect_db(); my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute( $nid, $code, $uri-&gt;canonical() ) or die $sth-&gt;errstr;</pre> <p>Hopefully this is all standard <a href="https://metacpan.org/module/DBI">DBI</a> programming for you. Nothing tremendously mysterious going on here.</p> <pre class="prettyprint">$msg = $uri-&gt;as_string . " has been shrunk to " . request-&gt;base() . $code;</pre> <p>We want to send a message to our user telling her that the URL she supplied has been added to the database with whatever code was next in our ID assignment scheme.</p> <pre class="prettyprint"> } } template 'add.tt', { 'err' =&gt; $err, 'msg' =&gt; $msg, };</pre> <p>Here we use the <code>template</code> directive to render the <i>add.tt</i> view supplying the <code>err</code> and <code>msg</code> values as appropriate. If we fell through from our <code>if</code> statement above, both values are blank (which is fine because the <i>add.tt</i> template tests to see if <code>err</code> or <code>msg</code> have values before they're rendered.)</p> <pre class="prettyprint">};</pre> <p>Note the semicolon after the closing curly brace. This is required because the subroutine above is actually a coderef.</p> <h2><a name="processing_a_shortened_url"></a>Processing a shortened URL</h2> <p>Next we're going to write a route handler to do something when a user tries to use a shortened URL code.</p> <pre class="prettyprint">get qr|\A\/(?&lt;code&gt;[A-Za-z0-9]+)\Z| =&gt; sub {</pre> <p>Like all Dancer handlers, we start by stating which HTTP verb we want to handle, a GET in this case. Next we define a regular expression the GET request must match.</p> <p>This regular expression specifies a route that starts with a '/' and is followed by one or more of the following characters 0-9, a-z, or A-Z. Notice the <code>?&lt;code&gt;</code> construction? This is the syntax for creating a named regular expression match in Perl 5.10 (or later) - instead of using the positional variables like <code>$1</code> and the like, we can directly specify a name for the match we want to save.</p> <pre class="prettyprint">my $decode = decode_base36(uc captures-&gt;{'code'});</pre> <p>In this example, the match (if any) is stored in a special hash (<code>%+</code> generally, or the <code>captures</code> directive in Dancer) with a key of <code>code</code>. We make sure to upper case the code value because <a href="https://metacpan.org/module/Math::Base36">Math::Base36</a> uses only uppercase letters.</p> <pre class="prettyprint">if ( $decode &gt; $id ) { send_error(404); }</pre> <p>If the decoded value is greater than the current id value, we know it won't exist in the database, so we send the user a 404 error instead of trying to process the request any further.</p> <pre class="prettyprint">my $db = connect_db(); my $sql = 'SELECT url, count FROM link WHERE id = ?'; my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute($decode) or die $sth-&gt;errstr; my ($url, $count) = $sth-&gt;fetchrow_array() or die $sth-&gt;errstr; $sql = 'UPDATE link SET count = ? WHERE id = ?'; $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute(++$count, $decode);</pre> <p>More DBI programming, now. We update the database entry by incrementing the <code>count</code> counter for this request.</p> <pre class="prettyprint"> redirect $url; };</pre> <p>Finally, we tell Dancer to redirect the user to the specified URL and close the handler.</p> <h2><a name="link_stats"></a>Link stats</h2> <p>Since we're collecting the number of visits to specific links, we need to display those to a user somehow. Let's look at the handler for that.</p> <pre class="prettyprint">get '/:code/stats' =&gt; sub {</pre> <p>Another GET request, this time going to a special Dancer construction <code>:code</code> which will match anything preceded by '/' and followed by a '/stats' pattern. This is a much less restrictive regular expression than the one above, but I wanted to show a different way to do the same thing - although to be truly defensive here, much better parameter validation would be required on the <code>:code</code> input.</p> <pre class="prettyprint">my $decode = decode_base36(uc params-&gt;{'code'}); if ( $decode &gt; $id ) { send_error(404); }</pre> <p>This is the same code block as above, except this time the <code>:code</code> capture is stored inside of the the <code>params</code> Dancer construction, rather than the <code>captures</code> routine.</p> <pre class="prettyprint">my $sql = 'SELECT id, code, url, count FROM link WHERE id = ?'; my $db = connect_db(); my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute($decode) or die $sth-&gt;errstr;</pre> <p>This section retrieves the appropriate information from our database.</p> <pre class="prettyprint">my $prevl; my $nextl; unless ( ( $decode - 1 ) &lt; 0 ) { $prevl = encode_base36( $decode - 1 ); } unless ( ( $decode + 1 ) &gt; $id ) { $nextl = encode_base36( $decode + 1 ); }</pre> <p>I wanted to put some navigation links in the statistical display so a user could move around in them. This code section generates the appropriate bounded links to do that.</p> <pre class="prettyprint"> template 'stats.tt', { 'stats' =&gt; $sth-&gt;fetchall_hashref('id'), 'nextl' =&gt; $nextl, 'prevl' =&gt; $prevl, }; };</pre> <p>And here we call the <code>template</code> method, and hand off the database query results, and the navigation links as appropriate. The <i>stats.tt</i> template will check to see if <code>nextl</code> or <code>prevl</code> have values before rendering them so it's OK to pass in a value which isn't defined.</p> <h2><a name="showing_all_link_stats"></a>Showing all link stats</h2> <p>I also wanted a way to show a user all of the links stored in the database, so this handler does that.</p> <pre class="prettyprint">get '/all_stats' =&gt; sub { my $sql = 'SELECT id, code, url, count FROM link'; my $db = connect_db(); my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute() or die $sth-&gt;errstr; template 'stats.tt', { 'stats' =&gt; $sth-&gt;fetchall_hashref('id'), }; };</pre> <p>This handler is even simpler than the one above it but it does basically the same thing. Notice I'm using the same template to display the data, the main differences being that in the single link case, there's navigation links and there aren't any such links here.</p> <h2><a name="putting_it_all_together"></a>Putting it all together</h2> <p>Here's the entire script from start to finish.</p> <pre class="prettyprint">use 5.010_000; use Dancer; use Template; use DBI; use Math::Base36 ':all'; use File::Spec; use File::Slurp; use URI; set 'database' =&gt; File::Spec-&gt;tmpdir() . '/shrinkr.db'; set 'template' =&gt; 'template_toolkit'; set 'logger' =&gt; 'console'; set 'log' =&gt; 'debug'; set 'show_errors' =&gt; 1; layout 'main'; before_template sub { my $tokens = shift; $tokens-&gt;{'base'} = request-&gt;base(); $tokens-&gt;{'css_url'} = 'css/style.css'; }; sub connect_db { my $dbh = DBI-&gt;connect("dbi:SQLite:dbname=".setting('database')) or die $DBI::errstr; return $dbh; } my $id = 0; sub init_db { my $db = connect_db(); my $sql = read_file("./schema.sql"); $db-&gt;do($sql) or die $db-&gt;errstr; $sql = "SELECT MAX(id) FROM link"; my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute() or die $sth-&gt;errstr; ($id) = $sth-&gt;fetchrow_array() or die $sth-&gt;errstr; } sub get_next_id { return ++$id; } any ['get', 'post'] =&gt; '/' =&gt; sub { my $msg; my $err; if ( request-&gt;method() eq "POST" ) { my $uri = URI-&gt;new( params-&gt;{'url'} ); if ( $uri-&gt;scheme !~ 'http' ) { $err = 'Error: Only HTTP or HTTPS URLs are accepted.'; } else { my $nid = get_next_id(); my $code = encode_base36($nid); my $sql = 'INSERT INTO link (id, code, url, count) VALUES (?, ?, ?, 0)'; my $db = connect_db(); my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute( $nid, $code, $uri-&gt;canonical() ) or die $sth-&gt;errstr; $msg = $uri-&gt;as_string . " has been shrunk to " . request-&gt;base() . $code; } } template 'add.tt', { 'err' =&gt; $err, 'msg' =&gt; $msg, }; }; get qr|\A\/(?&lt;code&gt;[A-Za-z0-9]+)\Z| =&gt; sub { my $decode = decode_base36(uc captures-&gt;{'code'}); if ( $decode &gt; $id ) { send_error(404); } my $db = connect_db(); my $sql = 'SELECT url, count FROM link WHERE id = ?'; my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute($decode) or die $sth-&gt;errstr; my ($url, $count) = $sth-&gt;fetchrow_array() or die $sth-&gt;errstr; $sql = 'UPDATE link SET count = ? WHERE id = ?'; $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute(++$count, $decode); redirect $url; }; get '/:code/stats' =&gt; sub { my $decode = decode_base36(uc params-&gt;{'code'}); if ( $decode &gt; $id ) { send_error(404); } my $sql = 'SELECT id, code, url, count FROM link WHERE id = ?'; my $db = connect_db(); my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute($decode) or die $sth-&gt;errstr; my $prevl; my $nextl; unless ( ( $decode - 1 ) &lt; 0 ) { $prevl = encode_base36( $decode - 1 ); } unless ( ( $decode + 1 ) &gt; $id ) { $nextl = encode_base36( $decode + 1 ); } template 'stats.tt', { 'stats' =&gt; $sth-&gt;fetchall_hashref('id'), 'nextl' =&gt; $nextl, 'prevl' =&gt; $prevl, }; }; get '/all_stats' =&gt; sub { my $sql = 'SELECT id, code, url, count FROM link'; my $db = connect_db(); my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute() or die $sth-&gt;errstr; template 'stats.tt', { 'stats' =&gt; $sth-&gt;fetchall_hashref('id'), }; }; init_db(); start;</pre> <h2><a name="author"></a>Author</h2> <p>This article has been written by Mark R. Allen for the Perl Dancer Advent Calendar.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by Mark R. Allen.</p> </div> Deployment of Dancer applications with Starman, Apache and mod_proxy http://advent.perldancer.org/2010/14 perl http://advent.perldancer.org/2010/14 Tue, 14 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="deployment_of_dancer_applications_with_starman__apache_and_mod_proxy"></a>Deployment of Dancer applications with Starman, Apache and mod_proxy</h1> <h2><a name="introduction"></a>Introduction</h2> <p>I would like to show a clean and elegant deployment solution for deploying <b>Dancer</b> using <a href="https://metacpan.org/module/Starman">Starman</a>.</p> <p>Starman is a high-performance <a href="https://metacpan.org/module/PSGI">PSGI</a>/<a href="https://metacpan.org/module/Plack">Plack</a> web server, written by <b>Tatsuhiko Miyagawa</b>. PSGI is an interface between a web server and a web application, written in Perl. PSGI supports <b>mod_perl</b>, <b>CGI</b> and <b>FastCGI</b>.</p> <p>While PSGI is the equivalent to <b>WSGI</b> in Python or <b>Rack</b> for Ruby, Starman is the equivalent to <b>Gunicorn</b> in Python or <b>Unicorn</b> in Ruby, even if not 100% compatible.</p> <p>The <b>Apache</b> web server is a great web server, but has changed quite a bit with time. Its features and functionality is increasing, but so is its requirements. It is used in production environments to manage applications, virtual hosts and more. However, when Apache was started, it was not meant to serve Perl applications, which is why mod_perl was created.</p> <p>I appreciate simple applications that do one thing and do it well. This is why I prefer to use Starman which is very good at what it does.</p> <h2><a name="configure"></a>Configure</h2> <p>First, you'll need to install Starman. I use <a href="https://metacpan.org/module/App::cpanminus">App::cpanminus</a> here.</p> <pre class="prettyprint"># if you use a sudo policy: sudo cpanm Starman # if you're root: cpanm Starman</pre> <p>Once installed, you go to the application directory and start the server.</p> <pre class="prettyprint">cd app_dir plackup -s Starman app.pl</pre> <p>Notice this will start the Starman web server for this specific application. That means that if you're already running a web server (either Apache or just another Starman for a different application), it will not be able to start since the port will be taken. You can specify the port number using <code>-port</code>.</p> <p>Using Apache, you can run Starman as a proxy using <b>mod_proxy</b> and add the port number to direct the requests to.</p> <p>To be able to use Apache with mod_proxy, you'll need to make sure the required modules are available.</p> <p>If you're on <b>Debian</b> or <b>Ubuntu</b>, you can activate the Apache modules using the following command:</p> <pre class="prettyprint"># using sudo: sudo a2enmod proxy proxy_http cache # as root: a2enmod proxy proxy_http cache</pre> <p>If you're using a different distribution, please consult their documentation on how to enable Apache modules. It can be as simple as installing them or including a configuration file.</p> <p>Now to configure Apache:</p> <pre class="prettyprint">&lt;VirtualHost *:80&gt; ServerName example.com ServerAlias www.example.com DocumentRoot /path/to/dancer/app &lt;Proxy *&gt; Order deny,allow Allow from allow &lt;/Proxy&gt; ProxyPass / http://localhost:5000/ ProxyPassReverse / http://localhost:5000/ &lt;/VirtualHost&gt;</pre> <p>You can configuration Apache to serve static files, to ease on Starman and your application and provide faster response for these files.</p> <pre class="prettyprint">ProxyPass /public/favicon.ico !</pre> <p>Using <b>Debian</b> or <b>Ubuntu</b>, we enable the configuration so Apache will use it:</p> <pre class="prettyprint">cd /etc/apache2/sites-available/ # sudo: sudo a2ensite app_dancer # root: a2ensite app_dancer</pre> <p>And restart Apache.</p> <p>That's it!</p> <h2><a name="conclusion"></a>Conclusion</h2> <p>This deployment method is certainly a simple solution that is scalable and can even be improved later on by replacing Apache with a lighter server like <b>Cherokee</b>.</p> <h2><a name="author"></a>Author</h2> </div> DancerJukebox - controlling MPD from Dancer http://advent.perldancer.org/2010/13 perl http://advent.perldancer.org/2010/13 Mon, 13 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="dancerjukebox___controlling_mpd_from_dancer"></a>DancerJukebox - controlling MPD from Dancer</h1> <p>I've been using <a href="http://www.musicpd.org/">Music Player Daemon</a> to play my music for a long time, it really suits my needs. It runs on a machine under my stairs and outputs music through various outputs (two soundcards, one hooked up to the amp and one to my headphones transmitter, and also Shoutcast streaming so I can listen from work), and can be controlled by a variety of clients, which need only speak a simple text-based protocol.</p> <p>Some time ago I wrote a jukebox-style music queueing webapp using <a href="http://www.catalystframework.org/">Catalyst</a>, which worked pretty well, but I did not enjoy coding or maintaining it.</p> <p>After having become familiar with Dancer, I decided it was time to re-write it using Dancer, so I sat down one evening and began. To speak to MPD, I'm using <a href="https://metacpan.org/module/Audio::MPD">Audio::MPD</a>, and I wanted to make it easy to get a connection, so I wrote up the code as a simple plugin, <a href="https://metacpan.org/module/Dancer::Plugin::MPD">Dancer::Plugin::MPD</a>, which I released to CPAN.</p> <p>This lead to code as simple as, for example:</p> <pre class="prettyprint">get '/skipnext' =&gt; sub { mpd-&gt;next; redirect '/'; }; get '/control/play/:id' =&gt; sub { mpd-&gt;play(params-&gt;{id}); redirect '/'; };</pre> <p>Simple and easy.</p> <p>This time round, I was happy enough with the code to release it, so you'll find <a href="http://github.com/bigpresh/DancerJukebox">DancerJukebox on GitHub</a>. The previous version was developed in a private Subversion repository, and I was never happy enough with it to release it. Whilst I found Catalyst powerful, I found myself having to work "the Catalyst way", and didn't really enjoy it; re-writing it using Dancer was actually fun.</p> <p>I also added a very basic "admin" section to be used from my Android phone, allowing me to skip the playing song and remove requests from the queue in case anyone requests anything silly that I don&#x2019;t want played, but didn't actually use it. It only took a couple of minutes to add that feature, though! At some point, I'll tweak that to make use of <a href="https://metacpan.org/module/Dancer::Plugin::MobileDevice">Dancer::Plugin::MobileDevice</a> (see previous advent calendar post on this) to automatically go to a basic layout, rather than implementing that myself.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by David Precious for the Perl Dancer Advent Calendar 2010.</p> </div> Adding a feed to your application http://advent.perldancer.org/2010/12 perl http://advent.perldancer.org/2010/12 Sun, 12 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="adding_a_feed_to_your_application"></a>Adding a feed to your application</h1> <p>Now that you have written a nice application with Dancer, you want to add a RSS feed to publish your articles. For this task, you can use the plugin <a href="https://metacpan.org/module/Dancer::Plugin::Feed">Dancer::Plugin::Feed</a>.</p> <p>The goal of this module is to provide an easy way to generate a feed in <b>Atom</b> or <b>RSS</b>. For this tutorial, we will see how we use it in the Advent Calendar application.</p> <h2><a name="adding_a_simple_feed"></a>Adding a simple feed</h2> <p>In the advent calendar application, each article is stored in a POD file stored on disk. Each day, a new article will be visible, and should be added to the feed. We will see how to do that.</p> <p>First, we load the plugin in the application.</p> <pre class="prettyprint">use Dancer; use Dancer::Plugin::Feed;</pre> <p>Now we need a function that will, for each day, return the list of articles, with, for each articles, if it should be visible:</p> <pre class="prettyprint">sub _articles { my $year = shift; my @days = qw/1..24/; my @articles; foreach my $day (@days) { if (_article_is_visible($year, $day) { push @articles, _article( $year, $day ); } } @articles = sort { $a-&gt;{day} &lt;=&gt; $b-&gt;{day} } @articles; return \@articles; } sub _article_is_visible { # decide if this article should be visible at this date }</pre> <p>And of course, we need to build each article from POD, set the date of the publication, the title, the permalink, etc.</p> <pre class="prettyprint">sub _article { my ( $year, $day ) = @_; ... # skip if not visible return { title =&gt; $title, content =&gt; $content, link =&gt; $permalink, issued =&gt; DateTime-&gt;new( year =&gt; $year, month =&gt; 12, day =&gt; $day ), }; }</pre> <p>And to finish, our route to return the content of the RSS feed. This route gets the <b>year</b> as an argument, and returns the list of articles for this year:</p> <pre class="prettyprint">get '/feed/:year/rss' =&gt; sub { my $articles = _articles( params-&gt;{year} ); create_feed( format =&gt; 'RSS', entries =&gt; $articles, title =&gt; 'my awesome RSS feed', ); };</pre> <p>That's it. The important part here is the <b>create_feed</b> method. This method take a list of parameters that will be used to build the feed.</p> <h3><a name="how_to_let_the_user_choose_the_format"></a>How to let the user choose the format</h3> <p>In the previous example, we've seen how to create a RSS feed. But maybe some of your users would have preferred an Atom feed, so we will let the decide what format they prefer. We only need to update our previous route for this:</p> <pre class="prettyprint">get '/feed/:year/:format' =&gt; sub { my $format = params-&gt;{format}; my $articles = _articles(params-&gt;{year}); create_feed( format =&gt; $format, ... ); };</pre> <p>Now, they can use e.g. <code>/2010/atom</code>.</p> <h3><a name="setting_default_values_in_your_configuration"></a>Setting default values in your configuration</h3> <p>You can of course configure the default values for your feed in the configuration. We can create this configuration:</p> <pre class="prettyprint">plugins: Feed: title: PerlDancer Advent Calendar copyright: PerlDancer tagline: PerlDancer advent calendar, a community effort description: this is a description for our calendar</pre> <h3><a name="aliases_methods"></a>Aliases methods</h3> <p><a href="https://metacpan.org/module/Dancer::Plugin::Feed">Dancer::Plugin::Feed</a> export another two methods: <b>create_rss_feed</b> and <b>create_atom_feed</b>. Those method set the <b>format</b> argument for you.</p> <pre class="prettyprint">get '/feed/atom' =&gt; sub { create_atom_feed(...); }; get '/feed/rss' =&gt; sub { create_rss_feed(...); };</pre> <h2><a name="see_also"></a>See also</h2> <p>Under the hood, <a href="https://metacpan.org/module/Dancer::Plugin::Feed">Dancer::Plugin::Feed</a> uses <a href="https://metacpan.org/module/XML::Feed">XML::Feed</a>.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Franck Cuny for the Perl Dancer Advent Calendar 2010.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by Franck Cuny <code>&lt;franck@lumberjaph.net&gt;</code></p> </div> Using DBIx::Class within a Dancer application http://advent.perldancer.org/2010/11 perl http://advent.perldancer.org/2010/11 Sat, 11 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="using_dbix__class_within_a_dancer_application"></a>Using DBIx::Class within a Dancer application</h1> <p><code>DBIx::Class</code>, also known as <code>DBIC</code>, is one of the many Perl ORM (<i>Object Relational Mapper</i>), but it's commonly recognised as the best and most widely used.</p> <p>This is a nice presentation from Leo : <a href="http://www.slideshare.net/ranguard/dbixclass-beginners-presentation">http://www.slideshare.net/ranguard/dbixclass-beginners-presentation</a></p> <p>Basically, <code>DBIC</code> allows you to interact with your SQL Database without writing any SQL.</p> <p>To do that, you need a set of <b>Schema classes</b> that describes your database structure. Then you can use DBIC to create, update, delete, search, and do many more things on the data that are in your database.</p> <p>From a Dancer web application, it is very easy to use DBIC, thanks to <code>Dancer::Plugin::DBIC</code>. This article will implement a simple web application to demonstrate the use of <code>Dancer::Plugin::DBIC</code>.</p> <p><b>Note</b> : Although this article only skims the surface of <code>DBIX::Class</code>, it won't explain how to use it. We recommend you to have a look at <code>DBIx::Class::Manual::Intro</code> or <code>DBIx::Class::Manual::Example</code> if needed.</p> <h2><a name="the_bookstore_example"></a>The bookstore example</h2> <p>Let's consider a simple Dancer application that allows to search for authors or books. The application is connected to a database, that contains authors, and their books. The website will have one single page with a form, that allows to query books or authors, and display the results.</p> <p>To keep this article short, the HTML will be simplistic, and the implementation as well. However, we'll try to explain how to properly use <code>Dancer::Plugin::DBIC</code>.</p> <p>The application will be structured as follow:</p> <ul> <li> <p>a Dancer route <b>/search</b> to handle the request, and decide if there is any search to perform, and send the results to the view</p> </li> <li> <p>a view, that will display the search form, and the results if any.</p> </li> <li> <p>a set of models, linked to a database, that will contain the books and authors. These models will be created using DBIC</p> </li> </ul> <h2><a name="the_basics"></a>The basics</h2> <h3><a name="create_the_application"></a>Create the application</h3> <p>Okay, that's easy enough:</p> <pre class="prettyprint">$&gt; dancer -a bookstore</pre> <h3><a name="change_template_type"></a>Change template type</h3> <p>We'll want to loop on results and display authors and books, and it's easier to use Template Toolkit to do that, rather than the default <code>Dancer::Template::Simple</code>.</p> <p>So let's specify in the configuration that we'll use Template Toolkit as template engine:</p> <pre class="prettyprint"># add in bookstore/config.yml template: template_toolkit</pre> <h3><a name="create_a_view"></a>Create a view</h3> <p>We need a view to display the search form, and below, the results, if any. The results will be fed by the route to the view as an <code>arrayref</code> of results. Each result is a <i>hashref</i>, with a <code>author</code> key containing the name of the author, and a <code>books</code> key containing an <i>arrayref</i> of strings : the books names.</p> <p>That explanation is probably hard to follow, so here is an example, much easier:</p> <pre class="prettyprint"># example of a list of results [ { author =&gt; 'author 1', books =&gt; [ 'book 1', 'book 2' ], }, { author =&gt; 'author 2', books =&gt; [ 'book 3', 'book 4' ], } ]</pre> <p>So, what will the view look like? Here is a simple example, displaying the search form, and the results, if any. It's written in Template Toolkit, but Dancer changes the default <code>[&#x2030; %]</code> format to be <code>&lt;% %&gt;</code> instead.</p> <pre class="prettyprint"># bookstore/views/search.tt &lt;p&gt; &lt;form action="/search"&gt; Search query: &lt;input type="text" name="query" /&gt; &lt;/form&gt; &lt;/p&gt; &lt;br&gt; &lt;% IF query.length %&gt; &lt;p&gt;Search query was : &lt;% query %&gt;.&lt;/p&gt; &lt;% IF results.size %&gt; Results: &lt;ul&gt; &lt;% FOREACH result IN results %&gt; &lt;li&gt;Author: &lt;% result.author.replace("((?i)$query)", '&lt;b&gt;$1&lt;/b&gt;') %&gt; &lt;ul&gt; &lt;% FOREACH book IN result.books %&gt; &lt;li&gt;&lt;% book.replace("((?i)$query)", '&lt;b&gt;$1&lt;/b&gt;') %&gt; &lt;% END %&gt; &lt;/ul&gt; &lt;% END %&gt; &lt;% ELSE %&gt; No result &lt;% END %&gt; &lt;% END %&gt;</pre> <h3><a name="create_a_route"></a>Create a route</h3> <p>Let's create a simple Dancer route, to be added in the <code>bookstore.pm</code> module:</p> <pre class="prettyprint"># add in bookstore/lib/bookstore.pm get '/search' =&gt; sub { my $query = params-&gt;{query}; my @results = (); if (length $query) { @results = _perform_search($query); } template 'search', { query =&gt; $query, results =&gt; \@results, }; };</pre> <p>It's rather simple: get the parameter called <i>query</i>, if it exists perform the search, and in any case, call the <code>search</code> view.</p> <p>So, as you can see, we need to write the <code>_perform_search()</code> method. But before we do that, let's create the database.</p> <h3><a name="create_a_database"></a>Create a database</h3> <p>We'll go with SQLite, as it fits well with the aim of simplicity of this example. Let's create the SQLite file database:</p> <pre class="prettyprint">$&gt; sqlite3 bookstore.db CREATE TABLE author( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, firstname text default '' not null, lastname text not null); CREATE TABLE book( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, author INTEGER REFERENCES author (id), title text default '' not null );</pre> <p>Simple stuff: we have 2 tables, one for authors, and one for books, that points to the author table.</p> <h3><a name="populate_with_some_data"></a>Populate with some data</h3> <p>Let's write a script to populate the database with some data. We'll use <code>DBIX::Class</code>, and let it discover our simple database schema.</p> <pre class="prettyprint"># populate_database.pl package My::Bookstore::Schema; use base qw(DBIx::Class::Schema::Loader); package main; my $schema = My::Bookstore::Schema-&gt;connect('dbi:SQLite:dbname=bookstore.db'); $schema-&gt;populate('Author', [ [ 'firstname', 'lastname'], [ 'Ian M.', 'Banks' ], [ 'Richard', 'Matheson'], [ 'Frank', 'Herbert' ], ]); my @books_list = ( [ 'Consider Phlebas', 'Banks' ], [ 'The Player of Games', 'Banks' ], [ 'Use of Weapons', 'Banks' ], [ 'Dune', 'Herbert' ], [ 'Dune Messiah', 'Herbert' ], [ 'Children of Dune', 'Herbert' ], [ 'The Night Stalker', 'Matheson' ], [ 'The Night Strangler', 'Matheson' ], ); # transform author names into ids $_-&gt;[1] = $schema-&gt;resultset('Author')-&gt;find({ lastname =&gt; $_-&gt;[1] })-&gt;id foreach (@books_list); $schema-&gt;populate('Book', [ [ 'title', 'author' ], @books_list, ]);</pre> <p>Then run it in the directory where <i>bookstore.db</i> sits:</p> <pre class="prettyprint">perl populate_database.db</pre> <p>And that's our database populated !</p> <h2><a name="use_dancer__plugin__dbic"></a>Use Dancer::Plugin::DBIC</h2> <p>Let's go back to our Dancer application now. Instead of interacting with the database using SQL, let's configure <code>DBIX::Class</code>. DBIC needs to understand how your data is organised in your database. There are two ways of letting DBIC know:</p> <ul> <li> <p>either by writing a set of Perl modules, called schema modules: they will describe the database schema, each module describing one entity,</p> </li> <li> <p>or by letting DBIC connect to the database, explore it, and generate the schema itself.</p> </li> </ul> <p>We'll demonstrate the use of the two solutions. The author of this article (dams) is not a big fan of the detection method: on complex database, it doesn't get everything right, so one needs to help DBIC. Describing the schema manually in proper Perl classes seems a cleaner option. But hey, TIMTOWTDI.</p> <h3><a name="use_auto_detection"></a>Use auto-detection</h3> <p>Let's add some configuration in our Dancer application. We want to indicate that we want to use the <code>Dancer::Plugin::DBIC</code> plugin, and how we want to use it. We also want to define a new DBIC schema, that we will call <code>bookstore</code>. And we need to indicate that this schema is connected to the SQLite database we created.</p> <pre class="prettyprint"># add in bookstore/config.yml plugins: DBIC: bookstore: dsn: "dbi:SQLite:dbname=bookstore.db"</pre> <p>We could potentially define more schemas, by adding more fields under the <code>DBIC:</code> entry.</p> <p><b>Note</b> : you've noticed that we have only described which database to link the schema to. That way, we let <code>Dancer::Plugin::DBIC</code> connect to the database and discover its schema, and make it available for us</p> <p>Now that the configuration is done, let's see what needs to be done in the code.</p> <p>First of all, we need to indicate to Dancer that we want to use <code>Dancer::Plugin::DBIC</code>. That's easily done:</p> <pre class="prettyprint"># add in bookstore/lib/bookstore.pm use Dancer::Plugin::DBIC;</pre> <p>And now we can implement <code>_perform_search</code> using <code>Dancer::Plugin::DBIC</code>. The plugin gives you access to an additional keyword called <b>schema</b>, which you give the name of schema you want to retrieve. It returns a <code>DBIx::Class::Schema::Loader</code> (because we let the plugin discover the schema for us). This returned object can then be used to get a resultset and perform searches, as per standard usage of <code>DBIX::Class</code>.</p> <pre class="prettyprint"># add in bookstore/lib/bookstore.pm sub _perform_search { my ($query) = @_; my $bookstore_schema = schema 'bookstore'; my @results; # search in authors my @authors = $bookstore_schema-&gt;resultset('Author')-&gt;search({ -or =&gt; [ firstname =&gt; { like =&gt; "%$query%" }, lastname =&gt; { like =&gt; "%$query%" }, ] }); push @results, map { { author =&gt; join(' ', $_-&gt;firstname, $_-&gt;lastname), books =&gt; [], } } @authors; my %book_results; # search in books my @books = $bookstore_schema-&gt;resultset('Book')-&gt;search({ title =&gt; { like =&gt; "%$query%" }, }); foreach my $book (@books) { my $author_name = join(' ', $book-&gt;author-&gt;firstname, $book-&gt;author-&gt;lastname); push @{$book_results{$author_name}}, $book-&gt;title; } push @results, map { { author =&gt; $_, books =&gt; $book_results{$_}, } } keys %book_results; return @results; }</pre> <p>We needed to do some data fiddling so that the books results are gathered by authors.</p> <h3><a name="use_home_made_schema_classes"></a>Use home-made schema classes</h3> <p>Writing your own DBIC schema classes goes a bit beyond this article, but here are the basics. You can either have the <code>.pm</code> files be generated from you using <code>dbicdump</code> (see <code>DBIx::Class::Schema::Loader</code>), and then you can modify them to fit your needs. Or you can write them yourself from scratch, as explained in the DBIC documentation.</p> <p>A third option is to use the nice <code>DBIx::Class::MooseColumns</code> that let's you write the DBIC schema classes using <code>Moose</code>. This way of doing make it look more like ActiveRecord declarations.</p> <p>You should put your schema classes in a place that Dancer will find. A good place is in <i>bookstore/lib/</i>.</p> <p>Once your schema classes are in place, all you need to do is modify <i>config.yml</i> to specify that you want to use them, instead of the default auto-detection method:</p> <pre class="prettyprint"># change in bookstore/config.yml plugins: DBIC: bookstore: schema_class: My::Bookstore::Schema dsn: "dbi:SQLite:dbname=bookstore.db"</pre> <p>The rest will work exactly the same.</p> <h2><a name="start_the_application"></a>Start the application</h2> <p>Our bookstore lookup application can now be started using the built-in server:</p> <pre class="prettyprint"># start the web application bookstore/bin/app.pl</pre> <p>Now if we search for <code>The</code>, here is what we get :</p> <img src="/images/dancer_dbic.png" /> <p>As you can see, the page presents 4 results. The first one is an author's match, <i>Richard Ma<b>the</b>son</i>. The next 2 ones are 2 of his books. The last one is <i><b>The</b> Player of Games</i> (a great book by the way...).</p> <h2><a name="conclusion"></a>Conclusion</h2> <p>Well that was a rather long article, but we wanted to show a real example of using DBIC in Dancer. Most of the Dancer Plugins have the same spirit in common: be as simple as possible, and don't get in the way of the user. <code>Dancer::Plugin::DBIC</code> is exactly that, and we hope we demonstrated it to you.</p> <h2><a name="author"></a>AUTHOR</h2> <p>dams ( Damien Krotkine <code>&lt;dams@cpan.org&gt;</code> )</p> </div> Deploying Dancer in CGI and VPS Environments http://advent.perldancer.org/2010/10 perl http://advent.perldancer.org/2010/10 Fri, 10 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="deploying_dancer_in_cgi_and_vps_environments"></a>Deploying Dancer in CGI and VPS Environments</h1> <p>There are numerous ways to deploy <a href="https://metacpan.org/module/Dancer">Dancer</a> as mentioned in <a href="https://metacpan.org/module/Dancer::Deployment">Dancer::Deployment</a> and I would like to discuss two commonly used methods in production environments:</p> <ol> <li><a name="item_CGI___FastCGI"></a><b>CGI / FastCGI</b> </li> <li><a name="item_Reverse_Proxy"></a><b>Reverse Proxy</b> </li> </ol> <h1><a name="cgi"></a>CGI</h1> <p>A lot of shared hosting providers allow only CGI execution on Apache. One is also not allowed to edit <i>httpd.conf</i> or override certain values. With this in mind, let's see how you could deploy on a shared hosting environment. This method will vary based on your specific hosting environment but it has been tested successfully on <a href="https://metacpan.org/module/http:/www.nearlyfreespeech.net">NearlyFreeSpeech.Net</a>.</p> <h2><a name="requirements"></a>Requirements</h2> <p>The hosting company obviously has to install latest <a href="https://metacpan.org/module/Plack">Plack</a> and <a href="https://metacpan.org/module/Dancer">Dancer</a> along with all modules that you are using in your application. Most hosting providers will be able to install these for you upon request. However, you can also use <a href="https://metacpan.org/module/local::lib">local::lib</a> and build modules in your own directory yourself.</p> <p>You should request the following:</p> <ul> <li><a name="item__a_href__https___metacpan_org_module_Task__Plack__Task__Plack__a_"></a><b><a href="https://metacpan.org/module/Task::Plack">Task::Plack</a></b> </li> <li><a name="item__a_href__https___metacpan_org_module_Template__Template__a_"></a><b><a href="https://metacpan.org/module/Template">Template</a></b> </li> <li><a name="item__a_href__https___metacpan_org_module_Task__Dancer__Task__Dancer__a_"></a><b><a href="https://metacpan.org/module/Task::Dancer">Task::Dancer</a></b> </li> <li><a name="item____and_application_specific_modules"></a><b>...and application specific modules</b> </li> </ul> <p>You should also request updates to these and other modules regularly.</p> <ul> <li><a name="item_Note__1_"></a><b>Note #1:</b> <p><a href="https://metacpan.org/module/Plack::Runner">Plack::Runner</a> is what will actually be providing the CGI environment to Apache.</p> </li> <li><a name="item_Note__2_"></a><b>Note #2:</b> <p>If <a href="https://metacpan.org/module/Task::Dancer">Task::Dancer</a> fails for the hosting company, request individuals modules instead.</p> </li> </ul> <h2><a name="preparation"></a>Preparation</h2> <p>Locate the <i>dispatch.cgi</i> inside the 'public/' folder of your dancer application. We are going to make a symbolic link to <i>dispatch.cgi</i>. Where you put that link is up to your personal preference, how you want the url to appear (sans mod_rewrite), and specifics relating to your hosting company. Let's assume the root directory for your domain.</p> <p>From your domain root directory, type: <code>ln -s myapp/public/dispatch.cgi index.cgi</code></p> <h2><a name="apache"></a>Apache</h2> <p>At this point <a href="http://www.mydomain.com/">http://www.mydomain.com/</a> should render the '/' route if your hosting company set the Apache defaults for CGI properly.</p> <p>If that's the case then you're essentially done. Add your rewrite rules (if any) and then go grab a beer.</p> <p>If it didn't render properly then you have to create and edit the <i>.htaccess</i> inside the root directory or the Dancer application's root directory to allow for executing the scripts along with verifying any permissions.</p> <h3><a name="_htaccess"></a>.htaccess</h3> <p>First you need to set <i>index.cgi</i> as your directory index. You may also need to add handlers for cgi-scripts. This really depends on your hosting company though any redundant values would either be overridden or rejected silently by the server so don't worry.</p> <pre class="prettyprint">DirectoryIndex index.cgi AddHandler cgi-script .cgi .pl Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch</pre> <h4><a name="rewrite_rules"></a>Rewrite Rules</h4> <p>If you decided to use your <i>index.cgi</i> file in your server root directory and DirectoryIndex is set then a rewrite rule is rarely necessary. Regardless here's a simple rewrite rule:</p> <pre class="prettyprint">RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^/index.cgi/(.*) /$1 [L,R=301]</pre> <p>Read up on <a href="http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html">mod_rewrite</a>.</p> <p>If you wish to do something fancy like <a href="http://myapp.mydomain.com">http://myapp.mydomain.com</a> then you would just need a DNS <b>CNAME</b> along with <b>mod_rewrite</b>.</p> <ul> <li><a name="item_Note__1"></a><b>Note #1</b> <p>It is highly recommended that you create a rewrite rules that tells Apache to serve static files directly.</p> </li> </ul> <h3><a name="common_problems"></a>Common Problems</h3> <p>If everything appears as it should, then you should be fine. If you're having issues with <b>file paths</b> check the following below. There are usually two or three reasons for this:</p> <ol> <li><a name="item_Permissions"></a><b>Permissions</b> <p>Does the <b>webserver user</b> have access to read, and possibly execute, the file? Your user account is rarely the web server user! You might have 'chgrp' the file or files to the webserver user!</p> </li> <li><a name="item__i_public___i_"></a><b><i>public/</i></b> <p>Is the file inside the application's <i>public/</i> folder? Check your config.yml paths carefully.</p> </li> <li><a name="item_Absolute_path"></a><b>Absolute path</b> <p>If you plan to use files outside of <i>public/</i> make sure the path is <b>system absolute</b>.</p> <ul> <li><a name="item_A_"></a><b>A.</b> <p>The environment that your application runs under and the one your account uses are usually different!</p> </li> <li><a name="item_B_"></a><b>B.</b> <p><i>/home/public/</i>, <i>/home/htdocs</i>, etc... are <b>NOT</b> absolute paths but set by user environments usually.</p> </li> </ul> </li> </ol> <p><b>*</b> A cheap/easy way to find out the absolute path is to write a simple 'phpinfo.php' script:</p> <pre class="prettyprint"># in myphpinfo.php &lt;?php phpinfo(); ?&gt;</pre> <p>and search for the value of <i>_SERVER["SCRIPT_FILENAME"]</i> when you access it from the web. It should include references to the internal system paths.</p> <h2><a name="fastcgi"></a>FastCGI</h2> <p>For the few shared hosting companies that support FastCGI, just do the same thing as with CGI for <i>dispatch.fcgi</i> but in Apache's <i>.htaccess</i>:</p> <pre class="prettyprint">DirectoryIndex .fcgi AddHandler fastcgi-script .fcgi Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch</pre> <p>Easy as that.</p> <h2><a name="caching"></a>Caching</h2> <p>On shared hosting, caching is done automatically. Caching yourself could actually decrease your site's performance! <b>Just don't worry about it.</b></p> <h1><a name="reverse_proxy"></a>Reverse Proxy</h1> <p><a href="http://en.wikipedia.org/wiki/Reverse_proxy">Reverse proxy</a> is a technique of proxying HTTP requests to a backend server or servers. The advantages include load balancing, greater performance, and easier administration. This method is preferred for a VPS, cloud and any set up where you have root access.</p> <h2><a name="frontend_server__nginx"></a>Frontend Server: Nginx</h2> <p><a href="https://metacpan.org/module/www.nginx.net">Nginx</a> is an high performance HTTP server. It is very fast at serving static files.</p> <p><i>(It is best if your Dancer application does not serve static files)</i></p> <p>Regardless of what frontend server you use, remember that it is best if your Dancer application will only be used to generate dynamic content or process tasks. Serving static files ties up resources and significantly decreases performance.</p> <p>Installing <b>Nginx</b> is beyond the scope of this document. Google it for your specific OS.</p> <p>On both CentOS and Debian, the files of interest should be under <i>/etc/nginx/</i>. The layout of the files will be different but for the most part there will be an <i>nginx.conf</i> along with a <i>site-available</i> folder.</p> <p>Depending on how you installed Nginx (repo/source/ect), your <i>nginx.conf</i> should contain only information relating to Nginx as a whole. You can, though not recommended, put everything into <i>nginx.conf</i>. It is recommended to include an <i>include</i> if not already present pointing to <i>sites-available</i> or custom folder:</p> <p>Example <i>/etc/nginx/nginx.conf</i>:</p> <pre class="prettyprint"># Create separate user just for webserver (if not automatically created) user www-data; # Set worker_processes to 1 (or # of cores) minimum and 2x-3x cores maximum. # Max Clients = worker_processes * (worker_connections/4) worker_processes 2; # Set affinity so that each core receives equal load/power or set to # specific cores (Optional) # Equally balanced on 2 / 4 cores respectively: worker_cpu_affinity 0101 1010; # worker_cpu_affinity 1000 0100 0010 0001; error_log /var/log/nginx/main_error.log; pid /var/run/nginx.pid; events { # If you didn't read above note: # max clients = worker_processes * (worker_connections/4) # Set the maximum number of connections per worker. # Twiddle these for max performance. # Divided by 4 because browser requires 2 connections. # Reverse proxy = another 2 connections per request. # Thus 2 + 2 = 7 .. no 3 .. 9? worker_connections 1024; # There are 7 different polling methods Nginx can use. # Here are the recommended for each OS though you should play around and # see what works best for you. # Linux (2.6+) / FreeBSD &amp; OS X / Solaris 10 respectively: use epoll; # use kselect; # use eventport; # Note: You might have to recompile Nginx w/ specific options to access # some of these. # multi_accept on; } http { # This mime.types thing may cause a lot of trouble if you're doing # anything advance. # 90% of the time you don't have to touch it though. include /etc/nginx/mime.types; access_log /var/log/nginx/access.log; default_type application/octet-stream; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; tcp_nodelay on; # Turn off compression if there is a caching server in front of Nginx. # Play around with optimizing buffer size and ect. based on your needs. #gzip on; #gzip_min_length 1100; #gzip_buffers 4 8k; #gzip_types text/plain; #gzip_disable "MSIE [1-6]\.(?!.*SV1)"; # Include other configs.. include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }</pre> <p>Example <code>/etc/nginx/sites-available/default</code>:</p> <pre class="prettyprint"># Specify the number of backend servers along with how you want them # distrbuted. You can use domain name, IP address, port, or unix sockets. # By default, Nginx uses round robin. Stick with IP addresses and ports. # See Backend Servers section on how to set up multple instances on one # machine. upstream backend { server 127.0.0.1:5000; server 127.0.0.1:5001; server 127.0.0.2:5000; #server 127.0.0.2:5001 weight=5; #server bobscomputer; #server unix:/tmp/starman.pid; } server { # Port 80 is implied but with a caching server in front, you need a # different port. #listen 80; server_name mydomain.com; # It is recommended you create a separate access log for the server. access_log /var/log/nginx/access_server.log; # Serve static files using Nginx thus allowing Dancer to handle more # dynamic content requests. # Huge performance boost! First you must move all your # static ('/public') folder to the same server as Nginx or accessible # from by Nginx over the network. location ^~ (/images/|/css/|/javascripts/) { root /var/www/myapp/public; expires 30d; } # This is where all magic happens. Everything in this block goes # directly to Dancer. What's going on? # We set specific headers that L&lt;Plack::Middleware::ReverseProxy&gt; # expects. Using this information, # it overwrites certain environmental variables with the values we want. # When Dancer receives it, # it's as if Dancer is facing the intertubes. location / { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://backend; } # Note: If you add a frontend caching server, the above section will # have to change completely # along with serveral other things. }</pre> <h3><a name="http_1_1_vs_http_1_0"></a>HTTP 1.1 vs HTTP 1.0</h3> <p>Though Nginx communicates in HTTP 1.1 to the client, it uses HTTP 1.0 for the backends. If you need keep-alives or chunked requests/responses, then you can either try some 3rd party patches or you can use something like <b>HA Proxy</b>. This shouldn't be a problem for an overwhelming majority of users and won't affect the backend server since most HTTP 1.1 servers simply switch to HTTP 1.0 when not available.</p> <h2><a name="plack__middleware__reverseproxy"></a>Plack::Middleware::ReverseProxy</h2> <p><a href="https://metacpan.org/module/Plack::Middleware::ReverseProxy">Plack::Middleware::ReverseProxy</a> solves a problem associated with reverse proxy. When the request is sent from the intertubes to your frontend server, that request is forwarded to a backend server. That backend server believes that the request originated from the frontend server and not the intertubes. Thus the IP address and other environment variables are associated with the frontend server. When your logs/debug says that 100% of your users came from 192.168.1.10 or similar then there's a problem.</p> <p><a href="https://metacpan.org/module/Plack::Middleware::ReverseProxy">Plack::Middleware::ReverseProxy</a> reads these special headers sent from the frontend server that include the correct information. It takes that information and overwrites the environmental variables before sending those values to your Dancer application. Thus Dancer is none the wiser.</p> <p>Remember to add <a href="https://metacpan.org/module/Plack::Middleware::ReverseProxy">Plack::Middleware::ReverseProxy</a> to your <i>config.yml</i> same as with any other middleware.</p> <h2><a name="backend_server__starman_twiggy_etc_"></a>Backend Server: Starman/Twiggy/etc.</h2> <p>The backend server really depends on your needs. <a href="https://metacpan.org/module/Starman">Starman</a> offers the best performance. Set the number of workers based on your server specs.</p> <pre class="prettyprint">plackup -D -E deployment -s Starman --workers=10 -a app.pl -p 5000</pre> <p>Dancer unofficially supports Websockets and other streaming processes via <a href="https://metacpan.org/module/Web::Hippie">Web::Hippie</a> in which case you would need to use a non-blocking, async server such as <a href="https://metacpan.org/module/Twiggy">Twiggy</a>.</p> <p><i>(Don't worry about it since it's not official yet)</i></p> <pre class="prettyprint">plackup -D -E deployment -s Twiggy -a app.pl -p 5000</pre> <p>If you plan to use a non-preforking, single-threaded server, make sure to start one instance per CPU core. Adjust <i>nginx.conf</i> accordingly, and restart Nginx.</p> <pre class="prettyprint">plackup -D -E deployment -s HTTP::Server::PSGI -a app.pl -p 5000 plackup -D -E deployment -s HTTP::Server::PSGI -a app.pl -p 5001 plackup -D -E deployment -s HTTP::Server::PSGI -a app.pl -p 5002 plackup -D -E deployment -s HTTP::Server::PSGI -a app.pl -p 5003</pre> <ul> <li><a name="item_Note__1_"></a><b>Note #1:</b> <p>Using HTTP::Server::PSGI is <b>NOT</b> a good idea for production. Just using it as an example.</p> </li> <li><a name="item_Note__2_"></a><b>Note #2:</b> <p>Sometimes the <code>-D</code> option in plackup doesn't properly daemonize the server since it's the backend server's responsibility to respect this option. A cheap way to force a process to daemonize is to use <code>nohup plackup ... &amp;</code>.</p> </li> <li><a name="item_Note__3_"></a><b>Note #3:</b> <p>It's probably a good idea to create a start up script that launches your servers and initialises the environment in the background.</p> </li> </ul> <h2><a name="caching"></a>Caching</h2> <p>Caching is up to you, your application's needs and your personal preferences. Usually it's best to use URL matching. I suggest putting a caching server in front of Nginx such as Varnish or Squid. The request flow should be:</p> <p>Intertubes -&gt; Varnish -&gt; Nginx -&gt; Starman backends</p> <h2><a name="see_also"></a>See also</h2> <p><a href="https://metacpan.org/module/Dancer::Deployment">Dancer::Deployment</a></p> <h2><a name="author"></a>Author</h2> <p>This article has been written by nmani (Naveen Manivannan <code>&lt;nmani@nashresearch.com&gt;</code>) for the Perl Dancer Advent Calendar 2010.</p> </div> Writing a Quick NaNoWriMo Graphing Web Application with Dancer http://advent.perldancer.org/2010/9 perl http://advent.perldancer.org/2010/9 Thu, 9 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="writing_a_quick_nanowrimo_graphing_web_application_with_dancer"></a>Writing a Quick NaNoWriMo Graphing Web Application with Dancer</h1> <p>Just as December is the month of the Wreath, November is the month of the Write. For the last twelve years, writers of all calibers, aspirations and genres participate in a writing marathon named the <a href="http://www.nanowrimo.org/">National Novel Writing Month</a> (also referenced to as <i>NaNoWriMo</i>). The challenge is simple: starting on November 1st, write fifty thousand words before the end of the month.</p> <p>Although the contest is purely personal, many persons find additional motivation by pitting their scores against each other. Lagging behind is one thing, but lagging behind while your nemesis is 2,000 words ahead of you? Ah! <i>unacceptable</i>!</p> <p>In this perspective, wouldn't be nice to have a little web application that takes in the wordcount of a group of contestants, and displays a chart of everybody's progress? Well, let's see how hard it is to get such an application up and running, shall we?</p> <h2><a name="the_specs"></a>The Specs</h2> <p>The graph is only going to be used for one month, so there's no need to get terribly fancy. We'll use a CSV format looking like</p> <pre class="prettyprint">2010-11-01,Andy,0 2010-11-01,Bernadette,0 2010-11-01,Claude,0 2010-11-02,Bernadette,120</pre> <p>That is, each wordcount entry is made of a timestamp, the writer's name and his or her entered count. It's simple, and very easy to edit manually if anyone make a boo-boo during the month.</p> <p>The application we need around that is very simple. Basically, we need:</p> <ul> <li><a name="item_A_main_page__showing_a_graph_and_a_form_to_enter_new_results_"></a><b>A main page, showing a graph and a form to enter new results.</b> </li> <li><a name="item_An_auxiliary_page_to_process_the_input_of_a_new_word_count_"></a><b>An auxiliary page to process the input of a new word count.</b> </li> </ul> <p>Got it? Now, let's get cracking.</p> <h2><a name="creating_the_app"></a>Creating the App</h2> <p>Creating the skeleton of a new application in Dancer is incredibly complicated. First, we have to do</p> <pre class="prettyprint">$ dancer -a ournowrimo</pre> <p>and then, uh, we're done. Okay, so maybe it's not that complicated after all. :-)</p> <p>For the templating system, we'll use <a href="https://metacpan.org/module/Mason">Mason</a>, so we edit the configuration file and change the default templating to <a href="https://metacpan.org/module/Dancer::Template::Mason">Dancer::Template::Mason</a>:</p> <pre class="prettyprint">logger: "file" appname: "ournowrimo" template: mason</pre> <h2><a name="adding_the_actions"></a>Adding the Actions</h2> <p>By now, we have an application that is already in working order. It won't do anything, but if we were to launch it by running</p> <pre class="prettyprint">$ ./ournowrimo.pl</pre> <p>it would do it just fine.</p> <h3><a name="the_main_page"></a>The Main Page</h3> <p>For the main page, we don't do any heavy processing, we just want to invoke a template:</p> <pre class="prettyprint">get '/graph' =&gt; sub { template 'index', { wrimoers =&gt; get_wrimoers() }; };</pre> <p>That's it. For the url <code>/graph</code>, Dancer will render the template <code>views/index.mason</code>, passing it the argument <code>wrimoers</code> (which is conveniently populated by the function <code>get_wrimoers()</code>).</p> <p>I'll not show the Mason template here, as it's a fairly mundane HTML affair, but you can peek at it at the application's Github repo (link below). It is, however, using the <a href="http://code.google.com/p/flot/">Flot</a> jQuery plotting library to generate the graph, and it expects to get its data from an AJAX call. Which means that we need a new AJAX route for our application.</p> <h3><a name="feeding_graph_data_via_ajax"></a>Feeding graph data via AJAX</h3> <p>For the graph, we need the url <code>/data</code> to return a JSON representation of the wordcount data. Nicely enough, Dancer has a <code>to_json()</code> function that takes care of the JSON encapsulation. All that is left for us to do, really, is to do the real data munging:</p> <pre class="prettyprint">get '/data' =&gt; sub { open my $fh, '&lt;', $count_file; my %contestant; while (&lt;$fh&gt;) { chomp; my ( $date, $who, $count ) = split '\s*,\s*'; my $epoch = DateTime::Format::Flexible-&gt;parse_datetime($date)-&gt;epoch; my $time = 1000 * $epoch; $contestant{$who}{$time} = $count; } my @json; # data structure that is going to be JSONified while ( my ( $peep, $data ) = each %contestant ) { push @json, { label =&gt; $peep, hoverable =&gt; \1, # so that it becomes JavaScript's 'true' data =&gt; [ map { [ $_, $data-&gt;{$_} ] } sort { $a &lt;=&gt; $b } keys %$data ], }; } my $beginning = DateTime::Format::Flexible-&gt;parse_datetime( "2010-11-01")-&gt;epoch; my $end = DateTime::Format::Flexible-&gt;parse_datetime( "2010-12-01")-&gt;epoch; push @json, { label =&gt; 'de par', data =&gt; [ [$beginning * 1000, 0], [ DateTime-&gt;now-&gt;epoch * 1_000, 50_000 * (DateTime-&gt;now-&gt;epoch - $beginning) / ($end - $beginning) ] ], }; to_json( \@json ); };</pre> <p>For more serious AJAX interaction, there's also <a href="https://metacpan.org/module/Dancer::Plugin::Ajax">Dancer::Plugin::Ajax</a> that adds an <code>ajax</code> route handler to the mix, but in our case a simple <code>get</code> is perfectly satisfactory.</p> <h3><a name="processing_new_entries"></a>Processing New Entries</h3> <p>For the entry of a new word count, we are taking in a form request with two parameters, <i>who</i> and <i>count</i>:</p> <pre class="prettyprint">get '/add' =&gt; sub { open my $fh, '&gt;&gt;', $count_file; say $fh join ',', DateTime-&gt;now, params-&gt;{who}, params-&gt;{count}; close $fh; redirect '/'; };</pre> <p>Seriously, could things get any easier?</p> <h3><a name="bonus_feature__throwing_in_an_atom_feed"></a>Bonus Feature: Throwing in an Atom Feed</h3> <p>Since everything else resulted in a ridiculously small amount of code, I decided to add a feed to the application to let everybody know of wordcount updates. Surely that will require a lot more coding?</p> <pre class="prettyprint">get '/feed' =&gt; sub { content_type 'application/atom+xml'; # $feed is a XML::Atom::SimpleFeed object my $feed = generate_feed(); return $feed-&gt;as_string; };</pre> <p>... Seemingly not, it won't.</p> <h2><a name="deployment"></a>Deployment</h2> <p>Dancer can be deployed a gazillion different ways. As a standalone server (development heaven), as CGI (likely to be <i>sloooow</i>, but nice to it's there if everything else fail), as FastCGI, and as a <a href="https://metacpan.org/module/Plack">Plack</a> application.</p> <p>For example, to deploy is at a fastcgi talking to an Apache server, we can launch the app as a plack-backed fastcgi</p> <pre class="prettyprint">plackup -s FCGI --listen /tmp/ournowrimo.socket ournowrimo.pl</pre> <p>configure Apache to treat it as an external fastcgi server</p> <pre class="prettyprint">Alias /wrimo/ /tmp/ournowrimo.fcgi/ FastCgiExternalServer /tmp/ournowrimo.fcgi -socket /tmp/ournowrimo.socket</pre> <p>and everything should nicely begin to work together.</p> <h2><a name="the_result"></a>The Result</h2> <img src="http://babyl.dyndns.org/techblog/entry/ournowrimo/files/ournowrimo.png" /> <h2><a name="peek_at_the_code_on_github"></a>Peek at the Code on Github</h2> <p>The full application is available on <a href="http://github.com/yanick/ournowrimo">GitHub</a>.</p> <h2><a name="author"></a>Author</h2> <p>This article was originally a <a href="http://babyl.dyndns.org/techblog/entry/ournowrimo">blog entry</a> by Yanick Champoux, modified for the Perl Dancer Advent Calendar 2010.</p> <h2><a name="reviewers"></a>Reviewers</h2> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by Yanick Champoux <code>&lt;yanick@cpan.org&gt;</code></p> </div> Writing REST web services with Dancer http://advent.perldancer.org/2010/8 perl http://advent.perldancer.org/2010/8 Wed, 8 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="writing_rest_web_services_with_dancer"></a>Writing REST web services with Dancer</h1> <p>It's really easy to write REST web services with Dancer.</p> <p>A REST application is defined by:</p> <ul> <li><a name="item_a_route_to_a_resource"></a><b>a route to a resource</b> </li> <li><a name="item_an_HTTP_verb"></a><b>an HTTP verb</b> </li> <li><a name="item_a_format"></a><b>a format</b> </li> </ul> <h2><a name="serializers"></a>Serializers</h2> <p>Dancer comes with some helper functions, in order to help you to serialize your Perl data structure to something like JSON or XML.</p> <p>The core provides serializers for:</p> <ul> <li><a name="item__b_JSON__b____code_to_json__code__and__code_from_json__code__"></a><b><b>JSON</b> (<code>to_json</code> and <code>from_json</code>)</b> </li> <li><a name="item__b_XML__b____code_to_xml__code__and__code_from_xml__code__"></a><b><b>XML</b> (<code>to_xml</code> and <code>from_xml</code>)</b> </li> <li><a name="item__b_YAML__b____code_to_yaml__code__and__code_from_yaml__code__"></a><b><b>YAML</b> (<code>to_yaml</code> and <code>from_yaml</code>)</b> </li> </ul> <p>With these serializers, you can write:</p> <pre class="prettyprint">get '/user/:id' =&gt; sub { my $user = $schema-&gt;resultset('Users')-&gt;find( params-&gt;{id} ); content_type 'application/json'; return to_json { id =&gt; params-&gt;{id}, name =&gt; $user-&gt;name }; };</pre> <h2><a name="let_dancer_handle_the_serialization"></a>Let Dancer handle the serialization</h2> <h3><a name="using_json"></a>Using JSON</h3> <p>Now that we've seen how to do serialization manually, lets make Dancer do the work for us.</p> <p>You can configure your application to have a default serializer:</p> <pre class="prettyprint">set serializer =&gt; 'JSON';</pre> <p>Now, you can define a route like this:</p> <pre class="prettyprint">get '/user/:id' =&gt; sub { my $id = params-&gt;{id}; my $user = $schema-&gt;resultset('Users')-&gt;find($id); return { id =&gt; $id, name =&gt; $user-&gt;name }; };</pre> <p>As you can see, we no longer need to call the <code>content_type</code> and <code>to_json</code> functions. When you set a default serializer and your route returns an arrayref or hashref, Dancer will check if you have a default serializer defined. If that is the case, it will serialize the response to the appropriate format and set the correct content type.</p> <h3><a name="let_the_user_select_the_format_"></a>Let the user select the format.</h3> <p>If you have installed the required dependencies for using all the supported serializers by Dancer (<a href="https://metacpan.org/module/XML::Simple">XML::Simple</a>, <a href="https://metacpan.org/module/YAML">YAML</a> and <a href="https://metacpan.org/module/JSON">JSON</a>), you can even let the user choose in which format he prefers to have the content of the request. For this, you'll need to set the serializer to <b>mutable</b> (<a href="https://metacpan.org/module/Dancer::Serializer::Mutable">Dancer::Serializer::Mutable</a>. From now on, you can select your format by defining the correct value in the HTTP header of your request (<b>Content-Type</b> when doing a POST or PUT operation, and <b>Accept-Type</b> for GET and DELETE).</p> <p>So, if we take our previous example, by setting the serializer to <b>mutable</b>, we can do the following:</p> <pre class="prettyprint">$ curl http://localhost:5000/1 {"name":"franck","id":"1"} $ curl -H 'Accept-Type: text/x-yaml' http://localhost:5000/1 --- id: 1 name: franck $ curl -H 'Accept-Type: text/xml' http://localhost:5000/1 &lt;data name="franck" id="1" /&gt;</pre> <h2><a name="dancer__plugin__rest"></a>Dancer::Plugin::REST</h2> <p>There is an excellent plugin available to help you to write a REST application: <a href="https://metacpan.org/module/Dancer::Plugin::REST">Dancer::Plugin::REST</a>. With this one, you'll be able to declare routes to access resources, but also declare how you want to handle the format.</p> <h3><a name="format"></a>Format</h3> <p>As we have seen, you can already define the format by setting the <b>serializer</b> option to a certain value (JSON, YAML, mutable, etc.). The plugin add another way: by appending the format to your request. This mean you can declare this kind of route:</p> <pre class="prettyprint">prepare_serializer_for_format; get '/user/:id.:format' =&gt; sub { my $user = $schema-&gt;resultset('Users')-&gt;find(params-&gt;{id}); return { id =&gt; params-&gt;{id}, name =&gt; $user-&gt;name }; }; $ curl http://localhost:5000/1.json {"name":"franck","id":"1"} $ curl -H 'Accept-Type: text/xml' http://localhost:5000/1.xml &lt;data name="franck" id="1" /&gt;</pre> <h3><a name="resources"></a>Resources</h3> <p>As stated at the beginning of the article, with REST you defined routes to access resources. So let's do this:</p> <pre class="prettyprint">resource user =&gt; 'get' =&gt; \&amp;on_get_user, 'create' =&gt; \&amp;on_create_user, 'delete' =&gt; \&amp;on_delete_user, 'update' =&gt; \&amp;on_update_user; sub on_get_user { ... status_ok( { user =&gt; $users-&gt;id } ); } sub on_create_user { ... status_created( { user =&gt; $user-&gt;id } ); } ...</pre> <h3><a name="helpers"></a>Helpers</h3> <p>The plugin add also some helpers to return an appropriate HTTP status to your request.</p> <pre class="prettyprint">post '/user/' =&gt; sub { my $user = $schema-&gt;resultset('Users')-&gt;create(...); status_created( { id =&gt; $user-&gt;id, name =&gt; $user-&gt;name } ); };</pre> <p>This will return a new HTTP response with a status of 201.</p> <h2><a name="credits"></a>Credits</h2> <p>Most of the work done on the serializers have been inspired by the excellent plugin <a href="https://metacpan.org/module/Catalyst::Action::REST">Catalyst::Action::REST</a>. Thanks to all of the authors of this module.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Franck Cuny for the Perl Dancer Advent Calendar 2010.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by Franck Cuny <code>&lt;franck@lumberjaph.net&gt;</code>.</p> </div> Storing sessions in cookies http://advent.perldancer.org/2010/7 perl http://advent.perldancer.org/2010/7 Tue, 7 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="storing_sessions_in_cookies"></a>Storing sessions in cookies</h1> <h2><a name="history_of_stateful_http"></a>History of stateful HTTP</h2> <p>Since HTTP is a stateless protocol each request-response pair is independent. There's no state kept between responses (hence <i>stateless</i>). This feature of HTTP turned out to be both a blessing that allowed the web to scale so well and a hoop to jump through for developers of websites where the design requires keeping of state between page loads.</p> <p>Well, this deficiency is a thing of the past since Netscape invented HTTP cookies in 1994. Cookies provide an elegant way of emulating application state by transferring a piece of data from server out-of-band and keeping it on the client side. This piece is tied to a particular set of web pages via its parameters and is sent alongside each request from client back to server so that the server could restore the state and serve the request in a particular context.</p> <p>Early uses of cookies included shopping carts that stored a list of selected goods right in the cookie until the purchase was completed. Then personalised web came and lots of websites introduced "my" sections (e.g. My Yahoo) which required users to sign up/sign in to their accounts. Storing login credentials in cookies is inherently insecure both for users who risk losing them to eavesdroppers on open networks and for websites because cookies could be tampered with by malicious clients.</p> <p>So sessions emerged. The trick is to store data securely in the database while delivering a cookie with only a session identifier. The identifiers are taken from a huge space so that guessing or brute-forcing become infeasible. This is the most popular way of implementing statefulness over HTTP since then.</p> <h2><a name="problems_with_sessions"></a>Problems with sessions</h2> <p>The problems arise with load. Each and every request inside a session required a database query to retrieve the session data by its identifier or to prove the session invalid. Usability concerns require sessions to be long (all those "remember me on this computer" check boxes) and that means a session store should have room for a huge number of sessions while being sufficiently fast to serve a query for each page hit.</p> <p>Modern websites try to work around session storage problems by using special storages like <i>Memcached</i> and there's a <a href="https://metacpan.org/module/Dancer::Session::Memcached">Dancer::Session::Memcached</a> plugin to implement such a scheme in a Dancer application. That usually means replacing the database problems with Memcached problems, like Memcached not being persistent between reboots or not guaranteeing storage for any long period of time due to being a cache and not a general purpose database.</p> <h2><a name="using_cookies_more"></a>Using cookies more</h2> <p>There's an old Russian saying - "everything new is well-forgotten old" and that is exactly what is going on with storing sessions in cookies like in the old times of first shopping carts. The trick is that there is another good way of securing your sessions which does not involve any database and that is <i>cryptography</i>. Server stores session data on the client side in encrypted cookies.</p> <p>Basically, server sends this HTTP header:</p> <pre class="prettyprint">Set-Cookie: s=base64(encrypt(serialize($session_hash)))</pre> <p>Client will return this cookie with each subsequent request and server will check the validity of the data by reversing all the operations it performed when creating the cookie and verifying the embedded checksum. It will then have the session data readily available without any database access. Mismatched checksum means invalid (same as expired) session and also gives a hint about a tampering attempt going on.</p> <p>Little can be added to this. This method is not new and is in production use on some of the most loaded websites in the world for years. It is a kind of well-kept secret of doing secure stateful HTTP under heavy load. Personally, I tend to use it everywhere I can because it is also simpler than creating a server-side session store.</p> <p>The reason it is not used more widely, I think, lies in the frameworks which power a large percentage of all new websites and do not implement this mechanism. Fortunately, Dancer is not one of them.</p> <h2><a name="using_cookies_to_store_sessions_in_dancer"></a>Using cookies to store sessions in Dancer</h2> <p>The session plugin <a href="https://metacpan.org/module/Dancer::Session::Cookie">Dancer::Session::Cookie</a> implements encrypted cookies storage for sessions in a Dancer application. I wrote it more than a year ago and it had very little changes since then because it's very simple and there's little room for bugs to fix or for improvements.</p> <p>To install the plugin you will need three modules from CPAN which are not in base perl distribution: <a href="https://metacpan.org/module/Crypt::Rijndael">Crypt::Rijndael</a>, <a href="https://metacpan.org/module/Crypt::CBC">Crypt::CBC</a> for encryption/decryption and <a href="https://metacpan.org/module/String::CRC32">String::CRC32</a> for the checksum which is used to validate sessions.</p> <p>After installation, add these lines to your <i>config.yml</i>:</p> <pre class="prettyprint">session: "cookie" session_cookie_key: "random encryption key"</pre> <p>You should initialise your <b>session_cookie_key</b> with a random string of 16 or more characters right away to ensure the uniqueness of your encryption. You should also implement protection for <i>config.yml</i> by setting some permissions and not pushing it to GitHub :) Compromised encryption key may potentially lead to all sorts of bad things.</p> <p>Session expiration may be implemented on both sides. First, by using a built-in expiration features of HTTP cookies. But since the client is not trusted you can also save session creation time right inside that session and check it when you validate sessions. Automatic expiration is not implemented in <a href="https://metacpan.org/module/Dancer::Session::Cookie">Dancer::Session::Cookie</a>, patches are welcome.</p> <p>There's a limit on the size of cookies but it varies across browsers. A good practical limit to use is 4096 bytes - supported in all major browsers for a long time. This is plenty of space and if your sessions do not fit this is probably a sign of something strange happening.</p> <h2><a name="see_also"></a>SEE ALSO</h2> <p>See <a href="https://metacpan.org/module/Dancer::Session">Dancer::Session</a> for details about session usage in route handlers.</p> <p>See <a href="https://metacpan.org/module/Plack::Middleware::Session::Cookie">Plack::Middleware::Session::Cookie</a>, <a href="https://metacpan.org/module/Catalyst::Plugin::CookiedSession">Catalyst::Plugin::CookiedSession</a>, <a href="https://metacpan.org/module/Mojolicious::Controller/session">Mojolicious::Controller/session</a> for alternative implementation of this mechanism.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Alex Kapranoff for the Perl Dancer Advent Calendar 2010.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by Alex Kapranoff <code>&lt;kappa@cpan.org&gt;</code></p> </div> Testing a Dancer application http://advent.perldancer.org/2010/6 perl http://advent.perldancer.org/2010/6 Mon, 6 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="testing_a_dancer_application"></a>Testing a Dancer application</h1> <p>In <a href="http://advent.perldancer.org/2010/5">the previous article</a>, we saw how to develop a plugin. We have written our example as a plugin named <a href="https://metacpan.org/module/Dancer::Plugin::MobileDevice">Dancer::Plugin::MobileDevice</a>. In this article We'll see how to test it.</p> <p>As testing a plugin is pretty much the same thing as testing a complete application, you will learn in this article how to use the <a href="https://metacpan.org/module/Dancer::Test">Dancer::Test</a> module for building a good test suite for a Dancer application.</p> <h2><a name="why_testing"></a>Why testing?</h2> <p>Writing a plugin for the Dancer ecosystem is a great thing to do; It's a very good way to contribute to the project, but writing the plugin is not enough, you should write tests to validate your plugin before releasing it to the CPAN.</p> <p>We will now look at how easy it is to do that and we'll write a test suite to make sure everything provided by the plugin works as expected. Remember that tests are still code. Take quality seriously and your software will be better.</p> <h3><a name="the__code_is_mobile_device__code__keyword"></a>The <code>is_mobile_device</code> keyword</h3> <p>Let's start by testing that our helper works as expected, with <a href="https://metacpan.org/module/Dancer::Test">Dancer::Test</a> this is easy to do:</p> <pre class="prettyprint"># t/01-is_mobile_device.t use strict; use warnings; use Test::More import =&gt; ['!pass'];</pre> <p>Note that we ask not to import <a href="https://metacpan.org/module/Test::More">Test::More</a>'s <code>pass</code> keyword. It's already exported by Dancer and we don't want our test script to produce a warning.</p> <p>First of all, we need a basic app that uses our plugin, we'll define it within the test script, inside a lexical block:</p> <pre class="prettyprint">{ use Dancer; use Dancer::Plugin::MobileDevice; get '/' =&gt; sub { return is_mobile_device; }; }</pre> <p>OK, we have a basic app that just loads the plugin and defines one route handler which only returns the value of <code>is_mobile_device</code>. That's enough, we can now write the tests.</p> <pre class="prettyprint">use Dancer::Test;</pre> <p><a href="https://metacpan.org/module/Dancer::Test">Dancer::Test</a> provides a complete set of test functions specialized for testing a Dancer application. Here we'll use the function <code>response_content_is</code> which takes a request object (basically an array with a method and a path) and a value, and makes sure the route handler returns a response that is the same as the expected value.</p> <p>We'll define a bunch of user agent strings we consider "mobile devices" and make sure the flag is set appropriately for them:</p> <pre class="prettyprint">my @mobile_devices = qw(Android iPhone PalmOS); for my $md (@mobile_devices) { $ENV{HTTP_USER_AGENT} = $md; response_content_is [GET =&gt; '/'], 1, "agent $md is a mobile device"; }</pre> <p>And we finally add a non-mobile string:</p> <pre class="prettyprint">$ENV{HTTP_USER_AGENT} = 'Mozilla'; response_content_is [GET =&gt; '/'], 0, "Mozilla is not a mobile device";</pre> <p>Let's run the test:</p> <pre class="prettyprint">$ perl -Ilib t/01-is_mobile_device.t 1..4 ok 1 - agent iPhone is a mobile device ok 2 - agent Android is a mobile device ok 3 - agent PalmOS is a mobile device ok 4 - Mozilla is not a mobile device</pre> <p>Great! We know now for sure that <code>is_mobile_device works</code>, that's a good start!</p> <h3><a name="the_default_template_token"></a>The default template token</h3> <p>We now want to make sure all of our template calls got the <code>is_mobile_device</code> token. To do that, our test application will now only provide a route handler that calls <code>template</code>. Obviously, for this to work we need... a template to process. Dancer::Test takes care for us to initialize the views directory to <i>t/views</i>, so we can provide our test script with some views without polluting the root directory of our distribution.</p> <p>So we first create a view:</p> <pre class="prettyprint">$ mkdir t/views $ echo "is_mobile_device: &lt;% is_mobile_device %&gt;" &gt; t/views/index.tt</pre> <p>The view is very basic, it just shows the interpolation of the <code>is_mobile_device</code> token. Let's use it in our test script.</p> <pre class="prettyprint">{ use Dancer; use Dancer::Plugin::MobileDevice; get '/' =&gt; sub { template 'index', {}, { layout =&gt; undef }; }; }</pre> <p>Same as previously, we define a route handler that does just what we need. You'll see that we've given some extra options to the <code>template</code> keyword in order to disable the layout. Indeed, our plugin automatically sets a layout for mobile clients and we don't want to see that for the moment.</p> <p>The second argument given to <code>template</code> is an empty hash which is actually the tokens hash. It should have been populated by our plugin under the hood and we'll make sure of that.</p> <pre class="prettyprint">use Dancer::Test; $ENV{HTTP_USER_AGENT} = 'Android'; response_content_is [GET =&gt; '/'], "is_mobile_device: 1\n", "token is_mobile_device is present and valid for Android"; $ENV{HTTP_USER_AGENT} = 'Mozilla'; response_content_is [GET =&gt; '/'], "is_mobile_device: 0\n", "token is_mobile_device is present and valid for Mozilla";</pre> <p>Let's run the test to make sure everything is fine:</p> <pre class="prettyprint">$ perl -Ilib t/02-tokens.t 1..2 ok 1 - token is_mobile_device is present and valid for Android ok 2 - token is_mobile_device is present and valid for Mozilla</pre> <p>Cool! We now have one more thing to test: making sure the layout changes appropriately, the job of our final test script.</p> <h3><a name="the_dynamic_layout"></a>The dynamic layout</h3> <p>In this final test we want to be sure the layout is changed to 'mobile' whenever a mobile device is served, and that the original layout is reset afterwards (whether it was defined or not).</p> <p>To do that we'll use the same technique as before, but this time with the layouts:</p> <pre class="prettyprint">$ mkdir t/views/layouts $ echo -e "mobile:\n&lt;% content %&gt;" &gt; t/views/layout/mobile.tt $ echo -e "main:\n&lt;% content %&gt;" &gt; t/views/layout/main.tt</pre> <p><i>(or use your favourite editor to create our layout files)</i></p> <p>We now have our layouts waiting to be used in the <code>t/views/layouts</code> directory, let's use it.</p> <pre class="prettyprint">{ use Dancer; use Dancer::Plugin::MobileDevice; get '/' =&gt; sub { template 'index'; }; }</pre> <p>Just a basic route handler, like before, but this time if a layout is set, we'll use it.</p> <p>First, we want to test the behaviour of the app when no layout is set:</p> <pre class="prettyprint">use Dancer::Test; $ENV{HTTP_USER_AGENT} = 'Android'; response_content_like [GET =&gt; '/'], qr{mobile\nis_mobile_device: 1}ms, "mobile layout is set for mobile agents"; $ENV{HTTP_USER_AGENT} = 'Mozilla'; response_content_is [GET =&gt; '/'], "is_mobile_device: 0\n", "no layout for non-mobile agents";</pre> <p>And then, when a layout is manually set by the user:</p> <pre class="prettyprint">set layout =&gt; 'main'; $ENV{HTTP_USER_AGENT} = 'Android'; response_content_like [GET =&gt; '/'], qr{mobile\nis_mobile_device: 1}ms, "mobile layout is set for mobile agents"; $ENV{HTTP_USER_AGENT} = 'Mozilla'; response_content_like [GET =&gt; '/'], qr{main\nis_mobile_device: 0}ms, "main layout for non-mobile agents";</pre> <p>Let's see if everything works:</p> <pre class="prettyprint">$ perl -Ilib t/03-layouts.t ok 1 - mobile layout is set for mobile agents ok 2 - no layout for non-mobile agents ok 3 - mobile layout is set for mobile agents ok 4 - main layout for non-mobile agents</pre> <p>Great, everything works as expected!</p> <h2><a name="conclusion"></a>Conclusion</h2> <p>Our plugin is now covered by the test suite we've written, and we can publish it to the CPAN. Taking a step further, we could run coverage test with <a href="https://metacpan.org/module/Devel::Cover">Devel::Cover</a> in order to make sure our test suite goes through all the possible paths but that's beyond the scope of this article.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Alexis Sukrieh.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by Alexis Sukrieh <code>&lt;sukria@sukria.net&gt;</code></p> </div> How to write a plugin http://advent.perldancer.org/2010/5 perl http://advent.perldancer.org/2010/5 Sun, 5 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="how_to_write_a_plugin"></a>How to write a plugin</h1> <p>Dancer is a <a href="http://en.wikipedia.org/wiki/Domain-specific_language">DSL</a> for writing web applications. It's focused on providing the obvious which makes the feature set limited on purpose.</p> <p>For advanced or particular needs, Dancer's DSL can be extended by plugins.</p> <p>This article will explain the basics and concepts of Dancer plugins and will guide you through the writing of your first plugin: <code>Dancer::Plugin::MobileDevice</code>.</p> <h2><a name="the_basics"></a>The Basics</h2> <p>Before starting to write our own plugin, let's explain what a plugin can do and how.</p> <p>A plugin is a package that declares (with the <code>register</code> keyword) a set of <i>keywords</i> that are bound to <i>code refs</i>. When a plugin has performed all of its declarations, it registers itself in Dancer's core with the <code>register_plugin</code> keyword.</p> <p>Once a Dancer application imports a plugin, all of the keywords declared by the plugin are visible in the application's namespace, just as if they were part of Dancer's core DSL.</p> <p>A plugin can also do everything a regular Dancer application can do, like declaring a <code>before</code> filter, declaring a couple of route handlers or even running some Perl code at its import time.</p> <h2><a name="the_concept_of_a_mobile_plugin"></a>The concept of a "mobile" plugin</h2> <p>Now that we know what a Dancer plugin is, and how it works, we have to find something to do. I recently had the idea to implement a plugin which would provide the developer with a facility to detect if the user agent is a mobile device or not.</p> <p>When thinking of that idea, I realized it would be a perfect subject for an article, because the plugin itself will not be complicated while using an interesting subset of the possibilities.</p> <p>The idea is to provide the following features:</p> <ul> <li><a name="item_dynamic_layout"></a><b>dynamic layout</b> <p>We want to serve light HTML content when accessed by a mobile device, so we'll basically set a specific layout whenever a mobile client requests a page. That way, we can forget about the layout and focus on our route handlers, and the plugin will handle that for us.</p> </li> <li><a name="item_boolean_accessor__code_is_mobile_device__code_"></a><b>boolean accessor <code>is_mobile_device</code></b> <p>Basically, the plugin should provide an accessor for letting the developer know if the current user agent is a mobile device or not.</p> </li> <li><a name="item_default_token_in_templates"></a><b>default token in templates</b> <p>We want all of our template calls to be able to know about <code>is_mobile_device</code>, so we want to make it a default token.</p> </li> </ul> <p>OK, I think this feature-set sounds like a good start for <code>Dancer::Plugin::MobileDevice</code>, let's start writing it!</p> <h2><a name="writing_the_plugin"></a>Writing the plugin</h2> <p>Let's start with an empty plugin skeleton:</p> <pre class="prettyprint">package Dancer::Plugin::MobileDevice; use Dancer ':syntax'; use Dancer::Plugin; register_plugin;</pre> <p>That's it, we have an empty plugin. It does nothing yet, except registering itself to Dancer's core.</p> <p>We can now add a <i>keyword</i> which will be exported to our caller's namespace (basically, the user's application that <code>use</code>s our plugin).</p> <h3><a name="adding_a_keyword___code_is_mobile_device__code_"></a>Adding a keyword: <code>is_mobile_device</code></h3> <p>We want to provide a helper that returns a boolean value telling if the requesting user agent is a mobile device or not, we'll do that by exporting a new keyword to Dancer's DSL.</p> <p>This keyword is basically a subroutine bound to a name (<a href="https://metacpan.org/module/Dancer::Plugin">Dancer::Plugin</a> takes care of the exporting magic for us, we only have to declare new keywords with <code>register</code> and register the plugin itself when done with <code>register_plugin</code>).</p> <p>The subroutine bound to our <code>is_mobile_device</code> keyword should do one simple thing: test the user agent string of the incoming request against a pattern of known mobile devices. This is as easy as the following:</p> <pre class="prettyprint">register 'is_mobile_device' =&gt; sub { return request-&gt;user_agent =~ /(iPhone|Android|BlackBerry|Mobile|Palm)/; };</pre> <p>That's it. The <code>request</code> keyword is Dancer-native and returns a <a href="https://metacpan.org/module/Dancer::Request">Dancer::Request</a> object representing the current incoming request. It provides among other goodies an accessor to the user agent string (<code>user_agent</code>) and we test it with a regular expression with well-known mobile device strings.</p> <p>Whenever it's called from a route handler (or a filter), it returns true or false depending on the match.</p> <h3><a name="dynamic_layout"></a>Dynamic layout</h3> <p>We now want to change the layout whenever a request is served for a mobile device. This can easily be done with a before filter:</p> <pre class="prettyprint">before sub { var orig_layout =&gt; setting('layout'); if ( is_mobile_device() ) { setting layout =&gt; 'mobile'; } };</pre> <p>A <code>before</code> filter is executed whenever a request is served, <b>before</b> the route handler. This filter takes care of changing the <code>layout</code> setting whenever the <code>is_mobile_device</code> is true.</p> <p>We don't want the layout setting to remain that way afterwards, we want to restore that setting to its original value after the request is processed. That's why we save it first with the <code>var</code> keyword.</p> <p>Then, with an after filter, will reset it to its original value:</p> <pre class="prettyprint">after sub { setting layout =&gt; vars-&gt;{orig_layout}; };</pre> <p>That way, if a non-mobile client comes just after a mobile one, the layout will be back to its original value.</p> <h3><a name="default_token"></a>Default token</h3> <p>Finally, we want our templates to be able to render specific content for mobile devices, so we want to provide all our templates with a <code>is_mobile_device</code> token, whose value will be obviously given by the helper previously defined.</p> <p>This is easy to do, we just have to write a <code>before_template</code> filter, which will alter the default tokens hash table that is given to any <code>template</code> call.</p> <pre class="prettyprint">before_template sub { my $tokens = shift; $tokens-&gt;{'is_mobile_device'} = is_mobile_device(); };</pre> <p>That's it, we can now do this kind of conditions in our views:</p> <pre class="prettyprint">&lt;% IF is_mobile_device %&gt; some content for mobile devices &lt;% END %&gt;</pre> <h2><a name="conclusion"></a>Conclusion</h2> <p>Well, here we are. We now have a Dancer plugin that does what we wanted, writing a mobile-aware Dancer app will now be much easier.</p> <p>As you can imagine, I've written <a href="https://metacpan.org/module/Dancer::Plugin::MobileDevice">Dancer::Plugin::MobileDevice</a> and uploaded it to CPAN, so if you want to study it a bit more, feel free to grab the tarball. You can also check out the source code from <a href="https://github.com/sukria/Dancer-Plugin-MobileDevice">GitHub</a>.</p> <p>Furthermore, if you want to see this plugin in action, just use your smartphone to access the advent calendar. Indeed, our advent calendar is powered by <a href="http://perldancer.org">Dancer</a> and uses <code>Dancer::Plugin::MobileDevice</code> to change the layout dynamically, just as explained in this article.</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Alexis Sukrieh for the PerlDancer Advent Calendar 2010.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by Alexis Sukrieh <code>&lt;sukria@sukria.net&gt;</code></p> </div> Database connections with Dancer::Plugin::Database http://advent.perldancer.org/2010/4 perl http://advent.perldancer.org/2010/4 Sat, 4 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="database_connections_with_dancer__plugin__database"></a>Database connections with Dancer::Plugin::Database</h1> <p>The <a href="http://search.cpan.org/dist/Dancer-Plugin-Database">Dancer::Plugin::Database</a> plugin is designed to make connecting to databases from your Dancer applications simple and painless. Connection details are stored in your application's configuration, and the connection is automatically established for you (and re-established if the connection went away).</p> <h2><a name="how_do_i_use_it"></a>How do I use it?</h2> <p>Using it can be as simple as:</p> <pre class="prettyprint">my $user = database-&gt;selectrow_hashref( 'select * from users where username = ?', undef, params-&gt;{username} );</pre> <p>Calling the <code>database</code> keyword simply returns you a connected DBI object, so you can do whatever you'd usually do with a DBI object.</p> <pre class="prettyprint">get '/widget/view/:id' =&gt; sub { my $sth = database-&gt;prepare( 'select * from widgets where id = ?', ); $sth-&gt;execute(params-&gt;{id}); template 'display_widget', { widget =&gt; $sth-&gt;fetchrow_hashref }; };</pre> <h2><a name="how_do_i_tell_it_my_database_connection_details"></a>How do I tell it my database connection details?</h2> <p>Configuration is simple - for instance, in <code>config.yml</code> you could simply add:</p> <pre class="prettyprint">plugins: Database: driver: 'SQLite' database: 'foo.sqlite'</pre> <p>Or, let's say you're using MySQL, and would like to run queries automatically when you first get a connection to the database:</p> <pre class="prettyprint">plugins: Database: driver: 'mysql' database: 'databasename' username: 'fred' password: 'verysecretindeed' on_connect_do: - "SET NAMES 'utf8'" - "SET CHARACTER SET 'utf8'"</pre> <h2><a name="but_what_if_i_need_to_talk_to_multiple_databases"></a>But what if I need to talk to multiple databases?</h2> <p>All of the above examples assume that you only want to connect to one database. For the majority of web applications, that's often true, but there are of course plenty of people who'll want to talk to multiple databases.</p> <p>That's easy enough - you can define multiple named connections in your app config, and pass a name to the <code>database</code> keyword - for example:</p> <pre class="prettyprint">plugins: Database: connections: foo: driver: "SQLite" database: "foo.sqlite" bar: driver: "mysql" host: "localhost" ....</pre> <p>The above defines two connections named <code>foo</code> and <code>bar</code>. You can use them simply:</p> <pre class="prettyprint">my $foo_dbh = database('foo');</pre> <h2><a name="author"></a>Author</h2> <p>This article has been written by David Precious <code>&lt;davidp@preshweb.co.uk&gt;</code> for the Perl Dancer Advent Calendar 2010.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by David Precious</p> </div> Tutorial: writing a tiny blog engine http://advent.perldancer.org/2010/3 perl http://advent.perldancer.org/2010/3 Fri, 3 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="tutorial__writing_a_tiny_blog_engine"></a>Tutorial: writing a tiny blog engine</h1> <p>This article will guide you through the writing of a minimal but yet complete blog engine.</p> <h2><a name="origins_of_this_tutorial"></a>Origins of this tutorial</h2> <p>While I was investigating some Python web frameworks like <a href="http://flask.pocoo.org/">Flask</a> or <a href="http://bottle.paws.de/docs/dev/index.html">Bottle</a> I enjoyed the way they explained step by step how to build an example application which was a little more involved than a trivial example.</p> <p>Using the <a href="http://github.com/mitsuhiko/flask/tree/master/examples/flaskr/">Flaskr</a> sample application as my inspiration (OK, shamelessly plagiarised) I translated that application to the Dancer framework so I could better understand how Dancer worked. (I'm learning it too!)</p> <p>So "Dancr" was born.</p> <p>Dancr is a simple "micro" blog which uses the <a href="http://www.sqlite.org">SQLite</a> database engine for simplicity's sake.</p> <h2><a name="required_perl_modules"></a>Required Perl modules</h2> <p>Obviously you need <a href="https://metacpan.org/module/Dancer">Dancer</a>. You also need <a href="https://metacpan.org/module/Template">Template Toolkit</a>, <a href="https://metacpan.org/module/File::Slurp">File::Slurp</a> and <a href="https://metacpan.org/module/DBD::SQLite">DBD::SQLite</a>. These all can be installed using your CPAN client, as in:</p> <pre class="prettyprint">cpan Dancer Template File::Slurp DBD::SQLite</pre> <h2><a name="the_database"></a>The database</h2> <p>We're not going to spend a lot of time on the database, as it's not really the point of this particular tutorial.</p> <pre class="prettyprint">create table if not exists entries ( id integer primary key autoincrement, title string not null, text string not null );</pre> <p>Here we have a single table with three columns: id, title, and text. The 'id' field is the primary key and will automatically get an ID assigned by the database engine when a row is inserted.</p> <p>We want our application to initialize the database automatically for us when we start it, so open your favourite <a href="http://www.vim.org">text editor</a> and create a file called 'dancr.pl'. We're going to put the following subroutines in that file:</p> <pre class="prettyprint">sub connect_db { my $dbh = DBI-&gt;connect("dbi:SQLite:dbname=".setting('database')) or die $DBI::errstr; return $dbh; } sub init_db { my $db = connect_db(); my $schema = read_file('./schema.sql'); $db-&gt;do($schema) or die $db-&gt;errstr; }</pre> <p>Nothing too fancy in here, I hope. Standard DBI except for the <code>setting('database')</code> thing - more on that in a bit. For now, just assume that the expression evaluates to file location for the database file.</p> <h2><a name="our_first_route_handler"></a>Our first route handler</h2> <p>Let's tackle our first route handler now, the one for the root URL '/'. This is what it looks like:</p> <pre class="prettyprint">get '/' =&gt; sub { my $db = connect_db(); my $sql = 'select id, title, text from entries order by id desc'; my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute or die $sth-&gt;errstr; template 'show_entries.tt', { 'msg' =&gt; get_flash(), 'add_entry_url' =&gt; uri_for('/add'), 'entries' =&gt; $sth-&gt;fetchall_hashref('id'), }; };</pre> <p>As you can see, the handler is created by specifying the HTTP verb 'get' and the URL to match, '/' and finally a subroutine to do something once those conditions have been satisfied. Something you might not notice right away is the semicolon at the end of the route handler. Since the subroutine actually is a coderef, it requires a semicolon.</p> <p>Let's take a closer look at the subroutine. The first few lines are standard DBI. The only new concept as part of Dancer is that <code>template</code> directive at the end of the handler. That tells Dancer to process the output through one of its templating engines. In this case, we're using <a href="https://metacpan.org/module/Template">Template Toolkit</a> which offers a lot more flexibility than the simple default Dancer template engine.</p> <p>Templates all go into the <code>views/</code> directory. Optionally, you can create a "layout" template which provides a consistent look and feel for all of your views. We'll construct our own layout template cleverly named <i>main.tt</i> a little later in this tutorial.</p> <p>What's going on with the hashref as the second argument to the template directive? Those are all of the parameters we want to pass into our template. We have a <code>msg</code> field which displays a message to the user when an event happens like a new entry is posted, or the user logs in or out. It's called a "flash" message because we only want to display it one time, not every time the / URL is rendered.</p> <p>The <code>uri_for</code> directive tells Dancer to provide a URI for that specific route, in this case, it is the route to post a new entry into the database. You might ask why we don't simply hard-code the <code>/add</code> URI in our application or templates. The best reason <b>not</b> to do that is because it removes a layer of flexibility on where to "mount" the web application. Although the application is coded to use the root URL <code>/</code> it might be better in the future to locate it under its own URL route (maybe <code>/dancr</code>?) - at that point we'd have to go through our application and the templates and update the URLs and hope we didn't miss any of them. By using the <code>uri_for</code> Dancer method, we can easily load the application wherever we like and not have to modify the application at all.</p> <p>Finally, the <code>entries</code> field contains a hashref with the results from our database query. Those results will be rendered in the template itself, so we just pass them in.</p> <p>So what does the <i>show_entries.tt</i> template look like? This:</p> <pre class="prettyprint">&lt;% IF session.logged_in %&gt; &lt;form action="&lt;% add_entry_url %&gt;" method=post class=add-entry&gt; &lt;dl&gt; &lt;dt&gt;Title: &lt;dd&gt;&lt;input type=text size=30 name=title&gt; &lt;dt&gt;Text: &lt;dd&gt;&lt;textarea name=text rows=5 cols=40&gt;&lt;/textarea&gt; &lt;dd&gt;&lt;input type=submit value=Share&gt; &lt;/dl&gt; &lt;/form&gt; &lt;% END %&gt; &lt;ul class=entries&gt; &lt;% IF entries.size %&gt; &lt;% FOREACH id IN entries.keys.nsort %&gt; &lt;li&gt;&lt;h2&gt;&lt;% entries.$id.title %&gt;&lt;/h2&gt;&lt;% entries.$id.text %&gt; &lt;% END %&gt; &lt;% ELSE %&gt; &lt;li&gt;&lt;em&gt;Unbelievable. No entries here so far&lt;/em&gt; &lt;% END %&gt; &lt;/ul&gt;</pre> <p>Again, since this isn't a tutorial specifically about Template Toolkit, I'm going to gloss over the syntax here and just point out the section which starts with <code>&lt;ul class=entries&gt;</code> - this is the section where the database query results are displayed. You can also see at the very top some discussion about a session - more on that soon.</p> <h2><a name="other_http_verbs"></a>Other HTTP verbs</h2> <p>There are 8 defined HTTP verbs defined in <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9">RFC 2616</a>: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT. Of these, the majority of web applications focus on the verbs which closely map to the CRUD (Create, Retrieve, Update, Delete) operations most database driven applications need to implement.</p> <p>Dancer currently supports GET, PUT, POST, DELETE, OPTIONS which map to Retrieve, Create, Update, Delete respectively. Let's take a look now at the <code>/add</code> route handler which handles a POST operation.</p> <pre class="prettyprint">post '/add' =&gt; sub { if ( not session('logged_in') ) { send_error("Not logged in", 401); } my $db = connect_db(); my $sql = 'insert into entries (title, text) values (?, ?)'; my $sth = $db-&gt;prepare($sql) or die $db-&gt;errstr; $sth-&gt;execute(params-&gt;{'title'}, params-&gt;{'text'}) or die $sth-&gt;errstr; set_flash('New entry posted!'); redirect '/'; };</pre> <p>As before, the HTTP verb begins the handler, followed by the route, and a subroutine to do something - in this case, it will insert a new entry into the database.</p> <p>The first check in the subroutine is the make sure the user sending the data is logged in. If not, the application sends back an error and stops processing. Otherwise, we have standard DBI stuff. Let me insert (heh, heh) a blatant plug here for always, always using parameterised INSERTs in your application's SQL statements. It's the only way to be sure your application won't be vulnerable to SQL injection. (See <a href="http://www.bobby-tables.com">http://www.bobby-tables.com</a> for correct INSERT examples in multiple languages.) Here we're using the <code>params</code> convenience method to pull in the parameters in the current HTTP request. (You can see the 'title' and 'text' form parameters in the <i>show_entries.tt</i> template above.) Those values are inserted into the database, then we set a flash message for the user and redirect her back to the root URL.</p> <p>It's worth mentioning that the "flash message" is not part of Dancer, but a part of this specific application.</p> <h2><a name="logins_and_sessions"></a>Logins and sessions</h2> <p>Dancer comes with a simple in-memory session manager out of the box. It supports a bunch of other session engines including YAML, Memcached, browser cookies and others. For this application we're going to stick with the in-memory model which works great for development and tutorials, but won't persist across server restarts or scale very well in "real world" production scenarios.</p> <h2><a name="configuration_options"></a>Configuration options</h2> <p>To use sessions in our application, we have to tell Dancer to activate the session handler and initialize a session manager. To do that, we add some configuration directives toward the top of our dancr.pl file. But there are more options than just the session engine we want to set.</p> <pre class="prettyprint">set 'session' =&gt; 'Simple'; set 'template' =&gt; 'template_toolkit'; set 'logger' =&gt; 'console'; set 'log' =&gt; 'debug'; set 'show_errors' =&gt; 1; set 'access_log ' =&gt; 1; set 'warnings' =&gt; 1;</pre> <p>Hopefully these are fairly self-explanatory. We want the Simple session engine, the Template Toolkit template engine, logging enabled (at the 'debug' level with output to the console instead of a file), we want to show errors to the web browser, log access attempts and log Dancer warnings (instead of silently ignoring them)</p> <p>In a more sophisticated application you would want to put these configuration options into a YAML file, but for this tutorial, we're going to keep it simple. Dancer also supports the notion of application environments meaning you can create a configuration file for your development instance, and another config file for the production environment (with things like debugging and showing errors disabled perhaps.) Dancer also doesn't impose any limits on what parameters you can set using the <code>set</code> syntax. For this application we're going to embed our single username and password into the application itself.</p> <pre class="prettyprint">set 'username' =&gt; 'admin'; set 'password' =&gt; 'password';</pre> <p>Hopefully no one will ever guess our clever password! Obviously, you will want a more sophisticated user authentication scheme in any sort of non-tutorial application but this is good enough for our purposes.</p> <h2><a name="logging_in"></a>Logging in</h2> <p>Now that Dancr is configured to handle sessions, let's take a look at the URL handler for the <code>/login</code> route.</p> <pre class="prettyprint">any ['get', 'post'] =&gt; '/login' =&gt; sub { my $err; if ( request-&gt;method() eq "POST" ) { # process form input if ( params-&gt;{'username'} ne setting('username') ) { $err = "Invalid username"; } elsif ( params-&gt;{'password'} ne setting('password') ) { $err = "Invalid password"; } else { session 'logged_in' =&gt; true; set_flash('You are logged in.'); redirect '/'; } } # display login form template 'login.tt', { 'err' =&gt; $err, }; };</pre> <p>This is the first handler which accepts two different verb types, a GET for a human browsing to the URL and a POST for the browser to submit the user's input to the web application. Since we're handling two different verbs, we check to see what verb is in the request. If it's <b>not</b> a POST, we drop down to the <code>template</code> directive and display the <i>login.tt</i> template.</p> <pre class="prettyprint">&lt;h2&gt;Login&lt;/h2&gt; &lt;% IF err %&gt;&lt;p class=error&gt;&lt;strong&gt;Error:&lt;/strong&gt; &lt;% err %&gt;&lt;% END %&gt; &lt;form action="&lt;% login_url %&gt;" method=post&gt; &lt;dl&gt; &lt;dt&gt;Username: &lt;dd&gt;&lt;input type=text name=username&gt; &lt;dt&gt;Password: &lt;dd&gt;&lt;input type=password name=password&gt; &lt;dd&gt;&lt;input type=submit value=Login&gt; &lt;/dl&gt; &lt;/form&gt;</pre> <p>This is even simpler than our <i>show_entries.tt</i> template - but wait - there's a <code>login_url</code> template parameter and we're only passing in the <code>err</code> parameter. Where's the missing parameter? It's being generated and sent to the template in a <code>before_template</code> directive - we'll come back to that in a moment or two.</p> <p>So the user fills out the <i>login.tt</i> template and submits it back to the <code>/login</code> route handler. We now check the user input against our application settings and if they're incorrect, we alert the user, otherwise the application starts a session and sets the <code>logged_in</code> session parameter to the <code>true()</code> value. Dancer exports both a <code>true()</code> and <code>false()</code> convenience method which we use here. After that, it's another flash message and back to the root URL handler.</p> <h2><a name="logging_out"></a>Logging out</h2> <p>And finally, we need a way to clear our user's session with the customary logout procedure.</p> <pre class="prettyprint">get '/logout' =&gt; sub { session-&gt;destroy; set_flash('You are logged out.'); redirect '/'; };</pre> <p><code>session-&gt;destroy;</code> is Dancer's way to remove a stored session. We notify the user she is logged out and route her back to the root URL once again.</p> <h2><a name="layout_and_static_files"></a>Layout and static files</h2> <p>We still have a missing puzzle piece or two. First, how can we use Dancer to serve our CSS stylesheet? Second, where are flash messages displayed? Third, what about the <code>before_template</code> directive?</p> <h2><a name="serving_static_files"></a>Serving static files</h2> <p>In Dancer, static files should go into the <code>public/</code> directory, but in the application be sure to omit the <code>public/</code> element from the path. For example, the stylesheet for Dancr lives in <code>dancr/public/css/style.css</code> but is served from <a href="http://localhost:3000/css/style.css">http://localhost:3000/css/style.css</a>.</p> <p>If you wanted to build a mostly static web site you could simply write route handlers like this one:</p> <pre class="prettyprint">get '/' =&gt; sub { send_file 'index.html'; };</pre> <p>where index.html would live in your <code>public/</code> directory.</p> <p><code>send_file</code> does exactly what it says: it loads a static file, then sends the contents of that file to the user.</p> <h2><a name="layouts"></a>Layouts</h2> <p>I mentioned near the beginning of this tutorial that it is possible to create a <code>layout</code> template. In Dancr, that layout is called <code>main</code> and it's set up by putting in a directive like this:</p> <pre class="prettyprint">layout 'main';</pre> <p>near the top of your web application. What this tells Dancer's template engine is that it should look for a file called <i>main.tt</i> in <code>dancr/views/layouts/</code> and insert the calls from the <code>template</code> directive into a template parameter called <code>content</code>.</p> <p>For this web application, the layout template looks like this.</p> <pre class="prettyprint">&lt;!doctype html&gt; &lt;html&gt; &lt;head&gt; &lt;title&gt;Dancr&lt;/title&gt; &lt;link rel=stylesheet type=text/css href="&lt;% css_url %&gt;"&gt; &lt;/head&gt; &lt;body&gt; &lt;div class=page&gt; &lt;h1&gt;Dancr&lt;/h1&gt; &lt;div class=metanav&gt; &lt;% IF not session.logged_in %&gt; &lt;a href="&lt;% login_url %&gt;"&gt;log in&lt;/a&gt; &lt;% ELSE %&gt; &lt;a href="&lt;% logout_url %&gt;"&gt;log out&lt;/a&gt; &lt;% END %&gt; &lt;/div&gt; &lt;% IF msg %&gt; &lt;div class=flash&gt; &lt;% msg %&gt; &lt;/div&gt; &lt;% END %&gt; &lt;% content %&gt; &lt;/div&gt; &lt;/body&gt; &lt;/html&gt;</pre> <p>Aha! You now see where the flash message <code>msg</code> parameter gets rendered. You can also see where the content from the specific route handlers is inserted (the fourth line from the bottom in the <code>content</code> template parameter.)</p> <p>But what about all those other <code>*_url</code> template parameters?</p> <h2><a name="using__code_before_template__code_"></a>Using <code>before_template</code></h2> <p>Dancer has a way to manipulate the template parameters before they're passed to the engine for processing. It's <code>before_template</code>. Using this directive, you can generate and set the URIs for the <code>/login</code> and <code>/logout</code> route handlers and the URI for the stylesheet. This is handy for situations like this where there are values which are re-used consistently across all (or most) templates. This cuts down on code-duplication and makes your app easier to maintain over time since you only need to update the values in this one place instead of everywhere you render a template.</p> <pre class="prettyprint">before_template sub { my $tokens = shift; $tokens-&gt;{'css_url'} = request-&gt;base . 'css/style.css'; $tokens-&gt;{'login_url'} = uri_for('/login'); $tokens-&gt;{'logout_url'} = uri_for('/logout'); };</pre> <p>Here again I'm using <code>uri_for</code> instead of hardcoding the routes. This code block is executed before any of the templates are processed so that the template parameters have the appropriate values before being rendered.</p> <h2><a name="putting_it_all_together"></a>Putting it all together</h2> <p>If you want to test the application of this tutorial, you can grab the complete source code on <a href="https://github.com/PerlDancer/advent-calendar-apps/tree/master/2010/03-dancr/">GitHub</a></p> <pre class="prettyprint">git clone https://github.com/PerlDancer/advent-calendar-apps.git cd advent-calendar-apps/2010/03-dancr/ perl dancr.pl</pre> <h2><a name="advanced_route_moves"></a>Advanced route moves</h2> <p>There's a lot more to route matching than shown here. For example, you can match routes with regular expressions, or you can match pieces of a route like <code>/hello/:name</code> where the <code>:name</code> piece magically turns into a named parameter in your handler for manipulation.</p> <h2><a name="happy_dancing_"></a>Happy dancing!</h2> <p>I hope this effort has been helpful and interesting enough to get you exploring Dancer on your own. The framework is still under heavy development but it's definitely mature enough to use in a production project. Additionally, there are now a lot of great Dancer plugins which extend and enhance the capabilities of the the platform.</p> <p>Happy dancing!</p> <h2><a name="author"></a>Author</h2> <p>This article has been written by Mark R. Allen for the Perl Dancer Advent Calendar. It's also shipped with Dancer as <a href="https://metacpan.org/module/Dancer::Tutorial">Dancer::Tutorial</a>.</p> <h2><a name="copyright"></a>Copyright</h2> <p>Copyright (C) 2010 by Mark R. Allen.</p> </div> Why routes - route-based programming introduction http://advent.perldancer.org/2010/2 perl http://advent.perldancer.org/2010/2 Thu, 2 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="why_routes___route_based_programming_introduction"></a>Why routes - route-based programming introduction</h1> <p>In this article, we'll try to explain the basic premise behind Dancer, to make it easier for you to get started. That premise being <i>route-based web programming</i>.</p> <h2><a name="common_web_programming_models"></a>Common web programming models</h2> <h3><a name="cgi"></a>CGI</h3> <p>CGI (Common Gateway Interface) is arguably the most common web programming model. Not because it's particularly good, but because it's the simplest to write (something which is no longer true, thanks to Dancer, as we'll see later on) and the easier to configure on a web server.</p> <p>Mainly CGI web programming entails the web server running a script, providing everything possible (such as request parameters) in the environment variable (<code>%ENV</code>) and taking the standard output (<i>STDOUT</i>) and returning that to the browser, except the first chunk which is used for internal browser usage (such as declaring content type, setting cookies, noting redirects and so forth).</p> <p>Every time a browser makes a request, the server runs the CGI script and gets the information back to the browser. This is clearly very wasteful in resources.</p> <p>This can give programmers a lot of hassle. For example, you need to purify your environment variables, you need to print the content type (if you only provide one chunk of content without the internal browser chunk), the web server will crash your request and send the browser a 500 (Internal Server Error).</p> <p>You have to understand what a user wanted by checking the parameters. Even if use the great <a href="https://metacpan.org/module/CGI">CGI</a> module, you still need to write the entire logic behind what should happen and when.</p> <p>For example, to print the main page, you may write code such as this:</p> <pre class="prettyprint">use strict; use warnings; use CGI; my $cgi = CGI-&gt;new; if ( my $page = $cgi-&gt;param('page') ) { if ( $page eq 'main' ) { print $cgi-&gt;header( charset =&gt; 'UTF-8' ); # get main page and print it } }</pre> <p>That's a lot of boilerplate, and we haven't really gone into parameters which define how the page will be displayed, templating boilerplate and pretty links.</p> <h3><a name="mvc"></a>MVC</h3> <p>MVC (Model, View, Controller) was a major breakthrough that allowed us to write our code more efficiently with reusable components and logical separation.</p> <p>An MVC framework allows you to separate your application to a <i>Model</i> which handles your database connections - ORM-laden, usually, a <i>View</i> which handles your output (usually through templates) with their configuration and preferences and finally a <i>Controller</i> which contains your application logic.</p> <p>This allows you to write scalable, clean, understandable, reusable code.</p> <h2><a name="namespace_matching"></a>Namespace matching</h2> <p>MVC relies on something we refer to as <i>namespace matching</i>, which means that in order to dispatch a request to the correct code piece, the MVC framework will have a (usually predetermined) destination according to your application's namespace.</p> <p>In <a href="https://metacpan.org/module/Catalyst">Catalyst</a>, for example, a request to <code>http://myapp/view/articles/30</code> will be dispatched using the namespace <i>MyAppName::View</i> (as long as our app is under a <i>MyApp</i> namespace) to the file <i>View.pm</i>, to the function <i>articles</i> and will send <i>30</i> to as a first parameter to the function.</p> <p>This easy logic allows Catalyst (and MVC frameworks) to be very accurate, but also more rigid. Catalyst itself has many ways of making it much more flexible.</p> <h2><a name="routes"></a>Routes</h2> <p>Routes was an idea introduced by Ruby's <b>Sinatra</b> framework (which we often credit) and takes a much cleaner and clearer approach to cut down on the added hierarchy complexity that MVC can add.</p> <p>Routes are basically paths the user takes which are attached to code that will be triggered when a user reaches the specific route.</p> <h3><a name="basic_dispatching"></a>Basic dispatching</h3> <p>Imagine a user making a GET request to <i>/</i>. The following route will catch it and execute the attached subroutine:</p> <pre class="prettyprint">get '/' =&gt; sub { 'yay' };</pre> <p>In <a href="https://metacpan.org/module/Dancer">Dancer</a>, every return value is actually the content the user will get - and don't worry, you don't have to specify what the content type is, although you can.</p> <p>Usually you will render a template, and you can do that just as easy:</p> <pre class="prettyprint">get '/' =&gt; sub { template 'index' };</pre> <p>You'll notice that routes are very succinct and easy to read.</p> <h3><a name="parameters"></a>Parameters</h3> <p>The code that routes run do not get any parameters and instead rely on framework keywords to get the information needed. For example, to get the name of a user in a form that was <i>POST</i>ed to a route:</p> <pre class="prettyprint">post '/login' =&gt; sub { return "Hello, ", params-&gt;{'name'}; };</pre> <p>Routes are also able to specify variables in a given route, to allow for more dynamic routes. Here is an article view route:</p> <pre class="prettyprint">get '/view/article/:id' =&gt; sub { template 'article' =&gt; { entry = get_article( params-&gt;{'id'} ), }; };</pre> <p><a href="https://metacpan.org/module/Dancer">Dancer</a> does not carry an ORM or DB bindings with it because it aspires to be as lightweight as possible, but there are plugins which allow you to hook up to schemas straight from your app. Check out <a href="https://metacpan.org/module/Dancer::Plugin::Database">Dancer::Plugin::Database</a> and <a href="https://metacpan.org/module/Dancer::Plugin::DBIC">Dancer::Plugin::DBIC</a> for more on that.</p> <h3><a name="regular_expressions"></a>Regular expressions</h3> <p>Routes have much more to offer but in case you're not fully happy with the default spec for routes, you can specify your own route in any way, shape or form you find comfortable using regexes:</p> <pre class="prettyprint">get qr{ / view / articles / (\d+)(\.\d+)? }x =&gt; sub { # the matches can then be fetched using splat() my @matches = splat; };</pre> <p><i>(splat is a keyword that originated in Sinatra, blame them for the name :)</i></p> <h3><a name="more"></a>More</h3> <p>Routes actually have another thing or two up their sleeve (such as being able to skip routes or filter routes by hostname or user agent strings), but you can read all about it on <a href="https://metacpan.org/module/Dancer">Dancer</a> and <a href="https://metacpan.org/module/Dancer::Introduction">Dancer::Introduction</a>.</p> <h2><a name="summary"></a>Summary</h2> <p>What we've gone over in this article is the difference between CGI programming, MVC programming and route-based programming (which was introduced by the micro web frameworks).</p> <p>You may ask, however, what should you choose for your project? Which is the best?</p> <p>It's all a matter of choice and you first know that every project may be different than the next. You might want to use Dancer for one project but prefer to use Catalyst for another (and hopefully never use pure CGI for anything), and that's perfectly fine, because that's what we do too. :)</p> <p>The major benefit of route-based web programming is that it's much lighter, requires no specific directory hierarchy or a strong separation of model and view (since in Dancer you can configure both in the main config file in two-three lines). It's easier and faster to get it up and running, that's for sure. It's also here to stay.</p> <h2><a name="author"></a>Author</h2> <p>Sawyer X</p> </div> Dancer 1.2 - a micro web framework milestone http://advent.perldancer.org/2010/1 perl http://advent.perldancer.org/2010/1 Wed, 1 Dec 2010 00:00:00 -0000 <div class="pod-document"><h1><a name="dancer_1_2___a_micro_web_framework_milestone"></a>Dancer 1.2 - a micro web framework milestone</h1> <h2><a name="dancer"></a>Dancer?</h2> <p><a href="https://metacpan.org/module/Dancer">Dancer</a> is a micro web framework that allows you to get a website up and running within a minute, if not sooner. It abstracts away a lot of nastiness that exists in web programming and lets you focus just on the important details, without compromising on control and strength.</p> <p>The inspiration for Dancer is the Ruby micro web framework <b>Sinatra</b>, which we started to port and since then started diverging from Sinatra to our own path.</p> <p>It supports <a href="https://metacpan.org/module/Plack">Plack</a>/<a href="https://metacpan.org/module/PSGI">PSGI</a> so you can enjoy the new modern Perl world, but it also supports an internal web server to allow you to rapidly develop your web application without setting up a web server.</p> <p>The following synopsis shows just how strong and yet simple Dancer really is:</p> <pre class="prettyprint">get '/view/user/:id' =&gt; sub { my $id = params-&gt;{'id'}; my $details = database-&gt;selectrow_hashref( 'select * from users where id=?', undef, params-&gt;{id} ); template user =&gt; { user =&gt; $details }; };</pre> <p>This shows off an HTTP <b>GET</b> request route with a variable in it which is attached to an anonymous subroutine which gets the ID, performs a simple database query (using <a href="https://metacpan.org/module/Dancer::Plugin::Database">Dancer::Plugin::Database</a>) and passes the data to a template to render the resulting page.</p> <p>It really is that simple!</p> <p>If you like this, you should check out the Dancer website and documentation for more information on what Dancer can do to ease your web programming pain and leaving you with the fun, interesting parts.</p> <h2><a name="dancer_1_2_is_finally_out"></a>Dancer 1.2 is finally out</h2> <p>We've been speaking our heads off on the <b>1.2</b> release of Dancer for a while now. Why are we so excited, you ask? Well, for a few reasons!</p> <h3><a name="the_community_blossomed"></a>The community blossomed</h3> <p>The Dancer community has grown with time and provided a nice warm place for people to raise questions, ideas and create things together. Version 1.2 presents a culmination of the communal work of a very large number of people, all from the community, in a wide variety of areas from documentation, bug tracing, bug fixes, features and even design.</p> <p>Therefore this release is dedicated to the Dancer community itself!</p> <h3><a name="utf_8_ftw_"></a>UTF-8 FTW!</h3> <p>One of the issues the community stressed is having Unicode support, and we've decided it was about time to implement it fully.</p> <p>Unicode support isn't as trivial as it sounds, though. You have to support it in the core of the framework for parameter and environment parsing, in the different template engines (and Dancer has quite a few) and all around.</p> <p>So now we have that! It's also on by default for you!</p> <h3><a name="use_the_docs__luke_"></a>Use the docs, Luke!</h3> <p>If you like reading documentation (and who doesn't, really?), we made a lot of improvements to the docs. We've added a lot and changed quite a bit to make it clearer.</p> <p>While it still isn't perfect, it's a great place to start and you'll be able to understand more and more core layers of Dancer, and it will even give you a heads up if you feel like playing with the core, adding a feature, fixing a bug or simply better understand how Dancer works.</p> <p>All Dancer's features and keywords are documented; we also have a tutorial, a cookbook for those who prefer to see short examples of how to achieve common tasks, and full in-depth examples too.</p> <h3><a name="stable_solid_foundations"></a>Stable solid foundations</h3> <p>Users should always be able to trust Dancer to be stable. We've put countless hours into fixing bugs and improving the quality to ensure that now, more than ever, Dancer is a solid foundation you can depend upon.</p> <p>While some of this work went into code, a major part went as well to documenting the code and writing plenty of tests to have a very high code coverage.</p> <p>Some of the work also included our internal policies, such as the deprecation policy. When Dancer 1.2 finds you're doing something deprecated, it will not break, but instead inform you of it (via warning) so you will be able to fix it at your leisure. The entire 1.2xxx release series promises not to break your app, unless it is a critical fix (such as a security concern - which is business-critical). You are assured stability in upgrading to any 1.2xxx release.</p> <h3><a name="deployability"></a>Deployability</h3> <p>Yes, <i>deployability</i> is indeed a word (we checked) and it is something that all web applications dread. Since Dancer itself supports PSGI/Plack, deploying your Dancer applications is easy and flexible.</p> <p>However, the point that people find tricky is <b>how</b>. How do I configure my Apache for Dancer? What if it's Lighttpd, or Nginx? What about.. what about...?</p> <p>Therefore, we put effort in preparing <a href="https://metacpan.org/module/Dancer::Deployment">Dancer::Deployment</a> which provides instructions on how to configure web servers for your Dancer application.</p> <p>We've also put more work for the CGI and FCGI runner files and they should prove to be more correct and aid you better in deploying your app.</p> <h3><a name="oh__the_pretty_pretty_colors"></a>Oh, the pretty pretty colors</h3> <p>Dancer comes with a scaffolding script that gives you a nice layout to play with when you just start programming. We've decided to give it a whirl as well and improved it quite a bit.</p> <p>Your new scaffolded app should be prettier and more impressive, without making any effort. It even uses the jQuery JavaScript library! OMG jQuery!</p> <h2><a name="what_s_in_the_future_for_dancer"></a>What's in the future for Dancer</h2> <p>While we hope you enjoy version 1.2, we're not about to rest on our laurels. We're still working on improving the core, the documentation, the code testing coverage, provide new features, expand and flex other features and provide a stable set of community plugins to remove more and more clutter from your work.</p> <h2><a name="advent_calendar_you_too_really"></a>Advent calendar? You too? Really?</h2> <p>The advent calendar is our way of showcasing Dancer's ability by showing you how to write Dancer applications, plugins and engines. You'll learn how to deploy your applications on various backends and understand the beauty of simplicity that Dancer offers using its clean <a href="http://en.wikipedia.org/wiki/Domain-specific_language">DSL</a> and route-based structure.</p> <p>Stay tuned for more awesomeness!</p> <h2><a name="credits"></a>Credits</h2> <p>Credit goes to the entire Dancer community for our 1.2 release and the advent calendar. Dancer would definitely not be where it's at right now without the love and care the community has given it.</p> <p>A great thanks goes (and not limited) to the following people (in alphabetical order):</p> <ul> <li><a name="item_Adam_J__Foxson"></a><b>Adam J. Foxson</b> </li> <li><a name="item_Al_Newkirk"></a><b>Al Newkirk</b> </li> <li><a name="item_Alexis_Sukrieh"></a><b>Alexis Sukrieh</b> </li> <li><a name="item_Anton_Ukolov"></a><b>Anton Ukolov</b> </li> <li><a name="item_Boris_Shomodjvarac"></a><b>Boris Shomodjvarac</b> </li> <li><a name="item_crujones"></a><b>crujones</b> </li> <li><a name="item_Damien_Krotkine"></a><b>Damien Krotkine</b> </li> <li><a name="item_Danijel_Tasov"></a><b>Danijel Tasov</b> </li> <li><a name="item_Dave_Doyle"></a><b>Dave Doyle</b> </li> <li><a name="item_David_Precious"></a><b>David Precious</b> </li> <li><a name="item_Franck_Cuny"></a><b>Franck Cuny</b> </li> <li><a name="item_Gabor_Szabo"></a><b>Gabor Szabo</b> </li> <li><a name="item_Igor_Bujna"></a><b>Igor Bujna</b> </li> <li><a name="item_Ivan"></a><b>Ivan</b> </li> <li><a name="item_Mark_Allen"></a><b>Mark Allen</b> </li> <li><a name="item_Maurice"></a><b>Maurice</b> </li> <li><a name="item_Mike_Schroeder"></a><b>Mike Schroeder</b> </li> <li><a name="item_Naveed_Massjouni"></a><b>Naveed Massjouni</b> </li> <li><a name="item_Naveen_Manivannan"></a><b>Naveen Manivannan</b> </li> <li><a name="item_Nick_Langridge"></a><b>Nick Langridge</b> </li> <li><a name="item_Philippe_Bruhat"></a><b>Philippe Bruhat</b> </li> <li><a name="item_Puneet_Kishor"></a><b>Puneet Kishor</b> </li> <li><a name="item_Rafa&#x142;_Pocztarski"></a><b>Rafa&#x142; Pocztarski</b> </li> <li><a name="item_Roman_Galeev"></a><b>Roman Galeev</b> </li> <li><a name="item_Sawyer_X"></a><b>Sawyer X</b> </li> <li><a name="item_Sebastian_de_Castelberg"></a><b>Sebastian de Castelberg</b> </li> <li><a name="item_snearch"></a><b>snearch</b> </li> <li><a name="item_Stefan_Oberwahrenbrock"></a><b>Stefan Oberwahrenbrock</b> </li> <li><a name="item_Yanick_Champoux"></a><b>Yanick Champoux</b> </li> <li><a name="item_and_everyone_in_the_community_we_ve_missed_"></a><b>and everyone in the community we've missed.</b> </li> </ul> </div>