bump version
[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
75c8f1da 8our $VERSION = '0.033';
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),
6f0e017f 529plus if any C<:>/C<*> specs exist a hashref containing those values. If a
530parameter has no value, i.e. appears as '?foo&', a value of 1 will be
531captured.
9b9866ae 532
3895385d 533Please note that if you specify a multiple type parameter match, you are
534ensured of getting an arrayref for the value, EVEN if the current incoming
535request has only one value. However if a parameter is specified as single
536and multiple values are found, the last one will be used.
537
65e03df0 538For example to match a C<page> parameter with an optional C<order_by> parameter one
9b9866ae 539would write:
540
bb07abdc 541 '?page=&order_by~' => sub {
eb9e0e25 542 my ($self, $page, $order_by) = @_;
543 return unless $page =~ /^\d+$/;
6753ac7a 544 $order_by ||= 'id';
9b9866ae 545 response_filter {
6753ac7a 546 $_[1]->search_rs({}, { page => $page, order_by => $order_by });
9b9866ae 547 }
548 }
549
550to implement paging and ordering against a L<DBIx::Class::ResultSet> object.
551
3895385d 552Another Example: To get all parameters as a hashref of arrayrefs, write:
eb9e0e25 553
bb07abdc 554 '?@*' => sub {
eb9e0e25 555 my ($self, $params) = @_;
556 ...
557
8c4ffad3 558To get two parameters as a hashref, write:
559
bb07abdc 560 '?:user~&:domain~' => sub {
8c4ffad3 561 my ($self, $params) = @_; # params contains only 'user' and 'domain' keys
562
563You can also mix these, so:
564
bb07abdc 565 '?foo=&@bar~&:coffee=&@*' => sub {
566 my ($self, $foo, $bar, $params) = @_;
8c4ffad3 567
568where $bar is an arrayref (possibly an empty one), and $params contains
65e03df0 569arrayref values for all parameters B<not> mentioned and a scalar value for
8c4ffad3 570the 'coffee' parameter.
571
3895385d 572Note, in the case where you combine arrayref, single parameter and named
573hashref style, the arrayref and single parameters will appear in C<@_> in the
e139ce16 574order you defined them in the prototype, but all hashrefs will merge into a
3895385d 575single C<$params>, as in the example above.
576
1d2f4b67 577=head3 Upload matches
05aafc1a 578
bb07abdc 579 '*foo=' => sub { # param specifier can be anything valid for query or body
05aafc1a 580
581The upload match system functions exactly like a query/body match, except
582that the values returned (if any) are C<Web::Dispatch::Upload> objects.
583
584Note that this match type will succeed in two circumstances where you might
585not expect it to - first, when the field exists but is not an upload field
586and second, when the field exists but the form is not an upload form (i.e.
587content type "application/x-www-form-urlencoded" rather than
588"multipart/form-data"). In either of these cases, what you'll get back is
589a C<Web::Dispatch::NotAnUpload> object, which will C<die> with an error
590pointing out the problem if you try and use it. To be sure you have a real
591upload object, call
592
593 $upload->is_upload # returns 1 on a valid upload, 0 on a non-upload field
594
595and to get the reason why such an object is not an upload, call
596
597 $upload->reason # returns a reason or '' on a valid upload.
598
599Other than these two methods, the upload object provides the same interface
600as L<Plack::Request::Upload> with the addition of a stringify to the temporary
601filename to make copying it somewhere else easier to handle.
602
81a5b03e 603=head3 Combining matches
604
15dfe701 605Matches may be combined with the + character - e.g.
606
bb07abdc 607 'GET + /user/*' => sub {
b8bd7bd1 608
e139ce16 609to create an AND match. They may also be combined with the | character - e.g.
b8bd7bd1 610
bb07abdc 611 'GET|POST' => sub {
b8bd7bd1 612
613to create an OR match. Matches can be nested with () - e.g.
614
bb07abdc 615 '(GET|POST + /user/*)' => sub {
b8bd7bd1 616
617and negated with ! - e.g.
618
bb07abdc 619 '!/user/foo + /user/*' => sub {
b8bd7bd1 620
621! binds to the immediate rightmost match specification, so if you want
622to negate a combination you will need to use
623
bb07abdc 624 '!(POST|PUT|DELETE)' => sub {
b8bd7bd1 625
626and | binds tighter than +, so
627
bb07abdc 628 '(GET|POST) + /user/*' => sub {
b8bd7bd1 629
630and
631
bb07abdc 632 'GET|POST + /user/*' => sub {
b8bd7bd1 633
634are equivalent, but
635
bb07abdc 636 '(GET + /admin/...) | (POST + /admin/...)' => sub {
b8bd7bd1 637
638and
639
bb07abdc 640 'GET + /admin/... | POST + /admin/...' => sub {
b8bd7bd1 641
642are not - the latter is equivalent to
643
bb07abdc 644 'GET + (/admin/...|POST) + /admin/...' => sub {
b8bd7bd1 645
3895385d 646which will never match!
b8bd7bd1 647
648=head3 Whitespace
15dfe701 649
65e03df0 650Note that for legibility you are permitted to use whitespace:
15dfe701 651
bb07abdc 652 'GET + /user/*' => sub {
15dfe701 653
b8bd7bd1 654but it will be ignored. This is because the perl parser strips whitespace
655from subroutine prototypes, so this is equivalent to
656
bb07abdc 657 'GET+/user/*' => sub {
15dfe701 658
1fc9b979 659=head3 Accessing parameters via C<%_>
660
661If your dispatch specification causes your dispatch subroutine to receive
662a hash reference as its first argument, the contained named parameters
663will be accessible via C<%_>.
664
65e03df0 665This can be used to access your path matches, if they are named:
1fc9b979 666
bb07abdc 667 'GET + /foo/:path_part' => sub {
1fc9b979 668 [ 200,
669 ['Content-type' => 'text/plain'],
670 ["We are in $_{path_part}"],
671 ];
672 }
673
674Or, if your first argument would be a hash reference containing named
675query parameters:
676
bb07abdc 677 'GET + /foo + ?:some_param=' => sub {
1fc9b979 678 [ 200,
679 ['Content-type' => 'text/plain'],
680 ["We received $_{some_param} as parameter"],
681 ];
682 }
683
684Of course this also works when all you are doing is slurping the whole set
685of parameters by their name:
686
bb07abdc 687 'GET + /foo + ?*' => sub {
1fc9b979 688 [ 200,
689 ['Content-type' => 'text/plain'],
690 [exists($_{foo}) ? "Received a foo: $_{foo}" : "No foo!"],
691 ],
692 }
693
65e03df0 694Note that only the first hash reference will be available via C<%_>. If
1fc9b979 695you receive additional hash references, you will need to access them as
696usual.
697
24175cb5 698=head3 Accessing the PSGI env hash
699
3706e2a0 700In some cases you may wish to get the raw PSGI env hash - to do this,
65e03df0 701you can either use a plain sub:
3706e2a0 702
703 sub {
704 my ($env) = @_;
705 ...
706 }
24175cb5 707
65e03df0 708or use the C<PSGI_ENV> constant exported to retrieve it from C<@_>:
c21c9f07 709
bb07abdc 710 'GET + /foo + ?some_param=' => sub {
3706e2a0 711 my $param = $_[1];
712 my $env = $_[PSGI_ENV];
713 }
c21c9f07 714
3706e2a0 715but note that if you're trying to add a middleware, you should simply use
716Web::Simple's direct support for doing so.
c21c9f07 717
445b3ea0 718=head1 EXPORTED SUBROUTINES
c21c9f07 719
720=head2 response_filter
721
722 response_filter {
723 # Hide errors from the user because we hates them, preciousss
445b3ea0 724 if (ref($_[0]) eq 'ARRAY' && $_[0]->[0] == 500) {
725 $_[0] = [ 200, @{$_[0]}[1..$#{$_[0]}] ];
c21c9f07 726 }
445b3ea0 727 return $_[0];
c21c9f07 728 };
729
730The response_filter subroutine is designed for use inside dispatch subroutines.
731
732It creates and returns a special dispatcher that always matches, and calls
733the block passed to it as a filter on the result of running the rest of the
734current dispatch chain.
735
736Thus the filter above runs further dispatch as normal, but if the result of
737dispatch is a 500 (Internal Server Error) response, changes this to a 200 (OK)
738response without altering the headers or body.
739
740=head2 redispatch_to
741
742 redispatch_to '/other/url';
743
744The redispatch_to subroutine is designed for use inside dispatch subroutines.
745
746It creates and returns a special dispatcher that always matches, and instead
747of continuing dispatch re-delegates it to the start of the dispatch process,
748but with the path of the request altered to the supplied URL.
749
65e03df0 750Thus if you receive a POST to C</some/url> and return a redispatch to
751C</other/url>, the dispatch behaviour will be exactly as if the same POST
752request had been made to C</other/url> instead.
c21c9f07 753
3895385d 754Note, this is not the same as returning an HTTP 3xx redirect as a response;
38d5b336 755rather it is a much more efficient internal process.
3895385d 756
8c4ffad3 757=head1 CHANGES BETWEEN RELEASES
445b3ea0 758
759=head2 Changes between 0.004 and 0.005
760
761=over 4
762
763=item * dispatch {} replaced by declaring a dispatch_request method
764
765dispatch {} has gone away - instead, you write:
766
767 sub dispatch_request {
e4122532 768 my $self = shift;
bb07abdc 769 (
770 'GET /foo/' => sub { ... },
771 ...
772 );
445b3ea0 773 }
774
65e03df0 775Note that this method is still B<returning> the dispatch code - just like
776C<dispatch> did.
445b3ea0 777
65e03df0 778Also note that you need the C<< my $self = shift >> since the magic $self
e4122532 779variable went away.
780
781=item * the magic $self variable went away.
782
65e03df0 783Just add C<< my $self = shift; >> while writing your C<< sub dispatch_request { >>
e4122532 784like a normal perl method.
785
445b3ea0 786=item * subdispatch deleted - all dispatchers can now subdispatch
787
788In earlier releases you needed to write:
789
790 subdispatch sub (/foo/...) {
791 ...
792 [
793 sub (GET /bar/) { ... },
794 ...
795 ]
796 }
797
798As of 0.005, you can instead write simply:
799
800 sub (/foo/...) {
801 ...
802 (
803 sub (GET /bar/) { ... },
804 ...
805 )
806 }
8c4ffad3 807
c2150f7d 808=back
809
8c4ffad3 810=head2 Changes since Antiquated Perl
811
812=over 4
813
814=item * filter_response renamed to response_filter
815
816This is a pure rename; a global search and replace should fix it.
817
c21c9f07 818=item * dispatch [] changed to dispatch {}
8c4ffad3 819
820Simply changing
821
822 dispatch [ sub(...) { ... }, ... ];
823
824to
825
826 dispatch { sub(...) { ... }, ... };
827
828should work fine.
829
830=back
831
fb771406 832=head1 DEVELOPMENT HISTORY
833
834Web::Simple was originally written to form part of my Antiquated Perl talk for
835Italian Perl Workshop 2009, but in writing the bloggery example I realised
836that having a bare minimum system for writing web applications that doesn't
837drive me insane was rather nice and decided to spend my attempt at nanowrimo
838for 2009 improving and documenting it to the point where others could use it.
839
58fd1f7f 840The 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
841L<Web::Simple::AntiquatedPerl>.
fb771406 842
8c4ffad3 843=head1 COMMUNITY AND SUPPORT
844
845=head2 IRC channel
846
847irc.perl.org #web-simple
848
849=head2 No mailing list yet
850
851Because mst's non-work email is a bombsite so he'd never read it anyway.
852
853=head2 Git repository
854
855Gitweb is on http://git.shadowcat.co.uk/ and the clone URL is:
856
857 git clone git://git.shadowcat.co.uk/catagits/Web-Simple.git
858
859=head1 AUTHOR
860
c2150f7d 861Matt S. Trout (mst) <mst@shadowcat.co.uk>
8c4ffad3 862
863=head1 CONTRIBUTORS
864
48904f80 865Devin Austin (dhoss) <dhoss@cpan.org>
866
867Arthur Axel 'fREW' Schmidt <frioux@gmail.com>
868
c2150f7d 869gregor herrmann (gregoa) <gregoa@debian.org>
8c4ffad3 870
48904f80 871John Napiorkowski (jnap) <jjn1056@yahoo.com>
872
873Josh McMichael <jmcmicha@linus222.gsc.wustl.edu>
874
f42be65c 875Justin Hunter (arcanez) <justin.d.hunter@gmail.com>
48904f80 876
877Kjetil Kjernsmo <kjetil@kjernsmo.net>
878
879markie <markie@nulletch64.dreamhost.com>
880
881Christian Walde (Mithaldu) <walde.christian@googlemail.com>
882
883nperez <nperez@cpan.org>
884
885Robin Edwards <robin.ge@gmail.com>
886
3c39d241 887Andrew Rodland (hobbs) <andrew@cleverdomain.org>
888
c18a76d1 889Robert Sedlacek (phaylon) <r.sedlacek@shadowcat.co.uk>
890
73349c50 891Hakim Cassimally (osfameron) <osfameron@cpan.org>
892
a0411ab3 893Karen Etheridge (ether) <ether@cpan.org>
894
8c4ffad3 895=head1 COPYRIGHT
896
f42be65c 897Copyright (c) 2011 the Web::Simple L</AUTHOR> and L</CONTRIBUTORS>
8c4ffad3 898as listed above.
899
900=head1 LICENSE
901
902This library is free software and may be distributed under the same terms
903as perl itself.
904
3583ca04 905=cut