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