1Dancer2::Manual::MigratUisoenr(3C)ontributed Perl DocumeDnatnacteiro2n::Manual::Migration(3)
2
3
4

NAME

6       Dancer2::Manual::Migration - Migrating from Dancer to Dancer2
7

VERSION

9       version 0.400001
10

Migration from Dancer 1 to Dancer2

12       This document covers some changes that users will need to be aware of
13       while upgrading from Dancer (version 1) to Dancer2.
14
15   Launcher script
16       The default launcher script bin/app.pl in Dancer looked like this:
17
18           #!/usr/bin/env perl
19           use Dancer;
20           use MyApp;
21           dance;
22
23       In Dancer2 it is available as bin/app.psgi and looks like this:
24
25           #!/usr/bin/env perl
26
27           use strict;
28           use warnings;
29           use FindBin;
30           use lib "$FindBin::Bin/../lib";
31
32           use MyApp;
33           MyApp->to_app;
34
35       So you need to remove the "use Dancer;" part, replace the "dance;"
36       command by "MyApp->to_app;" (where MyApp is the name of your
37       application), and add the following lines:
38
39           use strict;
40           use warnings;
41           use FindBin;
42           use lib "$FindBin::Bin/../lib";
43
44       There is a Dancer Advent Calendar <http://advent.perldancer.org>
45       article covering the "to_app" keyword
46       <http://advent.perldancer.org/2014/9> and its usage.
47
48   Configuration
49       You specify a different location to the directory used for serving
50       static (public) content by setting the "public_dir" option. In that
51       case, you have to set "static_handler" option also.
52
53   Apps
54       1. In Dancer2, each module is a separate application with its own
55       namespace and variables. You can set the application name in each of
56       your Dancer2 application modules. Different modules can be tied into
57       the same app by setting the application name to the same value.
58
59       For example, to set the appname directive explicitly:
60
61       "MyApp":
62
63           package MyApp;
64           use Dancer2;
65           use MyApp::Admin
66
67           hook before => sub {
68               var db => 'Users';
69           };
70
71           get '/' => sub {...};
72
73           1;
74
75       "MyApp::Admin":
76
77           package MyApp::Admin;
78           use Dancer2 appname => 'MyApp';
79
80           # use a lexical prefix so we don't override it globally
81           prefix '/admin' => sub {
82               get '/' => sub {...};
83           };
84
85           1;
86
87       Without the appname directive, "MyApp::Admin" would not have access to
88       variable "db". In fact, when accessing "/admin", the before hook would
89       not be executed.
90
91       See Dancer2::Cookbook
92       <https://metacpan.org/pod/Dancer2::Cookbook#Using-the-prefix-feature-
93       to-split-your-application> for details.
94
95       2. To speed up an app in Dancer2, install the recommended modules
96       listed in the "Performance Improvements" in Dancer2::Manual::Deployment
97       section.
98
99   Request
100       The request object (Dancer2::Core::Request) is now deferring much of
101       its code to Plack::Request to be consistent with the known interface to
102       PSGI requests.
103
104       Currently the following attributes pass directly to Plack::Request:
105
106       "address", "remote_host", "protocol", "port", "method", "user",
107       "request_uri", "script_name", "content_length", "content_type",
108       "content_encoding", "referer", and "user_agent".
109
110       If previous attributes returned undef for no value beforehand, they
111       will return whatever Plack::Request defines now, which just might be an
112       empty list.
113
114       For example:
115
116           my %data = (
117               referer    => request->referer,
118               user_agent => request->user_agent,
119           );
120
121       should be replaced by:
122
123           my %data = (
124               referer    => request->referer    || '',
125               user_agent => request->user_agent || '',
126           );
127
128   Plugins: plugin_setting
129       "plugin_setting" returns the configuration of the plugin. It can only
130       be called in "register" or "on_plugin_import".
131
132   Routes
133       Dancer2 requires all routes defined via a string to begin with a
134       leading slash "/".
135
136       For example:
137
138           get '0' => sub {
139               return "not gonna fly";
140           };
141
142       would return an error. The correct way to write this would be to use
143       "get '/0'"
144
145   Route parameters
146       The "params" keyword which provides merged parameters used to allow
147       body parameters to override route parameters. Now route parameters take
148       precedence over query parameters and body parameters.
149
150       We have introduced "route_parameters" to retrieve parameter values from
151       the route matching. Please refer to Dancer2::Manual for more
152       information.
153
154   Tests
155       Dancer2 recommends the use of Plack::Test.
156
157       For example:
158
159           use strict;
160           use warnings;
161           use Test::More tests => 2;
162           use Plack::Test;
163           use HTTP::Request::Common;
164
165           {
166               package App::Test; # or whatever you want to call it
167               get '/' => sub { template 'index' };
168           }
169
170           my $test = Plack::Test->create( App::Test->to_app );
171           my $res  = $test->request( GET '/' );
172
173           ok( $res->is_success, '[GET /] Successful' );
174           like( $res->content, qr{<title>Test2</title>}, 'Correct title' );
175
176       Other modules that could be used for testing are:
177
178       •   Test::TCP
179
180       •   Test::WWW::Mechanize::PSGI
181
182       Logs
183
184       The "logger_format" in the Logger role (Dancer2::Core::Role::Logger) is
185       now "log_format".
186
187       "read_logs" can no longer be used, as with Dancer2::Test. Instead,
188       Dancer2::Logger::Capture could be used for testing, to capture all logs
189       to an object.
190
191       For example:
192
193           use strict;
194           use warnings;
195           use Test::More import => ['!pass'];
196           use Plack::Test;
197           use HTTP::Request::Common;
198           use Ref::Util qw<is_coderef>;
199
200           {
201               package App;
202               use Dancer2;
203
204               set log       => 'debug';
205               set logger    => 'capture';
206
207               get '/' => sub {
208                   debug 'this is my debug message';
209                   return 1;
210               };
211           }
212
213           my $app = Dancer2->psgi_app;
214           ok( is_coderef($app), 'Got app' );
215
216           test_psgi $app, sub {
217               my $cb = shift;
218
219               my $res = $cb->( GET '/' );
220               is $res->code, 200;
221
222               my $trap = App->dancer_app->logger_engine->trapper;
223
224               is_deeply $trap->read, [
225                   { level => 'debug', message => 'this is my debug message' }
226               ];
227           };
228
229   Exports: Tags
230       The following tags are not needed in Dancer2:
231
232        use Dancer2 qw(:syntax);
233        use Dancer2 qw(:tests);
234        use Dancer2 qw(:script);
235
236       The "plackup" command should be used instead. It provides a development
237       server and reads the configuration options in your command line
238       utilities.
239
240   Engines
241       •   Engines receive a logging callback
242
243           Engines now receive a logging callback named "log_cb". Engines can
244           use it to log anything in run-time, without having to worry about
245           what logging engine is used.
246
247           This is provided as a callback because the logger might be changed
248           in run-time and we want engines to be able to always reach the
249           current one without having a reference back to the core application
250           object.
251
252           The logger engine doesn't have the attribute since it is the logger
253           itself.
254
255       •   Engines handle encoding consistently
256
257           All engines are now expected to handle encoding on their own. User
258           code is expected to be in internal Perl representation.
259
260           Therefore, all serializers, for example, should deserialize to the
261           Perl representation. Templates, in turn, encode to UTF-8 if
262           requested by the user, or by default.
263
264           One side-effect of this is that "from_yaml" will call YAML's "Load"
265           function with decoded input.
266
267       Templating engine changes
268
269       Whereas in Dancer1, the following were equivalent for
270       Template::Toolkit:
271
272           template 'foo/bar'
273           template '/foo/bar'
274
275       In Dancer2, when using Dancer2::Template::TemplateToolkit, the version
276       with the leading slash will try to locate "/foo/bar" relative to your
277       filesystem root, not relative to your Dancer application directory.
278
279       The Dancer2::Template::Simple engine is unchanged in this respect.
280
281       Whereas in Dancer1, template engines have the methods:
282
283           $template_engine->view('foo.tt')
284           $template_engine->view_exists('foo.tt')
285
286       In Dancer2, you should instead write:
287
288           $template_engine->view_pathname('foo.tt')
289           $template_engine->pathname_exists($full_path)
290
291       You may not need these unless you are writing a templating engine.
292
293       Serializers
294
295       You no longer need to implement the "loaded" method. It is simply
296       unnecessary.
297
298       Sessions
299
300       Now the Simple session engine is turned on by default, unless you
301       specify a different one.
302
303   Configuration
304       "public_dir"
305
306       You cannot set the public directory with "setting" now. Instead you
307       will need to call "config":
308
309           # before
310           setting( 'public_dir', 'new_path/' );
311
312           # after
313           config->{'public_dir'} = 'new_path';
314
315       warnings
316
317       The "warnings" configuration option, along with the environment
318       variable "DANCER_WARNINGS", have been removed and have no effect
319       whatsoever.
320
321       They were added when someone requested to be able to load Dancer
322       without the warnings pragma, which it adds, just like Moose, Moo, and
323       other modules provide.
324
325       If you want this to happen now (which you probably shouldn't be doing),
326       you can always control it lexically:
327
328           use Dancer2;
329           no warnings;
330
331       You can also use Dancer2 within a narrower scope:
332
333           { use Dancer2 }
334           use strict;
335           # warnings are not turned on
336
337       However, having warnings turned it is very recommended.
338
339       server_tokens
340
341       The configuration "server_tokens" has been introduced in the reverse
342       (but more sensible, and Plack-compatible) form as "no_server_tokens".
343
344       "DANCER_SERVER_TOKENS" changed to "DANCER_NO_SERVER_TOKENS".
345
346       engines
347
348       If you want to use Template::Toolkit instead of the built-in simple
349       templating engine you used to enable the following line in the
350       config.yml file.
351
352           template: "template_toolkit"
353
354       That was enough to get started. The start_tag and end_tag it used were
355       the same as in the simple template <% and %> respectively.
356
357       If you wanted to further customize the Template::Toolkit you could also
358       enable or add the following:
359
360           engines:
361             template_toolkit:
362                encoding:  'utf8'
363                start_tag: '[%'
364                end_tag:   '%]'
365
366       In Dancer 2 you can also enable Template::Toolkit with the same
367       configuration option:
368
369           template: "template_toolkit"
370
371       But the default start_tag and end_tag are now [% and %], so if you used
372       the default in Dancer 1 now you will have to explicitly change the
373       start_tag and end_tag values.  The configuration also got an extra
374       level of depth. Under the "engine" key there is a "template" key and
375       the "template_toolkit" key comes below that. As in this example:
376
377           engines:
378             template:
379               template_toolkit:
380                 start_tag: '<%'
381                 end_tag:   '%>'
382
383       In a nutshell, if you used to have
384
385           template: "template_toolkit"
386
387       You need to replace it with
388
389           template: "template_toolkit"
390           engines:
391             template:
392               template_toolkit:
393                 start_tag: '<%'
394                 end_tag:   '%>'
395
396       Session engine
397
398       The session engine is configured in the "engine" section.
399
400       •   "session_name" changed to "cookie_name".
401
402       •   "session_domain" changed to "cookie_domain".
403
404       •   "session_expires" changed to "cookie_duration".
405
406       •   "session_secure" changed to "is_secure".
407
408       •   "session_is_http_only" changed to "is_http_only".
409
410       Dancer2 also adds two attributes for session:
411
412       •   "cookie_path" The path of the cookie to create for storing the
413           session key. Defaults to "/".
414
415       •   "session_duration" Duration in seconds before sessions should
416           expire, regardless of cookie expiration. If set, then
417           SessionFactories should use this to enforce a limit on session
418           validity.
419
420       See Dancer2::Core::Role::SessionFactory for more detailed documentation
421       for these options, or the particular session engine for other supported
422       options.
423
424         session: Simple
425
426         engines:
427           session:
428             Simple:
429               cookie_name: dance.set
430               cookie_duration: '24 hours'
431               is_secure: 1
432               is_http_only: 1
433
434       Plack Middleware
435
436       In Dancer1 you could set up Plack Middleware using a
437       "plack_middlewares" key in your "config.yml" file. Under Dancer2 you
438       will instead need to invoke middleware using Plack::Builder, as
439       demonstrated in Dancer2::Manual::Deployment.
440
441   Keywords
442       Calling Keywords Explicitly
443
444       In Dancer1, keywords could be imported individually into a package:
445
446           package MyApp;
447           use Dancer qw< get post params session >;
448
449           get '/foo' { ... };
450
451       Any keywords you did't export could be called explicitly:
452
453           package MyApp;
454           use Dancer qw< get post params session >;
455           use List::Util qw< any >;
456
457           Dancer::any sub { ... };
458
459       Dancer2's DSL is implemented differently. Keywords only exist in the
460       namespace of the package which "use"s Dancer2, i.e. there is no
461       "Dancer2::any", only e.g. "MyApp::any".
462
463       If you only want individual keywords, you can write a shim as follows:
464
465           package MyApp::DSL;
466           use Dancer2 appname => 'MyApp';
467
468           use Exporter qw< import >;
469
470           our @EXPORT = qw< get post ... >
471
472       Then in other packages:
473
474           package MyApp;
475
476           use MyApp::DSL qw< get post >;
477
478           MyApp::DSL::any sub { ... };
479
480       appdir
481
482       This keyword does not exist in Dancer2. However, the same information
483       can be found in "config->{'appdir'}".
484
485       load
486
487       This keyword is no longer required. Dancer2 loads the environment
488       automatically and will not reload any other environment when called
489       with load. (It's a good thing.)
490
491       param_array
492
493       This keyword doesn't exist in Dancer2.
494
495       session
496
497       In Dancer a session was created and a cookie was sent just by rendering
498       a page using the "template" function. In Dancer2 one needs to actually
499       set a value in a session object using the "session" function in order
500       to create the session and send the cookie.
501
502       The session keyword has multiple states:
503
504       •   No arguments
505
506           Without any arguments, the session keyword returns a
507           Dancer2::Core::Session object, which has methods for read, write,
508           and delete.
509
510               my $session = session;
511               $session->read($key);
512               $session->write( $key => $value );
513               $session->delete($key);
514
515       •   Single argument (key)
516
517           If a single argument is provided, it is treated as the key, and it
518           will retrieve the value for it.
519
520               my $value = session $key;
521
522       •   Two arguments (key, value)
523
524           If two arguments are provided, they are treated as a key and a
525           value, in which case the session will assign the value to the key.
526
527               session $key => $value;
528
529       •   Two arguments (key, undef)
530
531           If two arguments are provided, but the second is undef, the key
532           will be deleted from the session.
533
534               session $key => undef;
535
536       In Dancer 1 it wasn't possible to delete a key, but in Dancer2 we can
537       finally delete:
538
539           # these two are equivalent
540           session $key => undef;
541
542           my $session = session;
543           $session->delete($key);
544
545       You can retrieve the whole session hash with the "data" method:
546
547           $session->data;
548
549       To destroy a session, instead of writing:
550
551           session->destroy
552
553       In Dancer2, we write:
554
555           app->destroy_session if app->has_session
556
557       If you make changes to the session in an "after" hook, your changes
558       will not be written to storage, because writing sessions to storage
559       also takes place in an (earlier) "after" hook.
560

AUTHOR

562       Dancer Core Developers
563
565       This software is copyright (c) 2023 by Alexis Sukrieh.
566
567       This is free software; you can redistribute it and/or modify it under
568       the same terms as the Perl 5 programming language system itself.
569
570
571
572perl v5.38.0                      2023-07-20     Dancer2::Manual::Migration(3)
Impressum