1# PODNAME: Dancer::Cookbook 2# ABSTRACT: a quick-start guide to the Dancer web framework 3 4__END__ 5 6=pod 7 8=encoding UTF-8 9 10=head1 NAME 11 12Dancer::Cookbook - a quick-start guide to the Dancer web framework 13 14=head1 VERSION 15 16version 1.3513 17 18=head1 DESCRIPTION 19 20A quick-start guide with examples to get you up and running with the Dancer web 21framework. 22 23=head1 BEGINNER'S DANCE 24 25=head2 Your first Dancer web app 26 27Dancer has been designed to be easy to work with. It's trivial to write a 28simple web app, but still has the power to work with larger projects. To start 29with, let's make an incredibly simple "Hello World" example: 30 31 #!/usr/bin/perl 32 33 use Dancer; 34 35 get '/hello/:name' => sub { 36 return "Why, hello there " . params->{name}; 37 }; 38 39 dance; 40 41Yes, the above is a fully-functioning web app; running that script will launch 42a webserver listening on the default port (3000). Now you can make a request 43 44 $ curl http://localhost:3000/hello/Bob 45 Why, hello there Bob 46 47(or the name of the machine you ran it on, if it's not your local system), 48and it will say hello. The C<:name> part is a named parameter within the 49route specification whose value is made available through C<params> 50- more on that later. 51 52Note that you don't need to use the C<strict> and C<warnings> pragma, they are 53already loaded by Dancer. (If you don't want the C<warnings> pragma (which can 54lead to undesired warnings about use of undef values, for example), then set the 55L<import_warnings|Dancer::Config/import_warnings> setting to a false value. 56 57=head2 Starting a Dancer project 58 59The first simple example is fine for trivial projects, but for anything more 60complex you'll want a more maintainable solution - enter the C<dancer> helper 61script, which will build the framework of your application with a single 62command: 63 64 $ dancer -a mywebapp 65 + mywebapp 66 + mywebapp/bin 67 + mywebapp/bin/app.pl 68 + mywebapp/config.yml 69 + mywebapp/environments 70 + mywebapp/environments/development.yml 71 + mywebapp/environments/production.yml 72 + mywebapp/views 73 + mywebapp/views/index.tt 74 + mywebapp/views/layouts 75 + mywebapp/views/layouts/main.tt 76 + mywebapp/MANIFEST.SKIP 77 + mywebapp/lib 78 + mywebapp/lib/mywebapp.pm 79 + mywebapp/public 80 + mywebapp/public/css 81 + mywebapp/public/css/style.css 82 + mywebapp/public/css/error.css 83 + mywebapp/public/images 84 + mywebapp/public/500.html 85 + mywebapp/public/404.html 86 + mywebapp/public/dispatch.fcgi 87 + mywebapp/public/dispatch.cgi 88 + mywebapp/public/javascripts 89 + mywebapp/public/javascripts/jquery.min.js 90 + mywebapp/t 91 + mywebapp/t/002_index_route.t 92 + mywebapp/t/001_base.t 93 + mywebapp/Makefile.PL 94 95As you can see, it creates a directory named after the name of the app, along 96with a configuration file, a views directory (where your templates and layouts 97will live), an environments directory (where environment-specific settings 98live), a module containing the actual guts of your application, a script to 99start it - or to run your web app via Plack/PSGI - more on that later. 100 101=head1 DANCE ROUTINES: ROUTES 102 103=head2 Declaring routes 104 105To control what happens when a web request is received by your webapp, you'll 106need to declare C<routes>. A route declaration indicates for which HTTP method(s) 107it is valid, the path it matches (e.g. /foo/bar), and a coderef to execute, 108which returns the response. 109 110 get '/hello/:name' => sub { 111 return "Hi there " . params->{name}; 112 }; 113 114The above route specifies that, for GET requests to '/hello/...', the code block 115provided should be executed. 116 117=head2 Handling multiple HTTP request methods 118 119Routes can use C<any> to match all, or a specified list of HTTP methods. 120 121The following will match any HTTP request to the path /myaction: 122 123 any '/myaction' => sub { 124 # code 125 } 126 127The following will match GET or POST requests to /myaction: 128 129 any ['get', 'post'] => '/myaction' => sub { 130 # code 131 }; 132 133For convenience, any route which matches GET requests will also match HEAD 134requests. 135 136=head2 Retrieving request parameters 137 138The L<params|Dancer/params> keyword returns a hashref of request parameters; 139these will be parameters supplied on the query string, within the path itself 140(with named placeholders), and, for HTTP POST requests, the content of the 141POST body. 142 143=head2 Named parameters in route path declarations 144 145As seen above, you can use C<:somename> in a route's path to capture part of the 146path; this will become available by calling L<params|Dancer/params>. 147 148So, for a web app where you want to display information on a company, you might 149use something like: 150 151 get '/company/view/:companyid' => sub { 152 my $company_id = params->{companyid}; 153 # Look up the company and return appropriate page 154 }; 155 156=head2 Wildcard path matching and splat 157 158You can also declare wildcards in a path, and retrieve the values they matched 159with the L<splat|Dancer/splat> keyword: 160 161 get '/*/*' => sub { 162 my ($action, $id) = splat; 163 if (my $action eq 'view') { 164 return display_item($id); 165 } elsif ($action eq 'delete') { 166 return delete_item($id); 167 } else { 168 status 'not_found'; 169 return "What?"; 170 } 171 }; 172 173=head2 Before hooks - processed before a request 174 175A before L<hook|Dancer/hook> declares code which should be handled before 176a request is passed to the appropriate route. 177 178 hook 'before' => sub { 179 var note => 'Hi there'; 180 request->path_info('/foo/oversee') 181 }; 182 183 get '/foo/*' => sub { 184 my ($match) = splat; # 'oversee'; 185 vars->{note}; # 'Hi there' 186 }; 187 188The above declares a before hook which uses C<var> to set a variable which 189will later be available within the route handler, then amends the path of the 190request to C</foo/oversee>; this means that, whatever path was requested, it 191will be treated as though the path requested was C</foo/oversee>. 192 193=head2 Default route 194 195In case you want to avoid a I<404 error>, or handle multiple routes in the same 196way and you don't feel like configuring all of them, you can set up a default 197route handler. 198 199The default route handler will handle any request that doesn't get served by 200any other route. 201 202All you need to do is set up the following route as the B<last> route: 203 204 any qr{.*} => sub { 205 status 'not_found'; 206 template 'special_404', { path => request->path }; 207 }; 208 209Then you can set up the template as such: 210 211 You tried to reach <% path %>, but it is unavailable at the moment. 212 213 Please try again or contact us at our email at <...>. 214 215=head2 Using the auto_page feature for automatic route creation 216 217For simple "static" pages, you can simply enable the C<auto_page> config 218setting; this means that you need not declare a route handler for those pages; 219if a request is for C</foo/bar>, Dancer will check for a matching view (e.g. 220C</foo/bar.tt> and render it with the default layout etc if found. For full 221details, see the documentation for the 222L<auto_page setting|Dancer::Config/"auto_page">. 223 224=head2 Why should I use the Ajax plugin 225 226As an Ajax query is just an HTTP query, it's similar to a GET or POST 227route. You may ask yourself why you may want to use the C<ajax> 228keyword (from the L<Dancer::Plugin::Ajax> plugin) instead of a simple 229C<get>. 230 231Let's say you have a path like '/user/:user' in your application. You 232may want to be able to serve this page, with a layout and HTML 233content. But you may also want to be able to call this same url from a 234javascript query using Ajax. 235 236So, instead of having the following code: 237 238 get '/user/:user' => sub { 239 if (request->is_ajax) { 240 # create xml, set headers to text/xml, blablabla 241 header('Content-Type' => 'text/xml'); 242 header('Cache-Control' => 'no-store, no-cache, must-revalidate'); 243 to_xml({...}) 244 }else{ 245 template users, {....} 246 } 247 }; 248 249you can have 250 251 get '/user/:user' => sub { 252 template users, {...} 253 } 254 255and 256 257 ajax '/user/:user' => sub { 258 to_xml({...}, RootName => undef); 259 } 260 261Because it's an Ajax query you know you need to return XML content, 262so the content type of the response is set for you. 263 264=head2 Using the prefix feature to split your application 265 266For better maintainability you may want to separate some of your application 267components to different packages. Let's say we have a simple web app with an 268admin section, and want to maintain this in a different package: 269 270 package myapp; 271 use Dancer ':syntax'; 272 use myapp::admin; 273 274 prefix undef; 275 276 get '/' => sub {...}; 277 278 1; 279 280 package myapp::admin; 281 use Dancer ':syntax'; 282 283 prefix '/admin'; 284 285 get '/' => sub {...}; 286 287 1; 288 289The following routes will be generated for us: 290 291 - get / 292 - get /admin/ 293 - head / 294 - head /admin/ 295 296=head1 MUSCLE MEMORY: STORING DATA 297 298=head2 Handling sessions 299 300It's common to want to use sessions to give your web applications state; for 301instance, allowing a user to log in, creating a session, and checking that 302session on subsequent requests. 303 304To make use of sessions you must first enable the session engine. Pick the 305session engine you want to use, then declare it in your config file: 306 307 session: Simple 308 309The L<Dancer::Session::Simple> backend implements very simple in-memory session 310storage. This will be fast and useful for testing, but sessions do not persist 311between restarts of your app. 312 313You can also use the L<Dancer::Session::YAML> backend included with Dancer, 314which stores session data on disc in YAML files (since YAML is a nice 315human-readable format, it makes inspecting the contents of sessions a breeze): 316 317 session: YAML 318 319Or, to enable session support from within your code, 320 321 set session => 'YAML'; 322 323(Controlling settings is best done from your config file, though). 'YAML' in 324the example is the session backend to use; this is shorthand for 325L<Dancer::Session::YAML>. There are other session backends you may wish to use, 326for instance L<Dancer::Session::Memcache>, but the YAML backend is a simple and 327easy to use example which stores session data in a YAML file in sessions). 328 329You can then use the L<session|Dancer/session> keyword to manipulate the 330session: 331 332=head3 Storing data in the session 333 334Storing data in the session is as easy as: 335 336 session varname => 'value'; 337 338=head3 Retrieving data from the session 339 340Retrieving data from the session is as easy as: 341 342 session('varname') 343 344Or, alternatively, 345 346 session->{varname} 347 348=head3 Controlling where sessions are stored 349 350For disc-based session back ends like L<Dancer::Session::YAML>, 351L<Dancer::Session::Storable> etc, session files are written to the session dir 352specified by the C<session_dir> setting, which defaults to C<appdir/sessions>. 353 354If you need to control where session files are created, you can do so quickly 355and easily within your config file. For example: 356 357 session_dir: /tmp/dancer-sessions 358 359If the directory you specify does not exist, Dancer will attempt to create it 360for you. 361 362=head3 Destroying a session 363 364When you're done with your session, you can destroy it: 365 366 session->destroy 367 368=head2 Sessions and logging in 369 370A common requirement is to check the user is logged in, and, if not, require 371them to log in before continuing. 372 373This can easily be handled with a before L<hook|Dancer/hook> to check their session: 374 375 hook 'before' => sub { 376 if (! session('user') && request->path_info !~ m{^/login}) { 377 var requested_path => request->path_info; 378 request->path_info('/login'); 379 } 380 }; 381 382 get '/login' => sub { 383 # Display a login page; the original URL they requested is available as 384 # vars->{requested_path}, so could be put in a hidden field in the form 385 template 'login', { path => vars->{requested_path} }; 386 }; 387 388 post '/login' => sub { 389 # Validate the username and password they supplied 390 if (params->{user} eq 'bob' && params->{pass} eq 'letmein') { 391 session user => params->{user}; 392 redirect params->{path} || '/'; 393 } else { 394 redirect '/login?failed=1'; 395 } 396 }; 397 398In your login page template, you'll want a text field named user, a password 399field named pass, and a hidden field named path, which will be populated with 400the path originally requested, so that it's sent back in the POST submission, 401and can be used by the post route to redirect onwards to the page originally 402requested once you're logged in. 403 404Of course you'll probably want to validate your users against a database table, 405or maybe via IMAP/LDAP/SSH/POP3/local system accounts via PAM etc. 406L<Authen::Simple> is probably a good starting point here! 407 408A simple working example of handling authentication against a database table 409yourself (using L<Dancer::Plugin::Database> which provides the C<database> 410keyword, and L<Crypt::SaltedHash> to handle salted hashed passwords (well, you 411wouldn't store your users' passwords in the clear, would you?)) follows: 412 413 post '/login' => sub { 414 my $user = database->quick_select('users', 415 { username => params->{user} } 416 ); 417 if (!$user) { 418 warning "Failed login for unrecognised user " . params->{user}; 419 redirect '/login?failed=1'; 420 } else { 421 if (Crypt::SaltedHash->validate($user->{password}, params->{pass})) 422 { 423 debug "Password correct"; 424 # Logged in successfully 425 session user => $user; 426 redirect params->{path} || '/'; 427 } else { 428 debug("Login failed - password incorrect for " . params->{user}); 429 redirect '/login?failed=1'; 430 } 431 } 432 }; 433 434=head3 Retrieve complete hash stored in session 435 436Get complete hash stored in session: 437 438 my $hash = session; 439 440=head1 APPEARANCE 441 442=head2 Using templates - views and layouts 443 444Returning plain content is all well and good for examples or trivial apps, but 445soon you'll want to use templates to maintain separation between your code and 446your content. Dancer makes this easy. 447 448Your route handlers can use the L<template|Dancer/template> keyword to render 449templates. 450 451=head3 Views 452 453It's possible to render the action's content with a template, this is called a 454view. The `appdir/views' directory is the place where views are located. 455 456You can change this location by changing the setting 'views'. 457 458By default, the internal template engine L<Dancer::Template::Simple> is used, 459but you may want to upgrade to Template::Toolkit. If you do so, you have to 460enable this engine in your settings as explained in 461L<Dancer::Template::TemplateToolkit>. If you do so, you'll also have to 462import the L<Template> module in your application code. 463 464Note that, by default, Dancer configures the Template::Toolkit engine to use 465C<<% %>> brackets instead of its default C<[% %]> brackets. You can change this 466by using the following in your config file: 467 468 template: template_toolkit 469 470 engines: 471 template_toolkit: 472 start_tag: '[%' 473 stop_tag: '%]' 474 475All views must have a '.tt' extension. This may change in the future. 476 477To render a view just call the C<template|Dancer/template> keyword at 478the end of the action by giving the view name and the HASHREF of tokens to 479interpolate in the view (note that for convenience, the request, session, params 480and vars are automatically accessible in the view, named C<request>, C<session>, 481C<params> and C<vars>). For example: 482 483 hook 'before' => sub { var time => scalar(localtime) }; 484 485 get '/hello/:name' => sub { 486 my $name = params->{name}; 487 template 'hello.tt', { name => $name }; 488 }; 489 490The template 'hello.tt' could contain, for example: 491 492 <p>Hi there, <% name %>!</p> 493 <p>You're using <% request.user_agent %></p> 494 <% IF session.username %> 495 <p>You're logged in as <% session.username %> 496 <% END %> 497 It's currently <% vars.time %> 498 499For a full list of the tokens automatically added to your template 500(like C<session>, C<request> and C<vars>, refer to 501L<Dancer::Template::Abstract>). 502 503=head3 Layouts 504 505A layout is a special view, located in the 'layouts' directory (inside the views 506directory) which must have a token named 'content'. That token marks the place 507to render the action view. This lets you define a global layout for your 508actions, and have each individual view contain only the specific content. This 509is a good thing to avoid lots of needless duplication of HTML :) 510 511Here is an example of a layout: C<views/layouts/main.tt> : 512 513 <html> 514 <head>...</head> 515 <body> 516 <div id="header"> 517 ... 518 </div> 519 520 <div id="content"> 521 <% content %> 522 </div> 523 524 </body> 525 </html> 526 527You can tell your app which layout to use with C<layout: name> in the config 528file, or within your code: 529 530 set layout => 'main'; 531 532You can control which layout to use (or whether to use a layout at all) for a 533specific request without altering the layout setting by passing an options 534hashref as the third param to the template keyword: 535 536 template 'index.tt', {}, { layout => undef }; 537 538If your application is not mounted under root (B</>), you can use a 539before_template_render hook instead of hardcoding the path to your 540application for your css, images and javascript: 541 542 hook 'before_template_render' => sub { 543 my $tokens = shift; 544 $tokens->{uri_base} = request->base->path; 545 }; 546 547Then in your layout, modify your css inclusion as follows: 548 549 <link rel="stylesheet" href="<% uri_base %>/css/style.css" /> 550 551From now on, you can mount your application wherever you want, without 552any further modification of the css inclusion 553 554=head3 template and unicode 555 556If you use L<Plack> and have some unicode problem with your Dancer application, 557don't forget to check if you have set your template engine to use unicode, and 558set the default charset to UTF-8. So, if you are using template toolkit, your 559config.yml will look like this: 560 561 charset: UTF-8 562 engines: 563 template_toolkit: 564 ENCODING: utf8 565 566=head3 TT's WRAPPER directive in Dancer (META variables, SETs) 567 568Dancer already provides a WRAPPER-like ability, which we call a "layout". The 569reason we do not use TT's WRAPPER (which also makes it incompatible with Dancer) is 570because not all template systems support it. Actually, most don't. 571 572However, you might want to use it, and be able to define META variables and 573regular L<Template::Toolkit> variables. 574 575These few steps will get you there: 576 577=over 4 578 579=item * Disable the layout in Dancer 580 581You can do this by simply commenting (or removing) the C<layout> configuration 582in the F<config.yml> file. 583 584=item * Use Template Toolkit template engine 585 586Change the configuration of the template to Template Toolkit: 587 588 # in config.yml 589 template: "template_toolkit" 590 591=item * Tell the Template Toolkit engine who's your wrapper 592 593 # in config.yml 594 # ... 595 engines: 596 template_toolkit: 597 WRAPPER: layouts/main.tt 598 599=back 600 601Done! Everything will work fine out of the box, including variables and META 602variables. 603 604=head1 SETTING THE STAGE: CONFIGURATION AND LOGGING 605 606=head2 Configuration and environments 607 608Configuring a Dancer application can be done in many ways. The easiest one (and 609maybe the dirtiest) is to put all your settings statements at the top of 610your script, before calling the dance() method. 611 612Other ways are possible. You can define all your settings in the file 613`appdir/config.yml'. For this, you must have installed the YAML module, and of 614course, write the config file in YAML. 615 616That's better than the first option, but it's still not perfect as you can't 617switch easily from one environment to another without rewriting the config.yml 618file. 619 620The better way is to have one config.yml file with default global settings, 621like the following: 622 623 # appdir/config.yml 624 logger: 'file' 625 layout: 'main' 626 627And then write as many environment files as you like in C<appdir/environments>. 628That way the appropriate environment config file will be loaded according to 629the running environment (if none is specified, it will be 'development'). 630 631Note that you can change the running environment using the C<--environment> 632command line switch. 633 634Typically, you'll want to set the following values in a development config file: 635 636 # appdir/environments/development.yml 637 log: 'debug' 638 startup_info: 1 639 show_errors: 1 640 641And in a production one: 642 643 # appdir/environments/production.yml 644 log: 'warning' 645 startup_info: 0 646 show_errors: 0 647 648=head2 Accessing configuration information from your app 649 650A Dancer application can use the 'config' keyword to easily access the settings 651within its config file, for instance: 652 653 get '/appname' => sub { 654 return "This is " . config->{appname}; 655 }; 656 657This makes keeping your application's settings all in one place simple and easy. 658You shouldn't need to worry about implementing all that yourself :) 659 660=head2 Accessing configuration information from a separate script 661 662You may well want to access your webapp's configuration from outside your 663webapp. You could, of course, use the YAML module of your choice and load your 664webapps's config.yml, but chances are that this is not convenient. 665 666Use Dancer instead. Without any ado, magic or too big jumps, you can use the 667values from config.yml and some additional default values: 668 669 # bin/script1.pl 670 use Dancer ':script'; 671 print "template:".config->{template}."\n"; #simple 672 print "log:".config->{log}."\n"; #undef 673 674Note that config->{log} should result in an undef error on a default scaffold since 675you did not load the environment and in the default scaffold log is defined in 676the environment and not in config.yml. Hence undef. 677 678If you want to load an environment you need to tell Dancer where to look for it. 679One way to do so, is to tell Dancer where the webapp lives. From there Dancer 680deduces where the config.yml file is (typically $webapp/config.yml). 681 682 # bin/script2.pl 683 use FindBin; 684 use Cwd qw/realpath/; 685 use Dancer ':script'; 686 687 #tell the Dancer where the app lives 688 my $appdir=realpath( "$FindBin::Bin/.."); 689 690 Dancer::Config::setting('appdir',$appdir); 691 Dancer::Config::load(); 692 693 #getter 694 print "environment:".config->{environment}."\n"; #development 695 print "log:".config->{log}."\n"; #value from development environment 696 697By default Dancer loads development environment (typically 698$webapp/environment/development.yml). In contrast to the example before, you 699do have a value from the development environment (environment/development.yml) 700now. Also note that in the above example Cwd and FindBin are used. They are 701likely to be already loaded by Dancer anyways, so it's not a big overhead. You 702could just as well hand over a simple path for the app if you like that better, 703e.g.: 704 705 Dancer::Config::setting('appdir','/path/to/app/dir'); 706 707If you want to load an environment other than the default, try this: 708 709 # bin/script2.pl 710 use Dancer ':script'; 711 712 #tell the Dancer where the app lives 713 Dancer::Config::setting('appdir','/path/to/app/dir'); 714 715 #which environment to load 716 config->{environment}='production'; 717 718 Dancer::Config::load(); 719 720 #getter 721 print "log:".config->{log}."\n"; #has value from production environment 722 723By the way, you not only get values, you can also set values straightforward 724like we do above with config->{environment}='production'. Of course, this value 725does not get written in any file; it only lives in memory and your webapp 726doesn't have access to it, but you can use it inside your script. 727 728If you don't want to make your script environment-specific, or add extra arguments 729to it, you can also set the environment using a shell variable, DANCER_ENVIRONMENT. 730See also L<Dancer::Config/DANCER_CONFDIR-and-DANCER_ENVDIR> 731 732=head2 Logging 733 734=head3 Configuring logging 735 736It's possible to log messages generated by the application and by Dancer itself. 737 738To start logging, select the logging engine you wish to use with the C<logger> 739setting; Dancer includes built-in log engines named C<file> and C<console>, 740which log to a logfile and to the console respectively. 741 742To enable logging to a file, add the following to your config.yml: 743 744 logger: 'file' 745 746Then you can choose which kind of messages you want to actually log: 747 748 log: 'core' # will log all messages, including messages from 749 # Dancer itself 750 log: 'debug' # will log debug, info, warning and error messages 751 log: 'info' # will log info, warning and error messages 752 log: 'warning' # will log warning and error messages 753 log: 'error' # will log error messages 754 755If you're using the C<file> logging engine, a directory C<appdir/logs> will be 756created and will host one logfile per environment. The log message contains the 757time it was written, the PID of the current process, the message and the caller 758information (file and line). 759 760=head3 Logging your own messages 761 762Just call L<debug|Dancer/debug>, L<warning|Dancer/warning>, 763L<error|Dancer/error> or L<info|Dancer/info> with your message: 764 765 debug "This is a debug message from my app."; 766 767=head1 RESTING 768 769=head2 Writing a REST application 770 771With Dancer, it's easy to write REST applications. Dancer provides helpers to 772serialize and deserialize for the following data formats: 773 774=over 4 775 776=item JSON 777 778=item YAML 779 780=item XML 781 782=item Data::Dumper 783 784=back 785 786To activate this feature, you only have to set the C<serializer> setting to the 787format you require, for instance in your config.yml: 788 789 serializer: JSON 790 791Or right in your code: 792 793 set serializer => 'JSON'; 794 795From now, all HashRefs or ArrayRefs returned by a route will be serialized to 796the format you chose, and all data received from B<POST> or B<PUT> requests 797will be automatically deserialized. 798 799 get '/hello/:name' => sub { 800 # this structure will be returned to the client as 801 # {"name":"$name"} 802 return {name => params->{name}}; 803 }; 804 805It's possible to let the client choose which serializer he wants to use. For 806this, use the B<mutable> serializer, and an appropriate serializer will be 807chosen from the B<Content-Type> header. 808 809It's also possible to return a custom error, using the 810L<send_error|Dancer/send_error> keyword.. 811When you don't use a serializer, the C<send_error> function will take a string 812as the first parameter (the message), and an optional HTTP code. When using a 813serializer, the message can be a string, an ArrayRef or a HashRef: 814 815 get '/hello/:name' => sub { 816 if (...) { 817 send_error("you can't do that"); 818 # or 819 send_error({reason => 'access denied', message => "no"}); 820 } 821 }; 822 823The content of the error will be serialized using the appropriate serializer. 824 825=head2 Deploying your Dancer applications 826 827For examples on deploying your Dancer applications including standalone, behind 828proxy/load-balancing software, and using common web servers including Apache to 829run via CGI/FastCGI etc, see L<Dancer::Deployment>. 830 831=head1 DANCER ON THE STAGE: DEPLOYMENT 832 833=head2 Plack middlewares 834 835If you deploy with Plack and use some Plack middlewares, you can enable them 836directly from Dancer's configuration files. 837 838=head3 Generic middlewares 839 840To enable middlewares in Dancer, you just have to set the plack_middlewares 841setting like the following: 842 843 set plack_middlewares => [ 844 [ 'SomeMiddleware' => qw(some options for somemiddleware) ], 845 ]; 846 847For instance, if you want to enable L<Plack::Middleware::Debug> in your Dancer 848application, all you have to do is to set C<plack_middlewares> like that: 849 850 set plack_middlewares => [ 851 [ 'Debug' => ( 'panels' => [qw(DBITrace Memory Timer)] ) ], 852 ]; 853 854Of course, you can also put this configuration into your config.yml file, or 855even in your environment configuration files: 856 857 # environments/development.yml 858 ... 859 plack_middlewares: 860 - 861 - Debug # first element of the array is the name of the middleware 862 - panels # following elements are the configuration of the middleware 863 - 864 - DBITrace 865 - Memory 866 - Timer 867 868=head3 Path-based middlewares 869 870If you want to set up a middleware for a specific path, you can do that using 871C<plack_middlewares_map>. You'll need L<Plack::App::URLMap> to do that. 872 873 plack_middlewares_map: 874 '/': ['Debug'] 875 '/timer': ['Timer'], 876 877=head1 DEVELOPMENT TOOLS 878 879=head2 Auto-reloading code 880 881When you are furiously hacking on your Dancer app, it might come in handy to 882have the application auto-detect changes in the code and reload itself. 883 884To do that, you can use L<Plack::Loader::Shotgun>, L<Plack::Middleware::Refresh>, 885or plackup with the C<-r> switch: 886 887 plackup -r bin/appl.pl (will restart the app whenever a file in ./bin or ./lib is modified 888 889=head1 AUTHOR 890 891Dancer Core Developers 892 893=head1 COPYRIGHT AND LICENSE 894 895This software is copyright (c) 2010 by Alexis Sukrieh. 896 897This is free software; you can redistribute it and/or modify it under 898the same terms as the Perl 5 programming language system itself. 899 900=cut 901