summaryrefslogtreecommitdiff
path: root/lib/Dancer2/Tutorial.pod
blob: 0d4141dcfd78a5d0c0cb3e9346b60a9b0930623c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
package Dancer2::Tutorial;
# ABSTRACT: An example to get you dancing

__END__

=pod

=encoding UTF-8

=head1 NAME

Dancer2::Tutorial - An example to get you dancing

=head1 VERSION

version 1.0.0

=head1 Tutorial Overview

This tutorial is has three parts. Since they build on one another, each part is
meant to be gone through in sequential order.

B<Part I>, the longest part of this tutorial, will focus on the basics of Dancer2
development by building a simple yet functional blog app, called C<dancr>, that
you can use to impress your friends, mates, and family.

In B<Part II>, you'll learn about the preferred way to get your own web apps up
and running by using the C<dancer2> utility. We will take the script written in
Part I and convert it into a proper Dancer2 app, called C<Dancr2>, to help you
gain an understanding of what the C<dancer2> utility does for you.

Finally, in B<Part III>, we give you a taste of the power of plugins that other
developers have written and will show you how to modify the C<Dancr2> app to use
a database plugin.

This tutorial assumes you have some familiarity with Perl and that you know how
to create and execute a Perl script on your computer. Some experience with web
development is also greatly helpful but not entirely necessary. This tutorial is
mostly geared toward developers but website designers can get something out of
it as well since the basics of templating are covered plus it might be
good for a designer to have a decent idea of how Dancer2 works.

=head1 Part I: Let's Get Dancing!

Part I covers many of the basic concepts you'll need to know to lay a good
foundation for your future development work with Dancer2 by building a simple
micro-blogging app.

=head2 What is Dancer2?

Dancer2 is a micro-web framework, written in the Perl programming language, and is
modeled after a Ruby web application framework called L<Sinatra|http://www.sinatrarb.com>.

When we say "micro" framework, we mean that Dancer2 aims to maximize your freedom
and control by getting out of your way. "Micro" doesn't mean Dancer2
is only good for creating small apps. Instead, it means that Dancer2's primary
focus is on taking care of a lot of the boring, technical details of your app
for you and by creating an easy, clean routing layer on top of your app's
code. It also means you have almost total control over the app's functionality
and how you create and present your content. You will not confined to someone
else's approach to creating a website or app.

With Dancer2, you can build anything from a specialized content management
system to providing a simple API for querying a database over the web. But you
don't have to reinvent the wheel, either. Dancer2 has hundreds of plugins that
you can take advantage of. You can add only the capabilities your app needs to
keep complexity to a minimum.

As a framework, Dancer2 provides you with the tools and infrastructure you can
leverage to deliver content on the web quickly, easily and securely. The tools,
Dancer2 provides, called "keywords," are commands that you use to build your app,
access the data inside of it, and deliver it on the internet in many
different formats.

Dancer2's keywords provide what is called a B<Domain Specific Language> (DSL)
designed specifically for the task of building apps. But don't let the
technical jargon scare you off. Things will become clearer in our first code
example which we will look at shortly.

=head3 Getting Dancer2 installed

First, we need to make sure you have Dancer2 installed. Typically, you will do
that with one of the following two commands:

    cpan Dancer2  # requires the cpan command to be installed and configured
    cpanm Dancer2 # requires you have cpanminus installed

If you aren't familiar with installing Perl modules on your machine, you should
L<read this guide|https://www.cpan.org/modules/INSTALL.html>. You may also want
to consult your OS's documentation or a knowledgeable expert. And, of course,
your search engine of choice is always there for you, as well.

=head3 Your first Dancer2 "Hello World!" app

Now that you have Dancer2 installed, open up your favorite text editor and copy
and paste the following lines of Perl code into it and save it to a file
called C<dancr.pl>:

    #!/usr/bin/env perl
    use Dancer2;

    get '/' => sub {
        return 'Hello World!';
    };

    start;

If you make this script executable and run it, it will fire up a simple,
standalone web server that will display "Hello World!" when you point your
browser to L<http://localhost:3000>. Cool!

B<Important note:> We want to emphasize that writing a script file like
this with a C<start> command is B<not> how you would typically begin writing a
Dancer2 app. Part II of this tutorial will show you the recommended approach
using the C<dancer2> utility. For now, we want to stay focused on the
fundamentals.

So, though our example app is very simple, there is a lot going on under the hood
when we invoke C<use Dancer2;> in our first line of code. We won't go into the
gory details of how it all works. For now, it's enough for you to know that the
Dancer2 module infuses your script with the ability to use Dancer2 keywords for
building apps. Getting comfortable with the concept of keywords is probably the
most important step you can take as a budding Dancer2 developer and this
tutorial will do its best to help foster your understanding of them.

The next line of code in our example (which spans three lines to make it more
readable) is the B<route handler>. Let's examine this line closely, because
route handlers are at the core of how to build an app with Dancer2.

The syntax of a Dancer2 C<route handler> has three parts:

=over

=item *
an B<http method> or B<http verb>; in this example, we use the C<get> keyword
to tell Dancer2 that this route should apply to GET http requests. C<get> is the
first of many keywords that Dancer2 provides that we will cover in this tutorial.
Those familiar with web development will know that a GET request is what we use
to fetch information from a website.

=item *
the B<route pattern>; this is the bit of code that appears immediately after
our C<get> keyword. In this example it is a forward slash (C</>), wrapped in
single quotes, and it represents the pattern we wish to match against the URL
that the browser, or client, has requested. Web developers will immediately
recognize that the forward slash symbolizes the root directory of our website.
Experienced Perl programmers will pick up on the fact that the route pattern is
nothing more than an argument for our C<get> keyword.

=item *
the B<route action>; this is the subroutine that returns our data. More
precisely, it is a subroutine reference. The route action in our example returns
a simple string, C<Hello World!>. Like the route pattern, the route action is
nothing more than an argument to our C<get> keyword.

Note that convention has us use the fat comma (C<< => >>) operator between the
route pattern and the action to to make our code more readable. But we
could just as well have used a regular old comma to separate these argument to
our C<get> method. Gotta love Perl for its flexibility.

=back

So to put our route pattern in the example into plain English, we are telling
our app, "If the root directory is requested with the GET http method, send
the string 'Hello World!' back in our response." Of course, since this is a web
app, we also have to send back headers with our response. This is quitely taken
care of for us by Dancer2 so we don't have to think about it.

The syntax for route handlers might seem a bit foreign for newer Perl developers.
But rest assured there is nothing magical about it and it is all just plain
old Perl under the hood. If you keep in mind that the keyword is a subroutine
(or more precisely, a method) and that the pattern and action are arguments to
the keyword, you'll pick it up in no time. Thinking of these keywords as
"built-ins" to the Dancer2 framework might also eliminate any initial confusion
about them.

The most important takeaway here is that we build our app by adding route
handlers which are nothing more than a collection of, HTTP verbs, URL patterns,
and actions.

=head2 How about a little more involved example?

While investigating some Python web frameworks like L<Flask|http://flask.pocoo.org/>
or L<Bottle|https://bottlepy.org/docs/dev/>, 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. This tutorial is modeled after them.

Using the
L<Flaskr|https://github.com/pallets/flask>
sample application as my inspiration (OK, shamelessly plagiarised) I
translated that application to the Dancer2 framework so I could better
understand how Dancer2 worked. (I'm learning it too!)

So "dancr" was born.

dancr is a simple "micro" blog which uses the
L<SQLite|http://www.sqlite.org> database engine for simplicity's sake.
You'll need to install sqlite on your server if you don't have it
installed already. Consult your OS documentation for getting SQLite
installed on your machine.

=head3 Required Perl modules

Obviously you need L<Dancer2> installed. You'll also need the
L<Template Toolkit|Template>, L<File::Slurper>, and L<DBD::SQLite> modules.
These all can be installed using your CPAN client with the following command:

    cpan Template File::Slurper DBD::SQLite

=head2 The database code

We're not going to spend a lot of time on the database, as it's not really the
point of this particular tutorial. Try not to dwell on this section too much
if you don't understand all of it.

Open your favorite L<text editor|http://www.vim.org> and create a schema
definition called 'schema.sql' with the following content:

    create table if not exists entries (
        id integer primary key autoincrement,
        title string not null,
        text string not null
    );

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.

We want our application to initialize the database automatically for us when
we start it. So, let's edit the 'dancr.pl' file we created earlier and give it
the ability to talk to our database with the following subroutines: (Or, if you
prefer, you can copy and paste the finished dancr.pl script, found near the end
of Part I in this tutorial, into the file all at once and then just follow along
with the tutorial.)

    sub connect_db {
        my $dbh = DBI->connect("dbi:SQLite:dbname=".setting('database'))
            or die $DBI::errstr;

        return $dbh;
    }

    sub init_db {
        my $db     = connect_db();
        my $schema = read_text('./schema.sql');
        $db->do($schema)
            or die $db->errstr;
    }

Nothing too fancy in here, I hope. It's standard DBI except for the
C<setting('database')> thing, more on that in a bit. For now, just assume
that the expression evaluates to the location of the database file.

In Part III of the tutorial, we will show you how to use the
L<Dancer2::Plugin::Database> module for an easier way to configure and manage
database connections for your Dancer2 apps.

=head2 Our first route handler

Ok, let's get back to the business of learning Dancer2 by creating our app's
first route handler for the root URL.  Replace the route handler in our
simple example above with this one:

    get '/' => sub {
        my $db  = connect_db();
        my $sql = 'select id, title, text from entries order by id desc';

        my $sth = $db->prepare($sql)
            or die $db->errstr;

        $sth->execute
            or die $sth->errstr;

        template 'show_entries.tt', {
            msg           => get_flash(),
            add_entry_url => uri_for('/add'),
            entries       => $sth->fetchall_hashref('id'),
        };
    };

Our new route handler is the same as the one in our first example except that
our route action does a lot more work.

Something you might not have noticed right away is the semicolon at the end of
the route handler. This might confuse newer Perl coders and is a source of bugs
for more experienced ones who forget to add it. We need the semicolon there
because we are creating a reference to a subroutine and because that's just what
the Perl compiler demands and we must obey if we want our code to run.

Alright, let's take a closer look at this route's action. The first few lines are
standard DBI. The important bit related to Dancer2 is the C<template> keyword
at the end of the action. That tells Dancer2 to process the output through one
of its templating engines. There are many template engines available for use with
Dancer2. In this tutorial, we're using L<Template Toolkit|Template>
which offers a lot more flexibility than the simple default Dancer2
template engine.

Templates all go into a C<views/> directory which located in the same
directory as our dancr.pl script. 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 F<main.tt>, a little later in
this tutorial.

So 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 C<msg> 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 C</> URL is rendered.

The C<uri_for> directive tells Dancer2 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 hardcode the C</add> URI in our
application or templates.  The best reason B<not> to do that is because it
removes a layer of flexibility as to where to "mount" the web application.
Although the application is coded to use the root URL C</> it might be
better in the future to locate it under its own URL route (maybe C</dancr>?)
- 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
C<uri_for> Dancer2 method, we can easily load the application wherever we
like and not have to modify the application at all.

Finally, the C<entries> 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.

So what does the F<show_entries.tt> template look like? This:

  [% IF session.logged_in %]
    <form action="[% add_entry_url %]" method=post class=add-entry>
      <dl>
        <dt>Title:
        <dd><input type=text size=30 name=title>
        <dt>Text:
        <dd><textarea name=text rows=5 cols=40></textarea>
        <dd><input type=submit value=Share>
      </dl>
    </form>
  [% END %]
  <ul class=entries>
  [% IF entries.size %]
    [% FOREACH id IN entries.keys.nsort %]
      <li><h2>[% entries.$id.title | html %]</h2>[% entries.$id.text | html %]
    [% END %]
  [% ELSE %]
    <li><em>Unbelievable. No entries here so far</em>
  [% END %]
  </ul>

Go ahead and create a C<views/> directory in the same directory as the script
and add this file to it.

Again, since this isn't a tutorial about Template Toolkit, we'll gloss
over the syntax here and just point out the section which starts with
C<< <ul class=entries> >>. 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.

The only other Template Toolkit related thing that has to be mentioned here is
the C<| html> in C<[% entries.$id.title | html %]>. That's
L<a filter|http://www.template-toolkit.org/docs/manual/Filters.html#section_html>
to convert characters like C<< < >> and C<< > >> to C<&lt;> and C<&gt;>. This
way they will be displayed by the browser as content on the page rather than
just included. If we did not do this, the browser might interpret content as
part of the page, and a malicious user could smuggle in all kinds of bad code
that would then run in another user's browser. This is called
L<Cross Site Scripting|https://en.wikipedia.org/wiki/Cross-site_scripting> or
XSS and you should make sure to avoid it by always filtering data that came
in from the web when you display it in a template.

=head2 Other HTTP verbs

There are 8 defined HTTP verbs defined in L<RFC
2616|http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9>: 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.

In addition, the C<PATCH> verb was defined in
L<RFC5789|http://tools.ietf.org/html/rfc5789>, and is intended as a "partial
PUT", sending just the changes required to the entity in question.  How
this would be handled is down to your app, it will vary depending on the
type of entity in question and the serialization in use.

Dancer2's keywords currently supports GET, PUT/PATCH, POST, DELETE, OPTIONS which
map to Retrieve, Update, Create, Delete respectively.  Let's take a look now at
the C</add> route handler which handles a POST operation.

    post '/add' => 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->prepare($sql)
            or die $db->errstr;

        $sth->execute(
            body_parameters->get('title'),
            body_parameters->get('text')
        ) or die $sth->errstr;

        set_flash('New entry posted!');
        redirect '/';
    };

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.

The first check in the subroutine is to make sure the user sending the data
is logged in. If not, the application returns an error and stops
processing. Otherwise, we have standard DBI stuff. Let me insert (heh, heh)
a blatant plug here for always, always using parameterized INSERTs in your
application SQL statements. It's the only way to be sure your application
won't be vulnerable to SQL injection. (See L<http://www.bobby-tables.com>
for correct INSERT examples in multiple languages.) Here we're using the
C<body_parameters> convenience method to pull in the parameters in the current HTTP
request. (You can see the 'title' and 'text' form parameters in the
F<show_entries.tt> 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.

It's worth mentioning that the "flash message" is not part of Dancer2, but a
part of this specific application. We need to implement it ourself.

=head2 Logins and sessions

Dancer2 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. We'll just 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.

=head3 Configuration options

To use sessions in our application, we have to tell Dancer2 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.

    set 'database'        => File::Spec->catfile(File::Spec->tmpdir(), 'dancr.db');
    set 'session'         => 'Simple';
    set 'template'        => 'template_toolkit';
    set 'logger'          => 'console';
    set 'log'             => 'debug';
    set 'show_stacktrace' => 1;
    set 'startup_info'    => 1;

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 and prints a banner at the server start with
information such as versions and the environment.

Dancer2 doesn't impose any limits on what parameters you can set using the
C<set> syntax. For this application we're going to embed our single username
and password into the application itself:

    set 'username' => 'admin';
    set 'password' => 'password';

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.

In Part II of our tutorial, we will show you how to use Dancer2's configuration
files to manage these options and set up different environments for your app
using different configuration files. For now, we're going to keep it simple and
leave that discussion for later.

=head3 Logging in

Now that dancr is configured to handle sessions, let's take a look at the
URL handler for the C</login> route.

    any ['get', 'post'] => '/login' => sub {
        my $err;

        if ( request->method() eq "POST" ) {
            # process form input
            if ( body_parameters->get('username') ne setting('username') ) {
                $err = "Invalid username";
            }
            elsif ( body_parameters->get('password') ne setting('password') ) {
                $err = "Invalid password";
            }
            else {
                session 'logged_in' => true;
                set_flash('You are logged in.');
                return redirect '/';
            }
        }

        # display login form
        template 'login.tt', {
            err => $err,
        };
    };

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> a POST, we drop
down to the C<template> directive and display the F<login.tt> template:

  <h2>Login</h2>
  [% IF err %]<p class=error><strong>Error:</strong> [% err %][% END %]
  <form action="[% login_url %]" method=post>
    <dl>
      <dt>Username:
      <dd><input type=text name=username>
      <dt>Password:
      <dd><input type=password name=password>
      <dd><input type=submit value=Login>
    </dl>
  </form>

This is even simpler than our F<show_entries.tt> template–but wait– there's a
C<login_url> template parameter and we're only passing in the
C<err> parameter. Where's the missing parameter? It's being generated and
sent to the template in a C<before_template_render> directive, we'll come
back to that in a moment or two.

So the user fills out the F<login.tt> template and submits it back to the
C</login> route handler.  We now check the user input against our
application settings and if the input is incorrect, we alert the user, otherwise
the application starts a session and sets the C<logged_in> session parameter
to the C<true()> value. Dancer2 exports both a C<true()> and C<false()>
convenience method which we use here.  After that, it's another flash
message and back to the root URL handler.

=head3 Logging out

And finally, we need a way to clear our user's session with the customary
logout procedure.

    get '/logout' => sub {
        app->destroy_session;
        set_flash('You are logged out.');
        redirect '/';
    };

C<< app->destroy_session; >> is Dancer2'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.

You might wonder how we can then set a value in the session in C<set_flash>,
because we just destroyed the session.

Destroying the session has removed the data from the persistence layer (which
is the memory of our running application, because we are using the C<simple>
session engine). If we write to I<the session> now, it will actually create
a completely new session for our user. This new, empty session will have a new
I<session ID>, which Dancer2 tells the user's browser about in the response.
When the browser requests the root URL, it will send this new session ID to our
application.

=head2 Layout and static files

We still have a missing puzzle piece or two. First, how can we use Dancer2
to serve our CSS stylesheet? Second, where are flash messages displayed?
Third, what about the C<before_template_render> directive?

=head3 Serving static files

In Dancer2, static files should go into the C<public/> directory, but in the
application itself be sure to omit the C<public/> element from the path.  For
example, the stylesheet for dancr lives in C<dancr/public/css/style.css> but
is served from L<http://localhost:3000/css/style.css>.

If you wanted to build a mostly static web site you could simply write route
handlers like this one:

    get '/' => sub {
        send_file 'index.html';
    };

where index.html would live in your C<public/> directory.

C<send_file> does exactly what it says: it loads a static file, then sends
the contents of that file to the user.

Let's go ahead and create our style sheet. In the same directory as your dancr.pl
script, issue the following commands:

    mkdir public && mkdir public/css && touch public/css/style.css

Next add the following css to the C<public/css/style.css> file you just created:

    body            { font-family: sans-serif; background: #eee; }
    a, h1, h2       { color: #377ba8; }
    h1, h2          { font-family: 'Georgia', serif; margin: 0; }
    h1              { border-bottom: 2px solid #eee; }
    h2              { font-size: 1.2em; }

    .page           { margin: 2em auto; width: 35em; border: 5px solid #ccc;
                      padding: 0.8em; background: white; }
    .entries        { list-style: none; margin: 0; padding: 0; }
    .entries li     { margin: 0.8em 1.2em; }
    .entries li h2  { margin-left: -1em; }
    .add-entry      { font-size: 0.9em; border-bottom: 1px solid #ccc; }
    .add-entry dl   { font-weight: bold; }
    .metanav        { text-align: right; font-size: 0.8em; padding: 0.3em;
                      margin-bottom: 1em; background: #fafafa; }
    .flash          { background: #cee5F5; padding: 0.5em;
                      border: 1px solid #aacbe2; }
    .error          { background: #f0d6d6; padding: 0.5em; }

Be sure to save the file.

=head3 Layouts

I mentioned earlier in the tutorial that it is possible to
create a C<layout> template. In dancr, that layout is called C<main> and
it's set up by putting in a directive like this:

    set layout => 'main';

near the top of your web application.  This tells Dancer2's template
engine that it should look for a file called F<main.tt> in
C<views/layouts/> and insert the calls from the C<template> directive
into a template parameter called C<content>.

Here is the simple layout file we will use for this web application. Go ahead
and add this the F<main.tt> file to the C<views/layouts/> directory.

  <!doctype html>
  <html>
  <head>
    <title>dancr</title>
    <link rel=stylesheet type=text/css href="[% css_url %]">
  </head>
  <body>
    <div class=page>
    <h1>dancr</h1>
       <div class=metanav>
       [% IF not session.logged_in %]
         <a href="[% login_url %]">log in</a>
       [% ELSE %]
         <a href="[% logout_url %]">log out</a>
       [% END %]
    </div>
    [% IF msg %]
      <div class=flash> [% msg %] </div>
    [% END %]
    [% content %]
  </div>
  </body>
  </html>

Aha! You now see where the flash message C<msg> 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 C<content> template parameter).

But what about all those other C<*_url> template parameters?

=head3 Using C<before_template_render>

Dancer2 has a way to manipulate the template parameters before they're
passed to the engine for processing. It's C<before_template_render>. Using
this keyword, you can generate and set the URIs for the C</login> and
C</logout> 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.

    hook before_template_render => sub {
        my $tokens = shift;

        $tokens->{'css_url'}    = request->base . 'css/style.css';
        $tokens->{'login_url'}  = uri_for('/login');
        $tokens->{'logout_url'} = uri_for('/logout');
    };

Here again I'm using C<uri_for> 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.

=head2 Putting it all together

Here's the complete 'dancr.pl' script from start to finish.

    use Dancer2;
    use DBI;
    use File::Spec;
    use File::Slurper qw/ read_text /;
    use Template;

    set 'database'        => File::Spec->catfile(File::Spec->tmpdir(), 'dancr.db');
    set 'session'         => 'Simple';
    set 'template'        => 'template_toolkit';
    set 'logger'          => 'console';
    set 'log'             => 'debug';
    set 'show_stacktrace' => 1;
    set 'startup_info'    => 1;
    set 'username'        => 'admin';
    set 'password'        => 'password';
    set 'layout'          => 'main';

    sub set_flash {
        my $message = shift;

        session flash => $message;
    }

    sub get_flash {
        my $msg = session('flash');
        session->delete('flash');

        return $msg;
    }

    sub connect_db {
        my $dbh = DBI->connect("dbi:SQLite:dbname=".setting('database'))
            or die $DBI::errstr;

        return $dbh;
    }

    sub init_db {
        my $db     = connect_db();
        my $schema = read_text('./schema.sql');
        $db->do($schema)
            or die $db->errstr;
    }

    hook before_template_render => sub {
        my $tokens = shift;

        $tokens->{'css_url'}    = request->base . 'css/style.css';
        $tokens->{'login_url'}  = uri_for('/login');
        $tokens->{'logout_url'} = uri_for('/logout');
    };

    get '/' => sub {
        my $db  = connect_db();
        my $sql = 'select id, title, text from entries order by id desc';

        my $sth = $db->prepare($sql)
            or die $db->errstr;

        $sth->execute
            or die $sth->errstr;

        template 'show_entries.tt', {
            msg           => get_flash(),
            add_entry_url => uri_for('/add'),
            entries       => $sth->fetchall_hashref('id'),
        };
    };

    post '/add' => 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->prepare($sql)
            or die $db->errstr;

        $sth->execute(
            body_parameters->get('title'),
            body_parameters->get('text')
        ) or die $sth->errstr;

        set_flash('New entry posted!');
        redirect '/';
    };

    any ['get', 'post'] => '/login' => sub {
        my $err;

        if ( request->method() eq "POST" ) {
            # process form input
            if ( body_parameters->get('username') ne setting('username') ) {
                $err = "Invalid username";
            }
            elsif ( body_parameters->get('password') ne setting('password') ) {
                $err = "Invalid password";
            }
            else {
                session 'logged_in' => true;
                set_flash('You are logged in.');
                return redirect '/';
            }
        }

        # display login form
        template 'login.tt', {
            err => $err,
        };

    };

    get '/logout' => sub {
        app->destroy_session;
        set_flash('You are logged out.');
        redirect '/';
    };

    init_db();
    start;

=head3 Advanced route moves

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 C</hello/:name> where the C<:name> piece magically turns into a named
parameter in your handler for manipulation.

You can explore this and other advanced concepts by reading the L<Dancer2::Manual>.

=head1 Part II: Taking Advantage of the C<dancer2> Utility to Set Up New Apps

In Part I, we took an ordinary Perl script and turned it into a simple web
app to teach you basic Dancer2 concepts. While starting with a simple script
like this helped make it easier to teach these concepts, it did not demonstrate
how a typical app is built by a Dancer2 developer. So let's show you how things
really get done.

=head2 Creating a new app

So now that you have a better idea of what goes into building an app with
Dancer2, it's time to cha-cha with the C<dancer2> utility which will save you a
lot of time and effort by setting up directories, files, and default
configuration settings for you.

The C<dancer2> utility was installed on your machine when you installed the
Dancer2 distribution. Hop over to the command line into a directory you have
permission to write to and issue the following command:

    dancer2 gen -a Dancr2

That command should output something like the following to the console:

    + Dancr2
    + Dancr2/config.yml
    + Dancr2/Makefile.PL
    + Dancr2/MANIFEST.SKIP
    + Dancr2/.dancer
    + Dancr2/cpanfile
    + Dancr2/bin
    + Dancr2/bin/app.psgi
    + Dancr2/environments
    + Dancr2/environments/development.yml
    + Dancr2/environments/production.yml
    + Dancr2/lib
    + Dancr2/lib/Dancr2.pm
    + Dancr2/public
    + Dancr2/public/favicon.ico
    + Dancr2/public/500.html
    + Dancr2/public/dispatch.cgi
    + Dancr2/public/404.html
    + Dancr2/public/dispatch.fcgi
    + Dancr2/public/css
    + Dancr2/public/css/error.css
    + Dancr2/public/css/style.css
    + Dancr2/public/images
    + Dancr2/public/images/perldancer.jpg
    + Dancr2/public/images/perldancer-bg.jpg
    + Dancr2/public/javascripts
    + Dancr2/public/javascripts/jquery.js
    + Dancr2/t
    + Dancr2/t/001_base.t
    + Dancr2/t/002_index_route.t
    + Dancr2/views
    + Dancr2/views/index.tt
    + Dancr2/views/layouts
    + Dancr2/views/layouts/main.tt

What you just did was create a fully functional app in Dancer2 with just one
command! The new app, named "Dancr2," won't do anything particularly useful until
you add your own routes to it, but it does take care of many of the tedious tasks
of setting up an app for you.

The files and folders that were generated and that you see listed above provide
a convenient scaffolding, or B<skeleton>, upon which you can build your app. The
default skelelton provides you with basic error pages, css, javascript,
graphics, tests, templates and other files which you are free to modify and
customize to your liking.

If you don't like the default skeleton provided to you by Dancer, the C<dancer2>
command allows you to generate your own custom skeletons. Consult
L<Dancer2::Manual/BOOTSTRAPPING-A-NEW-APP> for further details on this and other
capabilities of the C<dancer2>) utility.

=head2 Getting the new app up and running with Plack

In Part I, we used the C<start> command in our script to launch a
server to serve our app. Things are a little different when using C<dancer2>,
however. You'll notice that the C<dancer2> utility created a C<bin/> directory
with a file in it called C<app.psgi>. This is the file we use to get our
app up and running.

Let's see how to to do that by first changing into the Dancr2 directory and
then starting the server using the C<plackup> command:

    cd Dancr2;
    plackup -p 5000 bin/app.psgi

If all went well, you'll be able to see the Dancr2 home page by visiting:

    http://localhost:5000

The web page you see there gives you some very basic advice for tuning and
modifying your app and where you can go for more information to learn about
developing apps with Dancer2 (like this handy tutorial!).

Our Dancr2 app is served on a simple web server provided by Plack. Plack is 
PSGI compliant software, hence the C<psgi> extension for our file in the C<bin/>
directory. Plack and PSGI is beyond the scope of this tutorial but you can learn
more by visiting the L<Plack website|http://plackperl.org/>.

For now, all you need to know is that if you are deploying an app for use by
just yourself or a handful of people on a local network, Plack alone may do the
trick. More typically, you would use Plack in conjunction with other server
software to make your app much more robust. But in the early stages of your app's
development, a simple Plack server is more than likely all you need.

To learn more about the different ways for deploying your app, see the
L<Dancer2 Deployment Manual|Dancer2::Manual::Deployment>

=head2 Porting dancr.pl over to the new Dancr2 app

Ok, so now that we've got our new Dancr2 app up and running, it's time to learn
how to take advantage of what the C<dancer2> utility set up for us by porting
our dancr.pl script created in Part I into Dancr2.

=head3 The C<lib/> directory

The C<lib/> directory in our Dancr2 app is where our C<app.psgi> file will
expect our code to live. So let's take a peek at the file generated for us
in there:

    cat lib/Dancr2.pm

You'll see something like the following bit of code which provides a single
route to our app's home page and loads the index template:

    package Dancr2;
    use Dancer2;

    our $VERSION = '0.1';

    get '/' => sub {
        template 'index' => { title => 'Dancr2' };
    };

    true;

The first thing you'll notice is that instead of a script, we are using a module,
C<Dancr2> to package our code. Modules make it easer to pull off many powerful
tricks like packaging our app across several discrete modules. We'll let the
L<manual|Dancer2::Manual/Importing-using-Appname> explain this more
advanced technique.

=head3 Updating the Dancr2 module

Now that we know where to put our code, let's update the C<Dancr2.pm> module
with our original C<dancr.pl> code. Remove the existing sample route in
C<Dancr2.pm> and replace it with the code from our C<dancr.pl> file. You'll have
to make a couple of adjustments to the C<dancr.pl> code like removing the
C<use Dancer2;> line since it's already provided by our module. You'll also want
to be sure to remove the C<start;> line as well from the end of the file.

When you're done, C<Dancr2.pm> should look something close to this:

    package Dancr2;
    use Dancer2;

    our $VERSION = '0.1';

    # Our original dancr.pl code with some minor tweaks
    use DBI;
    use File::Spec;
    use File::Slurper qw/ read_text /;
    use Template;

    set 'database' => File::Spec->catfile(File::Spec->tmpdir(), 'dancr.db');
    set 'session'  => 'YAML';
    ...

    <snip> # The rest of the stuff </snip>

    ...

    sub init_db {
        my $schema = read_text('./schema.sql');
        $db->do($schema)
            or die $db->errstr;
    }

    get '/logout' => sub {
        app->destroy_session;
        set_flash('You are logged out.');
        redirect '/';
    };

    init_db();

Finally, to avoid getting an error in the C<init_db>) subroutine when it tries to
load our schema file, copy over the C<schema.db> file to the root directory of
the Dancr2 app:

    cp /path/to/dancr.pl/schema.db /path/to/Dancr2;

Ok, now that we've got the code moved over, let's move the assets from dancr.pl
to our new app.

=head3 The C<public/> directory

As mentioned in Part I, our static assets go into our C<public/> directory. If
you followed along with the tutorial in Part I, you should have a C<public/>
directory with a C<public/css> subdirectory and a file called C<style.css>
within that.

Dancer2 has conveniently generated the C<public/css> directory for us which has 
a default css file. Let's copy the style sheet from our original app so our new
app can use it:

    # Note: This command overwrites the default style sheet. Move it or copy
    # it if you wish to preserve it.

    cp /path/to/dancr.pl/public/css/style.css /path/to/Dancr2/public/css;

=head3 The C<views> directory

Along with our C<public/> directory, Dancer has also provided a C<views/> directory,
which as we covered, serves as the a home for our templates. Let's get those
copied over now:

    # NOTE: This command will overwrite the default main.tt tempalte file. Move
    # it or copy it if you wish to preserve it.

    cp -r /path/to/dancr.pl/views/* /path/to/Dancr2/views;

=head3 Does it work?

If you followed the instructions here closely, your Dancr2 app should be working.
Shut down any running Plack servers and then issue the same plackup command to
see if it runs:

    cd /path/to/Dancr2
    plackup -p 5000 bin/app.psgi

If you see any errors, get them resolved until the app loads.

=head2 Configuring Your App

In Part I, you configured your app with a series of C<set> statements near the
top of your file. Now we will show you a better way to configure your app using
Dancer2's configuration files.

Your skeleton provides your app with three different configuration files. The
first two files we'll discuss, found in the C<environments/> folder of
your app, are C<development.yml> and C<production.yml>. As you can probably
guess, the C<development.yml> file has settings intended to be used while
developing the app. The C<production.yml> file has settings more appropriate
for running your app when used by others. The third configuration file is found
in the root directory of your app and is named C<config.yml>. This file has the
settings that are common to all environments but that can be overridden by the
environment configuration files. You can still override any configuration file
settings in your modules using the C<set> command.

We will take a look at the C<development.yml> file first. Open that file in
your text editor and take a look inside. It has a bunch of helpful comments and
the following five settings sprinkled throughout:

    logger: "console"
    log: "core"
    show_stacktrace: 1
    startup_info: 1

The first four settings duplicate many of the settings in our new Dancr2 app. So
in the spirit of DRY (don't repeat yourself), edit your Dancr2 module and delete
the four lines that correspond to these four settings.

Then, in the configuration file, be sure to change the value for the C<log>
setting from "core" to "debug" so it matches the value we had in our module.

We will leave it up to you what you want to do with the fourth setting,
C<startup_info>. You can read about that setting, along with all the other
settings, in the L<configuration manual|Dancer2::Config/"startup_info-(boolean)">.

Finally, let's add a new setting to the configuration file for C<session> with
the following line:

    session: "Simple"

Then delete the corresponding setting from your Dancr2 module.

Alright, our Dancr2 app is a little leaner and meaner. Now open the main
C<config.yml> file and look for the settings in there that are also duplicated in
our app's module. There are two:

    layout: "main"
    template: "simple"

Leave C<layout> as is but change the template setting to "template_toolkit".
Then edit your Dancr2 module file and delete these two settings.

Finally, add the following configuration settings to the .yml file:

    username: "admin"
    password: "password"

Then you delete these two settings from the Dancr2 module, as well.

So, if you have been following along, you now have only the following C<set>
command in your Dancr2 module, related to the database configuration:

    set 'database' => File::Spec->catfile(File::Spec->tmpdir(), 'dancr.db');

We will get rid of this setting in Part III of the tutorial. All the rest of the
settings have been transferred to our configuration files. Nice!

We still have a little more cleanup we can do. Now that Dancer2 knows we are
using Template::Toolkit, we can delete the C<use Template;> line from our
module.

Now start the app C<plackup> command and check to see that everything works. By
default, Dancer2 will load the development environment configuration. When it
comes time to put your app into production, you can load the C<production.yml>
file configuration with plackup's C<--env> switch like so:

    plackup -p 5000 --env production bin/app.psgi

=head2 Keep on Dancing!

This concludes Part II of our tutorial where we showed you how to take advantage
of the C<dancer2> utility to set up a app skeleton to make it really easy to get
started developing your own apps.

Part III will refine our app a little further by showing you how to use plugins
so you can start capitalizing on all the great work contributed by other
Dancer2 developers.

=head1 Part III: Plugins, Your Many Dancing Partners

Dancer2 takes advantage of the open source software revolution by making it
exceedingly easy to use plugins that you can mix into your app to give it new
functionality. In Part III of this tutorial, we will update our new Dancr2 app
to use the L<Dancer2::Plugin::Database> to give you enough skills to go out and
explore other plugins on your own.

=head2 Installing plugins

Like Dancer2 itself, Dancer2 plugins can be found on the CPAN. Use your
favorite method for downloading and installing the L<Dancer2::Plugin::Database>
module on your machine. We recommend using C<cpanminus> like so:

    cpanm Dancer2::Plugin::Database

=head2 Using plugins

Using a plugin couldn't be easier. Simply add the following line to your Dancr2
module below the C<use Dancer2;> line in your module:

    use Dancer2::Plugin::Database;

=head2 Configuring plugins

Plugins can be configured with the YAML configuration files mentioned in Part II
of this tutorial. Let's edit the C<development.yml> file and add our database
configuration there. Below the last line in that file, add the following lines,
being careful to keep the indentation as you see it here:

  plugins:                 # all plugin configuration settings go in this section
    Database:              # the name of our plugin
      driver: "SQLite"     # driver we want to use
      database: "dancr.db" # where the database will go in our app
                           # run a query when connecting to the datbase:
      on_connect_do: [ "create table if not exists entries (id integer primary key autoincrement, title string not null, text string not null)" ]

Here, we direct our database plugin to use the "SQLite" driver and to
place the database in the root directory of our Dancr2. The C<on_connect_db>
setting tells the plugin to run an SQL query when it connects with the database
to create a table for us if it doesn't already exist.

=head2 Modifying our database code in the Dancr2 module

Now it's time to modify our Dancr2 module so it will use the plugin to query the
database instead of our own code. There are a few things to do. First, we will
delete the code we no longer need.

Since our configuration file tells the plugin where our database is, we can
delete this line:

    set 'database' => File::Spec->catfile(File::Spec->tmpdir(), 'dancr.db');

And since the database plugin will create our database connection and initialize
our database for us, we can scrap the following two subroutines and line from our
module:

    sub connect_db {
        my $dbh = DBI->connect("dbi:SQLite:dbname=".setting('database'))
            or die $DBI::errstr;

        return $dbh;
    }

    sub init_db {
        my $db = connect_db();
        my $schema = read_text('./schema.sql');
        $db->do($schema)
            or die $db->errstr;
    }

    init_db(); # Found at the bottom of our file

With that done, let's now take advantage of a hook the plugin provides us that
we can use to handle certain events by adding the following command to our
module to handle database errors:

    hook 'database_error' => sub {
        my $error = shift;
        die $error;
    };

Now let's make a few adjustments to the bits of code that make the
database queries. In our C<get '/'> route, change all instances of C<$db> with
C<database> and remove all the C<die> calls since we now have a hook to
handle the errors for us. When you are done, your route should look something
like this:

    get '/' => sub {
        my $sql = 'select id, title, text from entries order by id desc';
        my $sth = database->prepare($sql);
        $sth->execute;
        template 'show_entries.tt', {
            msg           => get_flash(),
            add_entry_url => uri_for('/add'),
            entries       => $sth->fetchall_hashref('id'),
        };
    };

Make the same changes to the C<post '/add'> route to transform it into this:

    post '/add' => sub {
        if ( not session('logged_in') ) {
            send_error("Not logged in", 401);
        }

        my $sql = 'insert into entries (title, text) values (?, ?)';
        my $sth = database->prepare($sql);
        $sth->execute(
            body_parameters->get('title'),
            body_parameters->get('text')
        );

        set_flash('New entry posted!');
        redirect '/';
    };

Our last step is to get rid of the following lines which we no longer need,
thanks to our plugin:

  use DBI;
  use File::Spec;
  use File::Slurper qw/ read_text /;

That's it! Now start your app with C<plackup> to make sure you don't get any
errors and then point your browser to test the app to make sure it works as
expected. If it doesn't, double and triple check your configuration settings and
your module's code which should now look like this:

    package Dancr2;
    use Dancer2;
    use Dancer2::Plugin::Database;

    our $VERSION = '0.1';

    my $flash;

    sub set_flash {
        my $message = shift;

        $flash = $message;
    }

    sub get_flash {
        my $msg = $flash;
        $flash  = "";

        return $msg;
    }

    hook before_template_render => sub {
        my $tokens = shift;

        $tokens->{'css_url'}    = request->base . 'css/style.css';
        $tokens->{'login_url'}  = uri_for('/login');
        $tokens->{'logout_url'} = uri_for('/logout');
    };

    hook 'database_error' => sub {
        my $error = shift;
        die $error;
    };

    get '/' => sub {
        my $sql = 'select id, title, text from entries order by id desc';
        my $sth = database->prepare($sql);
        $sth->execute;
        template 'show_entries.tt', {
            msg           => get_flash(),
            add_entry_url => uri_for('/add'),
            entries       => $sth->fetchall_hashref('id'),
        };
    };

    post '/add' => sub {
        if ( not session('logged_in') ) {
            send_error("Not logged in", 401);
        }

        my $sql = 'insert into entries (title, text) values (?, ?)';
        my $sth = database->prepare($sql);
        $sth->execute(
            body_parameters->get('title'),
            body_parameters->get('text')
        );

        set_flash('New entry posted!');
        redirect '/';
    };

    any ['get', 'post'] => '/login' => sub {
        my $err;

        if ( request->method() eq "POST" ) {
            # process form input
            if ( params->{'username'} ne setting('username') ) {
                $err = "Invalid username";
            }
            elsif ( params->{'password'} ne setting('password') ) {
                $err = "Invalid password";
            }
            else {
                session 'logged_in' => true;
                set_flash('You are logged in.');
                return redirect '/';
            }
        }

        # display login form
        template 'login.tt', {
            err => $err,
        };

    };

    get '/logout' => sub {
        app->destroy_session;
        set_flash('You are logged out.');
        redirect '/';
    };

    true;

=head2 Next steps

Congrats! You are now using the database plugin like a boss. The database plugin
does a lot more than what we showed you here. We'll leave it up to you to consult
the L<Dancer2::Plugin::Database|documentation> to unlock its full potential.

There are many more plugins for you to explore. You now know enough to install
and experiment with them. Some of the more popular and useful plugins are listed
at L<Dancer2::Plugins>. You can also search CPAN with "Dancer2::Plugin" for a
more comprehensive listing.

If you are feeling really inspired, you can learn how to extend Dancer2 with
your own plugins by reading L<Dancer2::Plugin>.

=head1 Happy dancing!

I hope these tutorials have been helpful and interesting enough to get you
exploring Dancer2 on your own. The framework is still under development but
it's definitely mature enough to use in a production project.

Happy dancing!

=head2 One more thing: Test!

Before we go, we want to mention that Dancer2 makes it very easy to
run automated tests on your app to help you find bugs. If you are new to
testing, we encourage you to start learning how. Your future self will thank you.
The effort you put into creating tests for your app will save you many hours of
frustration in the long run. Unfortunately, until we get Part IV of this tutorial
written, you'll have to consult the L<Dancer2 testing documentation|Dancer2::Manual/TESTING>
for more details on how to test your app.

Enjoy!

=head1 SEE ALSO

=over 4

=item *

L<http://perldancer.org>

=item *

L<http://github.com/PerlDancer/Dancer2>

=item *

L<Dancer2::Plugins>

=back

=head1 CSS COPYRIGHT AND LICENSE

The CSS stylesheet is copied verbatim from the Flaskr example application
and is subject to their license:

Copyright (c) 2010, 2013 by Armin Ronacher and contributors.

Some rights reserved.

Redistribution and use in source and binary forms of the software as well as
documentation, with or without modification, are permitted provided that the
following conditions are met:

=over 4

=item *

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

=item *

Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

=item *

The names of the contributors may not be used to endorse or promote products
derived from this software without specific prior written permission.

=back

=head1 AUTHOR

Dancer Core Developers

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2023 by Alexis Sukrieh.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut