de-proto the examples
[catagits/Web-Simple.git] / lib / Web / Simple.pm
CommitLineData
5c33dda5 1package Web::Simple;
2
8bd060f4 3use strictures 1;
8bd060f4 4use warnings::illegalproto ();
876e62e1 5use Moo ();
6use Web::Dispatch::Wrapper ();
8c4ffad3 7
204d2ff7 8our $VERSION = '0.030';
5c33dda5 9
44db8e76 10sub import {
5c33dda5 11 my ($class, $app_package) = @_;
876e62e1 12 $app_package ||= caller;
13 $class->_export_into($app_package);
14 eval "package $app_package; use Web::Dispatch::Wrapper; use Moo; 1"
15 or die "Failed to setup app package: $@";
445b3ea0 16 strictures->import;
8bd060f4 17 warnings::illegalproto->unimport;
5c33dda5 18}
19
20sub _export_into {
21 my ($class, $app_package) = @_;
22 {
23 no strict 'refs';
c7b1c57f 24 *{"${app_package}::PSGI_ENV"} = sub () { -1 };
5c33dda5 25 require Web::Simple::Application;
26 unshift(@{"${app_package}::ISA"}, 'Web::Simple::Application');
27 }
b7063124 28 (my $name = $app_package) =~ s/::/\//g;
29 $INC{"${name}.pm"} = 'Set by "use Web::Simple;" invocation';
5c33dda5 30}
31
fd6d986e 321;
34823486 33
7401408e 34=head1 NAME
35
36Web::Simple - A quick and easy way to build simple web applications
37
7401408e 38
39=head1 SYNOPSIS
40
05ad188d 41 #!/usr/bin/env perl
7401408e 42
4f83bde7 43 package HelloWorld;
6ee6b2dc 44 use Web::Simple;
4f83bde7 45
46 sub dispatch_request {
bb07abdc 47 GET => sub {
4f83bde7 48 [ 200, [ 'Content-type', 'text/plain' ], [ 'Hello world!' ] ]
49 },
bb07abdc 50 '' => sub {
4f83bde7 51 [ 405, [ 'Content-type', 'text/plain' ], [ 'Method not allowed' ] ]
445b3ea0 52 }
7401408e 53 }
54
55 HelloWorld->run_if_script;
56
05ad188d 57If you save this file into your cgi-bin as C<hello-world.cgi> and then visit:
7401408e 58
59 http://my.server.name/cgi-bin/hello-world.cgi/
60
4f83bde7 61you'll get the "Hello world!" string output to your browser. At the same time
62this file will also act as a class module, so you can save it as HelloWorld.pm
63and use it as-is in test scripts or other deployment mechanisms.
64
ca30a017 65Note that you should retain the ->run_if_script even if your app is a
66module, since this additionally makes it valid as a .psgi file, which can
67be extremely useful during development.
68
4f83bde7 69For more complex examples and non-CGI deployment, see
70L<Web::Simple::Deployment>. To get help with L<Web::Simple>, please connect to
71the irc.perl.org IRC network and join #web-simple.
7401408e 72
fb771406 73=head1 DESCRIPTION
7401408e 74
6a4808bf 75The philosophy of L<Web::Simple> is to keep to an absolute bare minimum for
7401408e 76everything. It is not designed to be used for large scale applications;
77the L<Catalyst> web framework already works very nicely for that and is
78a far more mature, well supported piece of software.
79
80However, if you have an application that only does a couple of things, and
3895385d 81want to not have to think about complexities of deployment, then L<Web::Simple>
7401408e 82might be just the thing for you.
83
6a4808bf 84The only public interface the L<Web::Simple> module itself provides is an
85C<import> based one:
7401408e 86
87 use Web::Simple 'NameOfApplication';
88
6a4808bf 89This sets up your package (in this case "NameOfApplication" is your package)
3895385d 90so that it inherits from L<Web::Simple::Application> and imports L<strictures>,
38d5b336 91as well as installs a C<PSGI_ENV> constant for convenience, as well as some
3895385d 92other subroutines.
93
6a4808bf 94Importing L<strictures> will automatically make your code use the C<strict> and
3895385d 95C<warnings> pragma, so you can skip the usual:
7401408e 96
97 use strict;
c6ce65ac 98 use warnings FATAL => 'all';
7401408e 99
100provided you 'use Web::Simple' at the top of the file. Note that we turn
101on *fatal* warnings so if you have any warnings at any point from the file
102that you did 'use Web::Simple' in, then your application will die. This is,
103so far, considered a feature.
104
a5006b25 105When we inherit from L<Web::Simple::Application> we also use L<Moo>, which is
3895385d 106the the equivalent of:
7401408e 107
108 {
109 package NameOfApplication;
445b3ea0 110 use Moo;
111 extends 'Web::Simple::Application';
7401408e 112 }
113
6a4808bf 114So you can use L<Moo> features in your application, such as creating attributes
115using the C<has> subroutine, etc. Please see the documentation for L<Moo> for
116more information.
117
445b3ea0 118It also exports the following subroutines for use in dispatchers:
7401408e 119
74afe4b7 120 response_filter { ... };
7401408e 121
122 redispatch_to '/somewhere';
123
b7063124 124Finally, import sets
125
126 $INC{"NameOfApplication.pm"} = 'Set by "use Web::Simple;" invocation';
127
128so that perl will not attempt to load the application again even if
129
130 require NameOfApplication;
131
132is encountered in other code.
133
20645c5f 134One important thing to remember when using
135
136 NameOfApplication->run_if_script;
137
138At the end of your app is that this call will create an instance of your app
139for you automatically, regardless of context. An easier way to think of this
140would be if the method were more verbosely named
141
142 NameOfApplication->run_request_if_script_else_turn_coderef_for_psgi;
143
3583ca04 144=head1 DISPATCH STRATEGY
145
6a4808bf 146L<Web::Simple> despite being straightforward to use, has a powerful system
3895385d 147for matching all sorts of incoming URLs to one or more subroutines. These
148subroutines can be simple actions to take for a given URL, or something
149more complicated, including entire L<Plack> applications, L<Plack::Middleware>
150and nested subdispatchers.
151
c21c9f07 152=head2 Examples
153
445b3ea0 154 sub dispatch_request {
bb07abdc 155 (
156 # matches: GET /user/1.htm?show_details=1
157 # GET /user/1.htm
158 'GET + /user/* + ?show_details~ + .htm|.html|.xhtml' => sub {
159 my ($self, $user_id, $show_details) = @_;
445b3ea0 160 ...
161 },
bb07abdc 162 # matches: POST /user?username=frew
163 # POST /user?username=mst&first_name=matt&last_name=trout
164 'POST + /user + ?username=&*' => sub {
165 my ($self, $username, $misc_params) = @_;
445b3ea0 166 ...
167 },
bb07abdc 168 # matches: DELETE /user/1/friend/2
169 'DELETE + /user/*/friend/*' => sub {
170 my ($self, $user_id, $friend_id) = @_;
171 ...
172 },
173 # matches: PUT /user/1?first_name=Matt&last_name=Trout
174 'PUT + /user/* + ?first_name~&last_name~' => sub {
175 my ($self, $user_id, $first_name, $last_name) = @_;
176 ...
177 },
178 '/user/*/...' => sub {
179 my $user_id = $_[1];
180 (
181 # matches: PUT /user/1/role/1
182 'PUT + /role/*' => sub {
183 my $role_id = $_[1];
184 ...
185 },
186 # matches: DELETE /user/1/role/1
187 'DELETE + /role/*' => sub {
188 my $role_id = $_[1];
189 ...
190 },
191 );
192 },
193 );
c21c9f07 194 }
195
3706e2a0 196=head2 The dispatch cycle
81a5b03e 197
3706e2a0 198At the beginning of a request, your app's dispatch_request method is called
199with the PSGI $env as an argument. You can handle the request entirely in
200here and return a PSGI response arrayref if you want:
81a5b03e 201
3706e2a0 202 sub dispatch_request {
203 my ($self, $env) = @_;
204 [ 404, [ 'Content-type' => 'text/plain' ], [ 'Amnesia == fail' ] ]
205 }
81a5b03e 206
bb07abdc 207However, generally, instead of that, you return a set of route/target
208pairs:
81a5b03e 209
3706e2a0 210 sub dispatch_request {
211 my $self = shift;
bb07abdc 212 (
213 '/' => sub { redispatch_to '/index.html' },
214 '/user/*' => sub { $self->show_user($_[1]) },
215 'POST + %*' => 'handle_post',
216 ...
217 );
3706e2a0 218 }
81a5b03e 219
e927492b 220Well, a sub is a valid PSGI response too (for ultimate streaming and async
221cleverness). If you want to return a PSGI sub you have to wrap it into an
222array ref.
223
224 sub dispatch_request {
20645c5f 225 [ sub {
e927492b 226 my $respond = shift;
227 # This is pure PSGI here, so read perldoc PSGI
228 } ]
229 }
230
bb07abdc 231If you return a string followed by a subroutine or method name, the string is
232treated as a match specification - and if the test is passed, the subroutine
233is called as a method and passed any matched arguments (see below for more details).
81a5b03e 234
65e03df0 235You can also return a plain subroutine which will be called with just C<$env>
236- remember that in this case if you need C<$self> you B<must> close over it.
81a5b03e 237
3895385d 238If you return a normal object, L<Web::Simple> will simply return it upwards on
239the assumption that a response_filter (or some arbitrary L<Plack::Middleware>)
240somewhere will convert it to something useful. This allows:
81a5b03e 241
3706e2a0 242 sub dispatch_request {
243 my $self = shift;
bb07abdc 244 (
245 '.html' => sub { response_filter { $self->render_zoom($_[0]) } },
246 '/user/*' => sub { $self->users->get($_[1]) },
247 );
3706e2a0 248 }
81a5b03e 249
bb07abdc 250An alternative to using string + suborutine to declare a route is to use
251the sub prototype -
20645c5f 252
253 sub dispatch_request {
254 my $self = shift;
255 (
bb07abdc 256 sub (.html) { response_filter { $self->render_zoom($_[0]) } },
257 sub (/user/) { $self->users->get($_[1]) },
258 $self->can('handle_post'), # if declared as 'sub handle_post (...) {'
20645c5f 259 )
260 }
261
bb07abdc 262This can be useful sugar, especially if you want to keep method-based
263dispatchers' route specifications on the methods.
20645c5f 264
3895385d 265to render a user object to HTML, if there is an incoming URL such as:
266
267 http://myweb.org/user/111.html
268
269This works because as we descend down the dispachers, we first match
270C<sub (.html)>, which adds a C<response_filter> (basically a specialized routine
271that follows the L<Plack::Middleware> specification), and then later we also
272match C<sub (/user/*)> which gets a user and returns that as the response.
273This user object 'bubbles up' through all the wrapping middleware until it hits
274the C<response_filter> we defined, after which the return is converted to a
275true html response.
81a5b03e 276
29c7cff1 277However, two types of objects are treated specially - a C<Plack::Component> object
65e03df0 278will have its C<to_app> method called and be used as a dispatcher:
81a5b03e 279
3706e2a0 280 sub dispatch_request {
281 my $self = shift;
bb07abdc 282 (
283 '/static/...' => sub { Plack::App::File->new(...) },
284 ...
285 );
81a5b03e 286 }
287
65e03df0 288A L<Plack::Middleware> object will be used as a filter for the rest of the
3706e2a0 289dispatch being returned into:
81a5b03e 290
6af22ff2 291 ## responds to /admin/track_usage AND /admin/delete_accounts
292
3706e2a0 293 sub dispatch_request {
294 my $self = shift;
bb07abdc 295 (
296 '/admin/**' => sub {
297 Plack::Middleware::Session->new(%opts);
298 },
299 '/admin/track_usage' => sub {
300 ## something that needs a session
301 },
302 '/admin/delete_accounts' => sub {
303 ## something else that needs a session
304 },
305 );
81a5b03e 306 }
307
65e03df0 308Note that this is for the dispatch being B<returned> to, so if you want to
3706e2a0 309provide it inline you need to do:
81a5b03e 310
6af22ff2 311 ## ALSO responds to /admin/track_usage AND /admin/delete_accounts
312
3706e2a0 313 sub dispatch_request {
314 my $self = shift;
bb07abdc 315 (
316 '/admin/...' => sub {
317 (
318 sub {
319 Plack::Middleware::Session->new(%opts);
320 },
321 '/track_usage' => sub {
322 ## something that needs a session
323 },
324 '/delete_accounts' => sub {
325 ## something else that needs a session
326 },
327 );
328 }
329 );
81a5b03e 330 }
331
3706e2a0 332And that's it - but remember that all this happens recursively - it's
3895385d 333dispatchers all the way down. A URL incoming pattern will run all matching
334dispatchers and then hit all added filters or L<Plack::Middleware>.
3706e2a0 335
81a5b03e 336=head2 Web::Simple match specifications
337
338=head3 Method matches
339
bb07abdc 340 'GET' => sub {
15dfe701 341
342A match specification beginning with a capital letter matches HTTP requests
343with that request method.
344
81a5b03e 345=head3 Path matches
346
bb07abdc 347 '/login' => sub {
15dfe701 348
349A match specification beginning with a / is a path match. In the simplest
350case it matches a specific path. To match a path with a wildcard part, you
351can do:
352
bb07abdc 353 '/user/*' => sub {
15dfe701 354 $self->handle_user($_[1])
355
356This will match /user/<anything> where <anything> does not include a literal
357/ character. The matched part becomes part of the match arguments. You can
358also match more than one part:
359
bb07abdc 360 '/user/*/*' => sub {
15dfe701 361 my ($self, $user_1, $user_2) = @_;
362
bb07abdc 363 '/domain/*/user/*' => sub {
15dfe701 364 my ($self, $domain, $user) = @_;
365
65e03df0 366and so on. To match an arbitrary number of parts, use C<**>:
15dfe701 367
bb07abdc 368 '/page/**' => sub {
1d02a8ae 369 my ($self, $match) = @_;
15dfe701 370
1d02a8ae 371This will result in a single element for the entire match. Note that you can do
15dfe701 372
bb07abdc 373 '/page/**/edit' => sub {
15dfe701 374
375to match an arbitrary number of parts up to but not including some final
376part.
377
65e03df0 378Note: Since Web::Simple handles a concept of file extensions, C<*> and C<**>
e060a690 379matchers will not by default match things after a final dot, and this
65e03df0 380can be modified by using C<*.*> and C<**.*> in the final position, e.g.:
e060a690 381
382 /one/* matches /one/two.three and captures "two"
383 /one/*.* matches /one/two.three and captures "two.three"
384 /** matches /one/two.three and captures "one/two"
385 /**.* matches /one/two.three and captures "one/two.three"
386
da8429c9 387Finally,
388
bb07abdc 389 '/foo/...' => sub {
da8429c9 390
65e03df0 391Will match C</foo/> on the beginning of the path B<and> strip it. This is
e060a690 392designed to be used to construct nested dispatch structures, but can also prove
393useful for having e.g. an optional language specification at the start of a
394path.
da8429c9 395
396Note that the '...' is a "maybe something here, maybe not" so the above
397specification will match like this:
398
399 /foo # no match
400 /foo/ # match and strip path to '/'
401 /foo/bar/baz # match and strip path to '/bar/baz'
402
e060a690 403Almost the same,
15e679c1 404
bb07abdc 405 '/foo...' => sub {
e060a690 406
407Will match on C</foo/bar/baz>, but also include C</foo>. Otherwise it
408operates the same way as C</foo/...>.
409
410 /foo # match and strip path to ''
411 /foo/ # match and strip path to '/'
412 /foo/bar/baz # match and strip path to '/bar/baz'
413
414Please note the difference between C<sub(/foo/...)> and C<sub(/foo...)>. In
415the first case, this is expecting to find something after C</foo> (and fails to
416match if nothing is found), while in the second case we can match both C</foo>
417and C</foo/more/to/come>. The following are roughly the same:
418
bb07abdc 419 '/foo' => sub { 'I match /foo' },
420 '/foo/...' => sub {
421 (
422 '/bar' => sub { 'I match /foo/bar' },
423 '/*' => sub { 'I match /foo/{id}' },
424 );
e060a690 425 }
426
427Versus
428
bb07abdc 429 '/foo...' => sub {
430 (
431 '~' => sub { 'I match /foo' },
432 '/bar' => sub { 'I match /foo/bar' },
433 '/*' => sub { 'I match /foo/{id}' },
434 );
e060a690 435 }
436
437You may prefer the latter example should you wish to take advantage of
438subdispatchers to scope common activities. For example:
439
bb07abdc 440 '/user...' => sub {
e060a690 441 my $user_rs = $schema->resultset('User');
bb07abdc 442 (
443 '~' => sub { $user_rs },
444 '/*' => sub { $user_rs->find($_[1]) },
445 );
e060a690 446 }
447
448You should note the special case path match C<sub (~)> which is only meaningful
449when it is contained in this type of path match. It matches to an empty path.
450
7c03cd61 451=head4 Naming your patch matches
452
65e03df0 453Any C<*>, C<**>, C<*.*>, or C<**.*> match can be followed with C<:name> to make it into a named
7c03cd61 454match, so:
455
bb07abdc 456 '/*:one/*:two/*:three/*:four' => sub {
7c03cd61 457 "I match /1/2/3/4 capturing { one => 1, two => 2, three => 3, four => 4 }"
458 }
459
bb07abdc 460 '/**.*:allofit' => sub {
7c03cd61 461 "I match anything capturing { allofit => \$whole_path }"
462 }
463
464In the specific case of a simple single-* match, the * may be omitted, to
465allow you to write:
466
bb07abdc 467 '/:one/:two/:three/:four' => sub {
7c03cd61 468 "I match /1/2/3/4 capturing { one => 1, two => 2, three => 3, four => 4 }"
469 }
470
e060a690 471=head4 C</foo> and C</foo/> are different specs
472
bb07abdc 473As you may have noticed with the difference between C<'/foo/...'> and
474C<'/foo...'>, trailing slashes in path specs are significant. This is
e060a690 475intentional and necessary to retain the ability to use relative links on
476websites. Let's demonstrate on this link:
477
478 <a href="bar">bar</a>
479
480If the user loads the url C</foo/> and clicks on this link, they will be
481sent to C</foo/bar>. However when they are on the url C</foo> and click this
482link, then they will be sent to C</bar>.
483
484This makes it necessary to be explicit about the trailing slash.
15e679c1 485
81a5b03e 486=head3 Extension matches
487
bb07abdc 488 '.html' => sub {
15dfe701 489
6a4808bf 490will match .html from the path (assuming the subroutine itself returns
65e03df0 491something, of course). This is normally used for rendering - e.g.:
15dfe701 492
bb07abdc 493 '.html' => sub {
74afe4b7 494 response_filter { $self->render_html($_[1]) }
15dfe701 495 }
496
b8bd7bd1 497Additionally,
498
bb07abdc 499 '.*' => sub {
b8bd7bd1 500
6a4808bf 501will match any extension and supplies the extension as a match argument.
b8bd7bd1 502
9b9866ae 503=head3 Query and body parameter matches
504
505Query and body parameters can be match via
506
bb07abdc 507 '?<param spec>' => sub { # match URI query
508 '%<param spec>' => sub { # match body params
9b9866ae 509
cb12d2a3 510The body spec will match if the request content is either
511application/x-www-form-urlencoded or multipart/form-data - the latter
c32b7fda 512of which is required for uploads - see below.
9b9866ae 513
65e03df0 514The param spec is elements of one of the following forms:
9b9866ae 515
516 param~ # optional parameter
517 param= # required parameter
518 @param~ # optional multiple parameter
519 @param= # required multiple parameter
eb9e0e25 520 :param~ # optional parameter in hashref
521 :param= # required parameter in hashref
522 :@param~ # optional multiple in hashref
523 :@param= # required multiple in hashref
524 * # include all other parameters in hashref
525 @* # include all other parameters as multiple in hashref
9b9866ae 526
65e03df0 527separated by the C<&> character. The arguments added to the request are
528one per non-C<:>/C<*> parameter (scalar for normal, arrayref for multiple),
529plus if any C<:>/C<*> specs exist a hashref containing those values.
9b9866ae 530
3895385d 531Please note that if you specify a multiple type parameter match, you are
532ensured of getting an arrayref for the value, EVEN if the current incoming
533request has only one value. However if a parameter is specified as single
534and multiple values are found, the last one will be used.
535
65e03df0 536For example to match a C<page> parameter with an optional C<order_by> parameter one
9b9866ae 537would write:
538
bb07abdc 539 '?page=&order_by~' => sub {
eb9e0e25 540 my ($self, $page, $order_by) = @_;
541 return unless $page =~ /^\d+$/;
6753ac7a 542 $order_by ||= 'id';
9b9866ae 543 response_filter {
6753ac7a 544 $_[1]->search_rs({}, { page => $page, order_by => $order_by });
9b9866ae 545 }
546 }
547
548to implement paging and ordering against a L<DBIx::Class::ResultSet> object.
549
3895385d 550Another Example: To get all parameters as a hashref of arrayrefs, write:
eb9e0e25 551
bb07abdc 552 '?@*' => sub {
eb9e0e25 553 my ($self, $params) = @_;
554 ...
555
8c4ffad3 556To get two parameters as a hashref, write:
557
bb07abdc 558 '?:user~&:domain~' => sub {
8c4ffad3 559 my ($self, $params) = @_; # params contains only 'user' and 'domain' keys
560
561You can also mix these, so:
562
bb07abdc 563 '?foo=&@bar~&:coffee=&@*' => sub {
564 my ($self, $foo, $bar, $params) = @_;
8c4ffad3 565
566where $bar is an arrayref (possibly an empty one), and $params contains
65e03df0 567arrayref values for all parameters B<not> mentioned and a scalar value for
8c4ffad3 568the 'coffee' parameter.
569
3895385d 570Note, in the case where you combine arrayref, single parameter and named
571hashref style, the arrayref and single parameters will appear in C<@_> in the
38d5b336 572order you defined them in the protoype, but all hashrefs will merge into a
3895385d 573single C<$params>, as in the example above.
574
1d2f4b67 575=head3 Upload matches
05aafc1a 576
bb07abdc 577 '*foo=' => sub { # param specifier can be anything valid for query or body
05aafc1a 578
579The upload match system functions exactly like a query/body match, except
580that the values returned (if any) are C<Web::Dispatch::Upload> objects.
581
582Note that this match type will succeed in two circumstances where you might
583not expect it to - first, when the field exists but is not an upload field
584and second, when the field exists but the form is not an upload form (i.e.
585content type "application/x-www-form-urlencoded" rather than
586"multipart/form-data"). In either of these cases, what you'll get back is
587a C<Web::Dispatch::NotAnUpload> object, which will C<die> with an error
588pointing out the problem if you try and use it. To be sure you have a real
589upload object, call
590
591 $upload->is_upload # returns 1 on a valid upload, 0 on a non-upload field
592
593and to get the reason why such an object is not an upload, call
594
595 $upload->reason # returns a reason or '' on a valid upload.
596
597Other than these two methods, the upload object provides the same interface
598as L<Plack::Request::Upload> with the addition of a stringify to the temporary
599filename to make copying it somewhere else easier to handle.
600
81a5b03e 601=head3 Combining matches
602
15dfe701 603Matches may be combined with the + character - e.g.
604
bb07abdc 605 'GET + /user/*' => sub {
b8bd7bd1 606
607to create an AND match. They may also be combined withe the | character - e.g.
608
bb07abdc 609 'GET|POST' => sub {
b8bd7bd1 610
611to create an OR match. Matches can be nested with () - e.g.
612
bb07abdc 613 '(GET|POST + /user/*)' => sub {
b8bd7bd1 614
615and negated with ! - e.g.
616
bb07abdc 617 '!/user/foo + /user/*' => sub {
b8bd7bd1 618
619! binds to the immediate rightmost match specification, so if you want
620to negate a combination you will need to use
621
bb07abdc 622 '!(POST|PUT|DELETE)' => sub {
b8bd7bd1 623
624and | binds tighter than +, so
625
bb07abdc 626 '(GET|POST) + /user/*' => sub {
b8bd7bd1 627
628and
629
bb07abdc 630 'GET|POST + /user/*' => sub {
b8bd7bd1 631
632are equivalent, but
633
bb07abdc 634 '(GET + /admin/...) | (POST + /admin/...)' => sub {
b8bd7bd1 635
636and
637
bb07abdc 638 'GET + /admin/... | POST + /admin/...' => sub {
b8bd7bd1 639
640are not - the latter is equivalent to
641
bb07abdc 642 'GET + (/admin/...|POST) + /admin/...' => sub {
b8bd7bd1 643
3895385d 644which will never match!
b8bd7bd1 645
646=head3 Whitespace
15dfe701 647
65e03df0 648Note that for legibility you are permitted to use whitespace:
15dfe701 649
bb07abdc 650 'GET + /user/*' => sub {
15dfe701 651
b8bd7bd1 652but it will be ignored. This is because the perl parser strips whitespace
653from subroutine prototypes, so this is equivalent to
654
bb07abdc 655 'GET+/user/*' => sub {
15dfe701 656
1fc9b979 657=head3 Accessing parameters via C<%_>
658
659If your dispatch specification causes your dispatch subroutine to receive
660a hash reference as its first argument, the contained named parameters
661will be accessible via C<%_>.
662
65e03df0 663This can be used to access your path matches, if they are named:
1fc9b979 664
bb07abdc 665 'GET + /foo/:path_part' => sub {
1fc9b979 666 [ 200,
667 ['Content-type' => 'text/plain'],
668 ["We are in $_{path_part}"],
669 ];
670 }
671
672Or, if your first argument would be a hash reference containing named
673query parameters:
674
bb07abdc 675 'GET + /foo + ?:some_param=' => sub {
1fc9b979 676 [ 200,
677 ['Content-type' => 'text/plain'],
678 ["We received $_{some_param} as parameter"],
679 ];
680 }
681
682Of course this also works when all you are doing is slurping the whole set
683of parameters by their name:
684
bb07abdc 685 'GET + /foo + ?*' => sub {
1fc9b979 686 [ 200,
687 ['Content-type' => 'text/plain'],
688 [exists($_{foo}) ? "Received a foo: $_{foo}" : "No foo!"],
689 ],
690 }
691
65e03df0 692Note that only the first hash reference will be available via C<%_>. If
1fc9b979 693you receive additional hash references, you will need to access them as
694usual.
695
24175cb5 696=head3 Accessing the PSGI env hash
697
3706e2a0 698In some cases you may wish to get the raw PSGI env hash - to do this,
65e03df0 699you can either use a plain sub:
3706e2a0 700
701 sub {
702 my ($env) = @_;
703 ...
704 }
24175cb5 705
65e03df0 706or use the C<PSGI_ENV> constant exported to retrieve it from C<@_>:
c21c9f07 707
bb07abdc 708 'GET + /foo + ?some_param=' => sub {
3706e2a0 709 my $param = $_[1];
710 my $env = $_[PSGI_ENV];
711 }
c21c9f07 712
3706e2a0 713but note that if you're trying to add a middleware, you should simply use
714Web::Simple's direct support for doing so.
c21c9f07 715
445b3ea0 716=head1 EXPORTED SUBROUTINES
c21c9f07 717
718=head2 response_filter
719
720 response_filter {
721 # Hide errors from the user because we hates them, preciousss
445b3ea0 722 if (ref($_[0]) eq 'ARRAY' && $_[0]->[0] == 500) {
723 $_[0] = [ 200, @{$_[0]}[1..$#{$_[0]}] ];
c21c9f07 724 }
445b3ea0 725 return $_[0];
c21c9f07 726 };
727
728The response_filter subroutine is designed for use inside dispatch subroutines.
729
730It creates and returns a special dispatcher that always matches, and calls
731the block passed to it as a filter on the result of running the rest of the
732current dispatch chain.
733
734Thus the filter above runs further dispatch as normal, but if the result of
735dispatch is a 500 (Internal Server Error) response, changes this to a 200 (OK)
736response without altering the headers or body.
737
738=head2 redispatch_to
739
740 redispatch_to '/other/url';
741
742The redispatch_to subroutine is designed for use inside dispatch subroutines.
743
744It creates and returns a special dispatcher that always matches, and instead
745of continuing dispatch re-delegates it to the start of the dispatch process,
746but with the path of the request altered to the supplied URL.
747
65e03df0 748Thus if you receive a POST to C</some/url> and return a redispatch to
749C</other/url>, the dispatch behaviour will be exactly as if the same POST
750request had been made to C</other/url> instead.
c21c9f07 751
3895385d 752Note, this is not the same as returning an HTTP 3xx redirect as a response;
38d5b336 753rather it is a much more efficient internal process.
3895385d 754
8c4ffad3 755=head1 CHANGES BETWEEN RELEASES
445b3ea0 756
757=head2 Changes between 0.004 and 0.005
758
759=over 4
760
761=item * dispatch {} replaced by declaring a dispatch_request method
762
763dispatch {} has gone away - instead, you write:
764
765 sub dispatch_request {
e4122532 766 my $self = shift;
bb07abdc 767 (
768 'GET /foo/' => sub { ... },
769 ...
770 );
445b3ea0 771 }
772
65e03df0 773Note that this method is still B<returning> the dispatch code - just like
774C<dispatch> did.
445b3ea0 775
65e03df0 776Also note that you need the C<< my $self = shift >> since the magic $self
e4122532 777variable went away.
778
779=item * the magic $self variable went away.
780
65e03df0 781Just add C<< my $self = shift; >> while writing your C<< sub dispatch_request { >>
e4122532 782like a normal perl method.
783
445b3ea0 784=item * subdispatch deleted - all dispatchers can now subdispatch
785
786In earlier releases you needed to write:
787
788 subdispatch sub (/foo/...) {
789 ...
790 [
791 sub (GET /bar/) { ... },
792 ...
793 ]
794 }
795
796As of 0.005, you can instead write simply:
797
798 sub (/foo/...) {
799 ...
800 (
801 sub (GET /bar/) { ... },
802 ...
803 )
804 }
8c4ffad3 805
c2150f7d 806=back
807
8c4ffad3 808=head2 Changes since Antiquated Perl
809
810=over 4
811
812=item * filter_response renamed to response_filter
813
814This is a pure rename; a global search and replace should fix it.
815
c21c9f07 816=item * dispatch [] changed to dispatch {}
8c4ffad3 817
818Simply changing
819
820 dispatch [ sub(...) { ... }, ... ];
821
822to
823
824 dispatch { sub(...) { ... }, ... };
825
826should work fine.
827
828=back
829
fb771406 830=head1 DEVELOPMENT HISTORY
831
832Web::Simple was originally written to form part of my Antiquated Perl talk for
833Italian Perl Workshop 2009, but in writing the bloggery example I realised
834that having a bare minimum system for writing web applications that doesn't
835drive me insane was rather nice and decided to spend my attempt at nanowrimo
836for 2009 improving and documenting it to the point where others could use it.
837
58fd1f7f 838The Antiquated Perl talk can be found at L<http://www.shadowcat.co.uk/archive/conference-video/> and the slides are reproduced in this distribution under
839L<Web::Simple::AntiquatedPerl>.
fb771406 840
8c4ffad3 841=head1 COMMUNITY AND SUPPORT
842
843=head2 IRC channel
844
845irc.perl.org #web-simple
846
847=head2 No mailing list yet
848
849Because mst's non-work email is a bombsite so he'd never read it anyway.
850
851=head2 Git repository
852
853Gitweb is on http://git.shadowcat.co.uk/ and the clone URL is:
854
855 git clone git://git.shadowcat.co.uk/catagits/Web-Simple.git
856
857=head1 AUTHOR
858
c2150f7d 859Matt S. Trout (mst) <mst@shadowcat.co.uk>
8c4ffad3 860
861=head1 CONTRIBUTORS
862
48904f80 863Devin Austin (dhoss) <dhoss@cpan.org>
864
865Arthur Axel 'fREW' Schmidt <frioux@gmail.com>
866
c2150f7d 867gregor herrmann (gregoa) <gregoa@debian.org>
8c4ffad3 868
48904f80 869John Napiorkowski (jnap) <jjn1056@yahoo.com>
870
871Josh McMichael <jmcmicha@linus222.gsc.wustl.edu>
872
f42be65c 873Justin Hunter (arcanez) <justin.d.hunter@gmail.com>
48904f80 874
875Kjetil Kjernsmo <kjetil@kjernsmo.net>
876
877markie <markie@nulletch64.dreamhost.com>
878
879Christian Walde (Mithaldu) <walde.christian@googlemail.com>
880
881nperez <nperez@cpan.org>
882
883Robin Edwards <robin.ge@gmail.com>
884
3c39d241 885Andrew Rodland (hobbs) <andrew@cleverdomain.org>
886
c18a76d1 887Robert Sedlacek (phaylon) <r.sedlacek@shadowcat.co.uk>
888
73349c50 889Hakim Cassimally (osfameron) <osfameron@cpan.org>
890
a0411ab3 891Karen Etheridge (ether) <ether@cpan.org>
892
8c4ffad3 893=head1 COPYRIGHT
894
f42be65c 895Copyright (c) 2011 the Web::Simple L</AUTHOR> and L</CONTRIBUTORS>
8c4ffad3 896as listed above.
897
898=head1 LICENSE
899
900This library is free software and may be distributed under the same terms
901as perl itself.
902
3583ca04 903=cut