1Dancer::Cookbook(3)   User Contributed Perl Documentation  Dancer::Cookbook(3)
2
3
4

NAME

6       Dancer::Cookbook - a quick-start guide to the Dancer web framework
7

VERSION

9       version 1.3512
10

DESCRIPTION

12       A quick-start guide with examples to get you up and running with the
13       Dancer web framework.
14

BEGINNER'S DANCE

16   Your first Dancer web app
17       Dancer has been designed to be easy to work with. It's trivial to write
18       a simple web app, but still has the power to work with larger projects.
19       To start with, let's make an incredibly simple "Hello World" example:
20
21           #!/usr/bin/perl
22
23           use Dancer;
24
25           get '/hello/:name' => sub {
26               return "Why, hello there " . params->{name};
27           };
28
29           dance;
30
31       Yes, the above is a fully-functioning web app; running that script will
32       launch a webserver listening on the default port (3000). Now you can
33       make a request
34
35           $ curl http://localhost:3000/hello/Bob
36           Why, hello there Bob
37
38       (or the name of the machine you ran it on, if it's not your local
39       system), and it will say hello.  The ":name" part is a named parameter
40       within the route specification whose value is made available through
41       "params" - more on that later.
42
43       Note that you don't need to use the "strict" and "warnings" pragma,
44       they are already loaded by Dancer.  (If you don't want the "warnings"
45       pragma (which can lead to undesired warnings about use of undef values,
46       for example), then set the import_warnings setting to a false value.
47
48   Starting a Dancer project
49       The first simple example is fine for trivial projects, but for anything
50       more complex you'll want a more maintainable solution - enter the
51       "dancer" helper script, which will build the framework of your
52       application with a single command:
53
54           $ dancer -a mywebapp
55           + mywebapp
56           + mywebapp/bin
57           + mywebapp/bin/app.pl
58           + mywebapp/config.yml
59           + mywebapp/environments
60           + mywebapp/environments/development.yml
61           + mywebapp/environments/production.yml
62           + mywebapp/views
63           + mywebapp/views/index.tt
64           + mywebapp/views/layouts
65           + mywebapp/views/layouts/main.tt
66           + mywebapp/MANIFEST.SKIP
67           + mywebapp/lib
68           + mywebapp/lib/mywebapp.pm
69           + mywebapp/public
70           + mywebapp/public/css
71           + mywebapp/public/css/style.css
72           + mywebapp/public/css/error.css
73           + mywebapp/public/images
74           + mywebapp/public/500.html
75           + mywebapp/public/404.html
76           + mywebapp/public/dispatch.fcgi
77           + mywebapp/public/dispatch.cgi
78           + mywebapp/public/javascripts
79           + mywebapp/public/javascripts/jquery.min.js
80           + mywebapp/t
81           + mywebapp/t/002_index_route.t
82           + mywebapp/t/001_base.t
83           + mywebapp/Makefile.PL
84
85       As you can see, it creates a directory named after the name of the app,
86       along with a configuration file, a views directory (where your
87       templates and layouts will live), an environments directory (where
88       environment-specific settings live), a module containing the actual
89       guts of your application, a script to start it - or to run your web app
90       via Plack/PSGI - more on that later.
91

DANCE ROUTINES: ROUTES

93   Declaring routes
94       To control what happens when a web request is received by your webapp,
95       you'll need to declare "routes".  A route declaration indicates for
96       which HTTP method(s) it is valid, the path it matches (e.g. /foo/bar),
97       and a coderef to execute, which returns the response.
98
99           get '/hello/:name' => sub {
100               return "Hi there " . params->{name};
101           };
102
103       The above route specifies that, for GET requests to '/hello/...', the
104       code block provided should be executed.
105
106   Handling multiple HTTP request methods
107       Routes can use "any" to match all, or a specified list of HTTP methods.
108
109       The following will match any HTTP request to the path /myaction:
110
111           any '/myaction' => sub {
112               # code
113           }
114
115       The following will match GET or POST requests to /myaction:
116
117           any ['get', 'post'] => '/myaction' => sub {
118               # code
119           };
120
121       For convenience, any route which matches GET requests will also match
122       HEAD requests.
123
124   Retrieving request parameters
125       The params keyword returns a hashref of request parameters; these will
126       be parameters supplied on the query string, within the path itself
127       (with named placeholders), and, for HTTP POST requests, the content of
128       the POST body.
129
130   Named parameters in route path declarations
131       As seen above, you can use ":somename" in a route's path to capture
132       part of the path; this will become available by calling params.
133
134       So, for a web app where you want to display information on a company,
135       you might use something like:
136
137           get '/company/view/:companyid' => sub {
138               my $company_id = params->{companyid};
139               # Look up the company and return appropriate page
140           };
141
142   Wildcard path matching and splat
143       You can also declare wildcards in a path, and retrieve the values they
144       matched with the splat keyword:
145
146           get '/*/*' => sub {
147               my ($action, $id) = splat;
148               if (my $action eq 'view') {
149                   return display_item($id);
150               } elsif ($action eq 'delete') {
151                   return delete_item($id);
152               } else {
153                   status 'not_found';
154                   return "What?";
155               }
156           };
157
158   Before hooks - processed before a request
159       A before hook declares code which should be handled before a request is
160       passed to the appropriate route.
161
162           hook 'before' => sub {
163               var note => 'Hi there';
164               request->path_info('/foo/oversee')
165           };
166
167           get '/foo/*' => sub {
168               my ($match) = splat; # 'oversee';
169               vars->{note}; # 'Hi there'
170           };
171
172       The above declares a before hook which uses "var" to set a variable
173       which will later be available within the route handler, then amends the
174       path of the request to "/foo/oversee"; this means that, whatever path
175       was requested, it will be treated as though the path requested was
176       "/foo/oversee".
177
178   Default route
179       In case you want to avoid a 404 error, or handle multiple routes in the
180       same way and you don't feel like configuring all of them, you can set
181       up a default route handler.
182
183       The default route handler will handle any request that doesn't get
184       served by any other route.
185
186       All you need to do is set up the following route as the last route:
187
188           any qr{.*} => sub {
189               status 'not_found';
190               template 'special_404', { path => request->path };
191           };
192
193       Then you can set up the template as such:
194
195           You tried to reach <% path %>, but it is unavailable at the moment.
196
197           Please try again or contact us at our email at <...>.
198
199   Using the auto_page feature for automatic route creation
200       For simple "static" pages, you can simply enable the "auto_page" config
201       setting; this means that you need not declare a route handler for those
202       pages; if a request is for "/foo/bar", Dancer will check for a matching
203       view (e.g.  "/foo/bar.tt" and render it with the default layout etc if
204       found.  For full details, see the documentation for the auto_page
205       setting.
206
207   Why should I use the Ajax plugin
208       As an Ajax query is just an HTTP query, it's similar to a GET or POST
209       route. You may ask yourself why you may want to use the "ajax" keyword
210       (from the Dancer::Plugin::Ajax plugin) instead of a simple "get".
211
212       Let's say you have a path like '/user/:user' in your application. You
213       may want to be able to serve this page, with a layout and HTML content.
214       But you may also want to be able to call this same url from a
215       javascript query using Ajax.
216
217       So, instead of having the following code:
218
219           get '/user/:user' => sub {
220                if (request->is_ajax) {
221                    # create xml, set headers to text/xml, blablabla
222                     header('Content-Type' => 'text/xml');
223                     header('Cache-Control' =>  'no-store, no-cache, must-revalidate');
224                     to_xml({...})
225                }else{
226                    template users, {....}
227                }
228           };
229
230       you can have
231
232           get '/user/:user' => sub {
233               template users, {...}
234           }
235
236       and
237
238           ajax '/user/:user' => sub {
239                to_xml({...}, RootName => undef);
240           }
241
242       Because it's an Ajax query you know you need to return XML content, so
243       the content type of the response is set for you.
244
245   Using the prefix feature to split your application
246       For better maintainability you may want to separate some of your
247       application components to different packages. Let's say we have a
248       simple web app with an admin section, and want to maintain this in a
249       different package:
250
251           package myapp;
252           use Dancer ':syntax';
253           use myapp::admin;
254
255           prefix undef;
256
257           get '/' => sub {...};
258
259           1;
260
261           package myapp::admin;
262           use Dancer ':syntax';
263
264           prefix '/admin';
265
266           get '/' => sub {...};
267
268           1;
269
270       The following routes will be generated for us:
271
272           - get /
273           - get /admin/
274           - head /
275           - head /admin/
276

MUSCLE MEMORY: STORING DATA

278   Handling sessions
279       It's common to want to use sessions to give your web applications
280       state; for instance, allowing a user to log in, creating a session, and
281       checking that session on subsequent requests.
282
283       To make use of sessions you must first enable the session engine. Pick
284       the session engine you want to use, then declare it in your config
285       file:
286
287           session: Simple
288
289       The Dancer::Session::Simple backend implements very simple in-memory
290       session storage.  This will be fast and useful for testing, but
291       sessions do not persist between restarts of your app.
292
293       You can also use the Dancer::Session::YAML backend included with
294       Dancer, which stores session data on disc in YAML files (since YAML is
295       a nice human-readable format, it makes inspecting the contents of
296       sessions a breeze):
297
298           session: YAML
299
300       Or, to enable session support from within your code,
301
302           set session => 'YAML';
303
304       (Controlling settings is best done from your config file, though).
305       'YAML' in the example is the session backend to use; this is shorthand
306       for Dancer::Session::YAML.  There are other session backends you may
307       wish to use, for instance Dancer::Session::Memcache, but the YAML
308       backend is a simple and easy to use example which stores session data
309       in a YAML file in sessions).
310
311       You can then use the session keyword to manipulate the session:
312
313       Storing data in the session
314
315       Storing data in the session is as easy as:
316
317           session varname => 'value';
318
319       Retrieving data from the session
320
321       Retrieving data from the session is as easy as:
322
323           session('varname')
324
325       Or, alternatively,
326
327           session->{varname}
328
329       Controlling where sessions are stored
330
331       For disc-based session back ends like Dancer::Session::YAML,
332       Dancer::Session::Storable etc, session files are written to the session
333       dir specified by the "session_dir" setting, which defaults to
334       "appdir/sessions".
335
336       If you need to control where session files are created, you can do so
337       quickly and easily within your config file. For example:
338
339           session_dir: /tmp/dancer-sessions
340
341       If the directory you specify does not exist, Dancer will attempt to
342       create it for you.
343
344       Destroying a session
345
346       When you're done with your session, you can destroy it:
347
348           session->destroy
349
350   Sessions and logging in
351       A common requirement is to check the user is logged in, and, if not,
352       require them to log in before continuing.
353
354       This can easily be handled with a before hook to check their session:
355
356           hook 'before' => sub {
357               if (! session('user') && request->path_info !~ m{^/login}) {
358                   var requested_path => request->path_info;
359                   request->path_info('/login');
360               }
361           };
362
363           get '/login' => sub {
364               # Display a login page; the original URL they requested is available as
365               # vars->{requested_path}, so could be put in a hidden field in the form
366               template 'login', { path => vars->{requested_path} };
367           };
368
369           post '/login' => sub {
370               # Validate the username and password they supplied
371               if (params->{user} eq 'bob' && params->{pass} eq 'letmein') {
372                   session user => params->{user};
373                   redirect params->{path} || '/';
374               } else {
375                   redirect '/login?failed=1';
376               }
377           };
378
379       In your login page template, you'll want a text field named user, a
380       password field named pass, and a hidden field named path, which will be
381       populated with the path originally requested, so that it's sent back in
382       the POST submission, and can be used by the post route to redirect
383       onwards to the page originally requested once you're logged in.
384
385       Of course you'll probably want to validate your users against a
386       database table, or maybe via IMAP/LDAP/SSH/POP3/local system accounts
387       via PAM etc.  Authen::Simple is probably a good starting point here!
388
389       A simple working example of handling authentication against a database
390       table yourself (using Dancer::Plugin::Database which provides the
391       "database" keyword, and Crypt::SaltedHash to handle salted hashed
392       passwords (well, you wouldn't store your users' passwords in the clear,
393       would you?)) follows:
394
395           post '/login' => sub {
396               my $user = database->quick_select('users',
397                   { username => params->{user} }
398               );
399               if (!$user) {
400                   warning "Failed login for unrecognised user " . params->{user};
401                   redirect '/login?failed=1';
402               } else {
403                   if (Crypt::SaltedHash->validate($user->{password}, params->{pass}))
404                   {
405                       debug "Password correct";
406                       # Logged in successfully
407                       session user => $user;
408                       redirect params->{path} || '/';
409                   } else {
410                       debug("Login failed - password incorrect for " . params->{user});
411                       redirect '/login?failed=1';
412                   }
413               }
414           };
415
416       Retrieve complete hash stored in session
417
418       Get complete hash stored in session:
419
420           my $hash = session;
421

APPEARANCE

423   Using templates - views and layouts
424       Returning plain content is all well and good for examples or trivial
425       apps, but soon you'll want to use templates to maintain separation
426       between your code and your content.  Dancer makes this easy.
427
428       Your route handlers can use the template keyword to render templates.
429
430       Views
431
432       It's possible to render the action's content with a template, this is
433       called a view. The `appdir/views' directory is the place where views
434       are located.
435
436       You can change this location by changing the setting 'views'.
437
438       By default, the internal template engine Dancer::Template::Simple is
439       used, but you may want to upgrade to Template::Toolkit. If you do so,
440       you have to enable this engine in your settings as explained in
441       Dancer::Template::TemplateToolkit.  If you do so, you'll also have to
442       import the Template module in your application code.
443
444       Note that, by default, Dancer configures the Template::Toolkit engine
445       to use "<% %"> brackets instead of its default "[% %]" brackets.  You
446       can change this by using the following in your config file:
447
448           template: template_toolkit
449
450           engines:
451               template_toolkit:
452                   start_tag: '[%'
453                   stop_tag: '%]'
454
455       All views must have a '.tt' extension. This may change in the future.
456
457       To render a view just call the "template|Dancer/template" keyword at
458       the end of the action by giving the view name and the HASHREF of tokens
459       to interpolate in the view (note that for convenience, the request,
460       session, params and vars are automatically accessible in the view,
461       named "request", "session", "params" and "vars"). For example:
462
463           hook 'before' => sub { var time => scalar(localtime) };
464
465           get '/hello/:name' => sub {
466               my $name = params->{name};
467               template 'hello.tt', { name => $name };
468           };
469
470       The template 'hello.tt' could contain, for example:
471
472           <p>Hi there, <% name %>!</p>
473           <p>You're using <% request.user_agent %></p>
474           <% IF session.username %>
475               <p>You're logged in as <% session.username %>
476           <% END %>
477           It's currently <% vars.time %>
478
479       For a full list of the tokens automatically added to your template
480       (like "session", "request" and "vars", refer to
481       Dancer::Template::Abstract).
482
483       Layouts
484
485       A layout is a special view, located in the 'layouts' directory (inside
486       the views directory) which must have a token named 'content'. That
487       token marks the place to render the action view. This lets you define a
488       global layout for your actions, and have each individual view contain
489       only the specific content.  This is a good thing to avoid lots of
490       needless duplication of HTML :)
491
492       Here is an example of a layout: "views/layouts/main.tt" :
493
494           <html>
495               <head>...</head>
496               <body>
497               <div id="header">
498               ...
499               </div>
500
501               <div id="content">
502               <% content %>
503               </div>
504
505               </body>
506           </html>
507
508       You can tell your app which layout to use with "layout: name" in the
509       config file, or within your code:
510
511           set layout => 'main';
512
513       You can control which layout to use (or whether to use a layout at all)
514       for a specific request without altering the layout setting by passing
515       an options hashref as the third param to the template keyword:
516
517           template 'index.tt', {}, { layout => undef };
518
519       If your application is not mounted under root (/), you can use a
520       before_template_render hook instead of hardcoding the path to your
521       application for your css, images and javascript:
522
523           hook 'before_template_render' => sub {
524               my $tokens = shift;
525               $tokens->{uri_base} = request->base->path;
526           };
527
528       Then in your layout, modify your css inclusion as follows:
529
530           <link rel="stylesheet" href="<% uri_base %>/css/style.css" />
531
532       From now on, you can mount your application wherever you want, without
533       any further modification of the css inclusion
534
535       template and unicode
536
537       If you use Plack and have some unicode problem with your Dancer
538       application, don't forget to check if you have set your template engine
539       to use unicode, and set the default charset to UTF-8. So, if you are
540       using template toolkit, your config.yml will look like this:
541
542           charset: UTF-8
543           engines:
544             template_toolkit:
545               ENCODING: utf8
546
547       TT's WRAPPER directive in Dancer (META variables, SETs)
548
549       Dancer already provides a WRAPPER-like ability, which we call a
550       "layout". The reason we do not use TT's WRAPPER (which also makes it
551       incompatible with Dancer) is because not all template systems support
552       it. Actually, most don't.
553
554       However, you might want to use it, and be able to define META variables
555       and regular Template::Toolkit variables.
556
557       These few steps will get you there:
558
559       ·   Disable the layout in Dancer
560
561           You can do this by simply commenting (or removing) the "layout"
562           configuration in the config.yml file.
563
564       ·   Use Template Toolkit template engine
565
566           Change the configuration of the template to Template Toolkit:
567
568               # in config.yml
569               template: "template_toolkit"
570
571       ·   Tell the Template Toolkit engine who's your wrapper
572
573               # in config.yml
574               # ...
575               engines:
576                   template_toolkit:
577                       WRAPPER: layouts/main.tt
578
579       Done! Everything will work fine out of the box, including variables and
580       META variables.
581

SETTING THE STAGE: CONFIGURATION AND LOGGING

583   Configuration and environments
584       Configuring a Dancer application can be done in many ways. The easiest
585       one (and maybe the dirtiest) is to put all your settings statements at
586       the top of your script, before calling the dance() method.
587
588       Other ways are possible. You can define all your settings in the file
589       `appdir/config.yml'. For this, you must have installed the YAML module,
590       and of course, write the config file in YAML.
591
592       That's better than the first option, but it's still not perfect as you
593       can't switch easily from one environment to another without rewriting
594       the config.yml file.
595
596       The better way is to have one config.yml file with default global
597       settings, like the following:
598
599           # appdir/config.yml
600           logger: 'file'
601           layout: 'main'
602
603       And then write as many environment files as you like in
604       "appdir/environments".  That way the appropriate environment config
605       file will be loaded according to the running environment (if none is
606       specified, it will be 'development').
607
608       Note that you can change the running environment using the
609       "--environment" command line switch.
610
611       Typically, you'll want to set the following values in a development
612       config file:
613
614           # appdir/environments/development.yml
615           log: 'debug'
616           startup_info: 1
617           show_errors:  1
618
619       And in a production one:
620
621           # appdir/environments/production.yml
622           log: 'warning'
623           startup_info: 0
624           show_errors:  0
625
626   Accessing configuration information from your app
627       A Dancer application can use the 'config' keyword to easily access the
628       settings within its config file, for instance:
629
630           get '/appname' => sub {
631               return "This is " . config->{appname};
632           };
633
634       This makes keeping your application's settings all in one place simple
635       and easy.  You shouldn't need to worry about implementing all that
636       yourself :)
637
638   Accessing configuration information from a separate script
639       You may well want to access your webapp's configuration from outside
640       your webapp. You could, of course, use the YAML module of your choice
641       and load your webapps's config.yml, but chances are that this is not
642       convenient.
643
644       Use Dancer instead. Without any ado, magic or too big jumps, you can
645       use the values from config.yml and some additional default values:
646
647               # bin/script1.pl
648               use Dancer ':script';
649               print "template:".config->{template}."\n"; #simple
650               print "log:".config->{log}."\n"; #undef
651
652       Note that config->{log} should result in an undef error on a default
653       scaffold since you did not load the environment and in the default
654       scaffold log is defined in the environment and not in config.yml. Hence
655       undef.
656
657       If you want to load an environment you need to tell Dancer where to
658       look for it.  One way to do so, is to tell Dancer where the webapp
659       lives. From there Dancer deduces where the config.yml file is
660       (typically $webapp/config.yml).
661
662               # bin/script2.pl
663               use FindBin;
664               use Cwd qw/realpath/;
665               use Dancer ':script';
666
667               #tell the Dancer where the app lives
668               my $appdir=realpath( "$FindBin::Bin/..");
669
670               Dancer::Config::setting('appdir',$appdir);
671               Dancer::Config::load();
672
673               #getter
674               print "environment:".config->{environment}."\n"; #development
675               print "log:".config->{log}."\n"; #value from development environment
676
677       By default Dancer loads development environment (typically
678       $webapp/environment/development.yml). In contrast to the example
679       before, you do have a value from the development environment
680       (environment/development.yml) now. Also note that in the above example
681       Cwd and FindBin are used. They are likely to be already loaded by
682       Dancer anyways, so it's not a big overhead. You could just as well hand
683       over a simple path for the app if you like that better, e.g.:
684
685               Dancer::Config::setting('appdir','/path/to/app/dir');
686
687       If you want to load an environment other than the default, try this:
688
689               # bin/script2.pl
690               use Dancer ':script';
691
692               #tell the Dancer where the app lives
693               Dancer::Config::setting('appdir','/path/to/app/dir');
694
695               #which environment to load
696               config->{environment}='production';
697
698               Dancer::Config::load();
699
700               #getter
701               print "log:".config->{log}."\n"; #has value from production environment
702
703       By the way, you not only get values, you can also set values
704       straightforward like we do above with
705       config->{environment}='production'. Of course, this value does not get
706       written in any file; it only lives in memory and your webapp doesn't
707       have access to it, but you can use it inside your script.
708
709       If you don't want to make your script environment-specific, or add
710       extra arguments to it, you can also set the environment using a shell
711       variable, DANCER_ENVIRONMENT.  See also
712       "DANCER_CONFDIR-and-DANCER_ENVDIR" in Dancer::Config
713
714   Logging
715       Configuring logging
716
717       It's possible to log messages generated by the application and by
718       Dancer itself.
719
720       To start logging, select the logging engine you wish to use with the
721       "logger" setting; Dancer includes built-in log engines named "file" and
722       "console", which log to a logfile and to the console respectively.
723
724       To enable logging to a file, add the following to your config.yml:
725
726           logger: 'file'
727
728       Then you can choose which kind of messages you want to actually log:
729
730           log: 'core'      # will log all messages, including messages from
731                            # Dancer itself
732           log: 'debug'     # will log debug, info, warning and error messages
733           log: 'info'      # will log info, warning and error messages
734           log: 'warning'   # will log warning and error messages
735           log: 'error'     # will log error messages
736
737       If you're using the "file" logging engine, a directory "appdir/logs"
738       will be created and will host one logfile per environment. The log
739       message contains the time it was written, the PID of the current
740       process, the message and the caller information (file and line).
741
742       Logging your own messages
743
744       Just call  debug, warning, error or info with your message:
745
746           debug "This is a debug message from my app.";
747

RESTING

749   Writing a REST application
750       With Dancer, it's easy to write REST applications. Dancer provides
751       helpers to serialize and deserialize for the following data formats:
752
753       JSON
754       YAML
755       XML
756       Data::Dumper
757
758       To activate this feature, you only have to set the "serializer" setting
759       to the format you require, for instance in your config.yml:
760
761          serializer: JSON
762
763       Or right in your code:
764
765          set serializer => 'JSON';
766
767       From now, all HashRefs or ArrayRefs returned by a route will be
768       serialized to the format you chose, and all data received from POST or
769       PUT requests will be automatically deserialized.
770
771           get '/hello/:name' => sub {
772               # this structure will be returned to the client as
773               # {"name":"$name"}
774               return {name => params->{name}};
775           };
776
777       It's possible to let the client choose which serializer he wants to
778       use. For this, use the mutable serializer, and an appropriate
779       serializer will be chosen from the Content-Type header.
780
781       It's also possible to return a custom error, using the send_error
782       keyword..  When you don't use a serializer, the "send_error" function
783       will take a string as the first parameter (the message), and an
784       optional HTTP code. When using a serializer, the message can be a
785       string, an ArrayRef or a HashRef:
786
787           get '/hello/:name' => sub {
788               if (...) {
789                  send_error("you can't do that");
790                  # or
791                  send_error({reason => 'access denied', message => "no"});
792               }
793           };
794
795       The content of the error will be serialized using the appropriate
796       serializer.
797
798   Deploying your Dancer applications
799       For examples on deploying your Dancer applications including
800       standalone, behind proxy/load-balancing software, and using common web
801       servers including Apache to run via CGI/FastCGI etc, see
802       Dancer::Deployment.
803

DANCER ON THE STAGE: DEPLOYMENT

805   Plack middlewares
806       If you deploy with Plack and use some Plack middlewares, you can enable
807       them directly from Dancer's configuration files.
808
809       Generic middlewares
810
811       To enable middlewares in Dancer, you just have to set the
812       plack_middlewares setting like the following:
813
814           set plack_middlewares => [
815               [ 'SomeMiddleware' => qw(some options for somemiddleware) ],
816           ];
817
818       For instance, if you want to enable Plack::Middleware::Debug in your
819       Dancer application, all you have to do is to set "plack_middlewares"
820       like that:
821
822           set plack_middlewares => [
823               [ 'Debug' => ( 'panels' => [qw(DBITrace Memory Timer)] ) ],
824           ];
825
826       Of course, you can also put this configuration into your config.yml
827       file, or even in your environment configuration files:
828
829           # environments/development.yml
830           ...
831           plack_middlewares:
832             -
833               - Debug          # first element of the array is the name of the middleware
834               - panels         # following elements are the configuration of the middleware
835               -
836                   - DBITrace
837                   - Memory
838                   - Timer
839
840       Path-based middlewares
841
842       If you want to set up a middleware for a specific path, you can do that
843       using "plack_middlewares_map". You'll need Plack::App::URLMap to do
844       that.
845
846           plack_middlewares_map:
847               '/':      ['Debug']
848               '/timer': ['Timer'],
849

DEVELOPMENT TOOLS

851   Auto-reloading code
852       When you are furiously hacking on your Dancer app, it might come in
853       handy to have the application auto-detect changes in the code and
854       reload itself.
855
856       To do that, you can use Plack::Loader::Shotgun,
857       Plack::Middleware::Refresh, or plackup with the "-r" switch:
858
859          plackup -r bin/appl.pl  (will restart the app whenever a file in ./bin or ./lib is modified
860

AUTHOR

862       Dancer Core Developers
863
865       This software is copyright (c) 2010 by Alexis Sukrieh.
866
867       This is free software; you can redistribute it and/or modify it under
868       the same terms as the Perl 5 programming language system itself.
869
870
871
872perl v5.30.0                      2019-07-26               Dancer::Cookbook(3)
Impressum