5 use warnings::illegalproto ();
7 our $VERSION = '0.004';
10 my ($class, $app_package) = @_;
11 $class->_export_into($app_package||caller);
12 eval "package $class; use Moo;";
13 warnings::illegalproto->unimport;
17 my ($class, $app_package) = @_;
20 *{"${app_package}::dispatch"} = sub (&) {
21 $app_package->_setup_dispatcher($_[0]);
23 *{"${app_package}::response_filter"} = sub (&) {
24 $app_package->_construct_response_filter($_[0]);
26 *{"${app_package}::redispatch_to"} = sub {
27 $app_package->_construct_redispatch($_[0]);
29 *{"${app_package}::default_config"} = sub {
30 $app_package->_setup_default_config(@_);
32 *{"${app_package}::PSGI_ENV"} = sub () { -1 };
33 *{"${app_package}::self"} = \${"${app_package}::self"};
34 require Web::Simple::Application;
35 unshift(@{"${app_package}::ISA"}, 'Web::Simple::Application');
37 (my $name = $app_package) =~ s/::/\//g;
38 $INC{"${name}.pm"} = 'Set by "use Web::Simple;" invocation';
43 Web::Simple - A quick and easy way to build simple web applications
47 This is really quite new. If you're reading this on CPAN, it means the stuff
48 that's here we're probably happy with. But only probably. So we may have to
49 change stuff. And if you're reading this from git, come check with irc.perl.org
50 #web-simple that we're actually sure we're going to keep anything that's
51 different from the CPAN version.
53 If we do find we have to change stuff we'll add to the
54 L<CHANGES BETWEEN RELEASES> section explaining how to switch your code across
55 to the new version, and we'll do our best to make it as painless as possible
56 because we've got Web::Simple applications too. But we can't promise not to
57 change things at all. Not yet. Sorry.
63 use Web::Simple 'HelloWorld';
70 [ 200, [ 'Content-type', 'text/plain' ], [ 'Hello world!' ] ]
73 [ 405, [ 'Content-type', 'text/plain' ], [ 'Method not allowed' ] ]
78 HelloWorld->run_if_script;
80 If you save this file into your cgi-bin as hello-world.cgi and then visit
82 http://my.server.name/cgi-bin/hello-world.cgi/
84 you'll get the "Hello world!" string output to your browser. For more complex
85 examples and non-CGI deployment, see below. To get help with Web::Simple,
86 please connect to the irc.perl.org IRC network and join #web-simple.
90 Web::Simple was originally written to form part of my Antiquated Perl talk for
91 Italian Perl Workshop 2009, but in writing the bloggery example I realised
92 that having a bare minimum system for writing web applications that doesn't
93 drive me insane was rather nice and decided to spend my attempt at nanowrimo
94 for 2009 improving and documenting it to the point where others could use it.
96 The philosophy of Web::Simple is to keep to an absolute bare minimum, for
97 everything. It is not designed to be used for large scale applications;
98 the L<Catalyst> web framework already works very nicely for that and is
99 a far more mature, well supported piece of software.
101 However, if you have an application that only does a couple of things, and
102 want to not have to think about complexities of deployment, then Web::Simple
103 might be just the thing for you.
105 The Antiquated Perl talk can be found at L<http://www.shadowcat.co.uk/archive/conference-video/>.
109 The only public interface the Web::Simple module itself provides is an
112 use Web::Simple 'NameOfApplication';
114 This imports 'strict' and 'warnings FATAL => "all"' into your code as well,
115 so you can skip the usual
120 provided you 'use Web::Simple' at the top of the file. Note that we turn
121 on *fatal* warnings so if you have any warnings at any point from the file
122 that you did 'use Web::Simple' in, then your application will die. This is,
123 so far, considered a feature.
125 Calling the import also makes NameOfApplication isa Web::Simple::Application
126 - i.e. does the equivalent of
129 package NameOfApplication;
130 use base qw(Web::Simple::Application);
133 It also exports the following subroutines:
140 dispatch { sub (...) { ... }, ... };
142 response_filter { ... };
144 redispatch_to '/somewhere';
146 subdispatch sub (...) { ... }
148 and creates a $self global variable in your application package, so you can
149 use $self in dispatch subs without violating strict (Web::Simple::Application
150 arranges for dispatch subroutines to have the correct $self in scope when
155 $INC{"NameOfApplication.pm"} = 'Set by "use Web::Simple;" invocation';
157 so that perl will not attempt to load the application again even if
159 require NameOfApplication;
161 is encountered in other code.
163 =head1 DISPATCH STRATEGY
168 # matches: GET /user/1.htm?show_details=1
170 sub (GET + /user/* + ?show_details~ + .htm|.html|.xhtml) {
171 my ($self, $user_id, $show_details) = @_;
174 # matches: POST /user?username=frew
175 # POST /user?username=mst&first_name=matt&last_name=trout
176 sub (POST + /user + ?username=&*) {
177 my ($self, $username, $misc_params) = @_;
180 # matches: DELETE /user/1/friend/2
181 sub (DELETE + /user/*/friend/*) {
182 my ($self, $user_id, $friend_id) = @_;
185 # matches: PUT /user/1?first_name=Matt&last_name=Trout
186 sub (PUT + /user/* + ?first_name~&last_name~) {
187 my ($self, $user_id, $first_name, $last_name) = @_;
194 # matches: PUT /user/1/role/1
195 sub (PUT + /role/*) {
199 # matches: DELETE /user/1/role/1
200 sub (DELETE + /role/*) {
209 =head2 Description of the dispatcher object
211 Web::Simple::Dispatcher objects have three components:
215 =item * match - an optional test if this dispatcher matches the request
217 =item * call - a routine to call if this dispatcher matches (or has no match)
219 =item * next - the next dispatcher to call
223 When a dispatcher is invoked, it checks its match routine against the
224 request environment. The match routine may provide alterations to the
225 request as a result of matching, and/or arguments for the call routine.
227 If no match routine has been provided then Web::Simple treats this as
228 a success, and supplies the request environment to the call routine as
231 Given a successful match, the call routine is now invoked in list context
232 with any arguments given to the original dispatch, plus any arguments
233 provided by the match result.
235 If this routine returns (), Web::Simple treats this identically to a failure
238 If this routine returns a Web::Simple::Dispatcher, the environment changes
239 are merged into the environment and the new dispatcher's next pointer is
240 set to our next pointer.
242 If this routine returns anything else, that is treated as the end of dispatch
243 and the value is returned.
245 On a failed match, Web::Simple invokes the next dispatcher with the same
246 arguments and request environment passed to the current one. On a successful
247 match that returned a new dispatcher, Web::Simple invokes the new dispatcher
248 with the same arguments but the modified request environment.
250 =head2 How Web::Simple builds dispatcher objects for you
252 In the case of the Web::Simple L</dispatch> export the match is constructed
253 from the subroutine prototype - i.e.
255 sub (<match specification>) {
259 and the 'next' pointer is populated with the next element of the array,
260 expect for the last element, which is given a next that will throw a 500
261 error if none of your dispatchers match. If you want to provide something
262 else as a default, a routine with no match specification always matches, so -
265 [ 404, [ 'Content-type', 'text/plain' ], [ 'Error: Not Found' ] ]
268 will produce a 404 result instead of a 500 by default. You can also override
269 the L<Web::Simple::Application/_build_final_dispatcher> method in your app.
271 Note that the code in the subroutine is executed as a -method- on your
272 application object, so if your match specification provides arguments you
273 should unpack them like so:
275 sub (<match specification>) {
276 my ($self, @args) = @_;
280 =head2 Web::Simple match specifications
282 =head3 Method matches
286 A match specification beginning with a capital letter matches HTTP requests
287 with that request method.
293 A match specification beginning with a / is a path match. In the simplest
294 case it matches a specific path. To match a path with a wildcard part, you
298 $self->handle_user($_[1])
300 This will match /user/<anything> where <anything> does not include a literal
301 / character. The matched part becomes part of the match arguments. You can
302 also match more than one part:
305 my ($self, $user_1, $user_2) = @_;
307 sub (/domain/*/user/*) {
308 my ($self, $domain, $user) = @_;
310 and so on. To match an arbitrary number of parts, use -
314 This will result in an element per /-separated part so matched. Note that
317 sub (/page/**/edit) {
319 to match an arbitrary number of parts up to but not including some final
326 will match /foo/ on the beginning of the path -and- strip it, much like
327 .html strips the extension. This is designed to be used to construct
328 nested dispatch structures, but can also prove useful for having e.g. an
329 optional language specification at the start of a path.
331 Note that the '...' is a "maybe something here, maybe not" so the above
332 specification will match like this:
335 /foo/ # match and strip path to '/'
336 /foo/bar/baz # match and strip path to '/bar/baz'
338 =head3 Extension matches
342 will match and strip .html from the path (assuming the subroutine itself
343 returns something, of course). This is normally used for rendering - e.g.
346 response_filter { $self->render_html($_[1]) }
353 will match any extension and supplies the stripped extension as a match
356 =head3 Query and body parameter matches
358 Query and body parameters can be match via
360 sub (?<param spec>) { # match URI query
361 sub (%<param spec>) { # match body params
363 The body is only matched if the content type is
364 application/x-www-form-urlencoded (note this means that Web::Simple does
365 not yet handle uploads; this will be addressed in a later release).
367 The param spec is elements of one of the following forms -
369 param~ # optional parameter
370 param= # required parameter
371 @param~ # optional multiple parameter
372 @param= # required multiple parameter
373 :param~ # optional parameter in hashref
374 :param= # required parameter in hashref
375 :@param~ # optional multiple in hashref
376 :@param= # required multiple in hashref
377 * # include all other parameters in hashref
378 @* # include all other parameters as multiple in hashref
380 separated by the & character. The arguments added to the request are
381 one per non-:/* parameter (scalar for normal, arrayref for multiple),
382 plus if any :/* specs exist a hashref containing those values.
384 So, to match a page parameter with an optional order_by parameter one
387 sub (?page=&order_by~) {
388 my ($self, $page, $order_by) = @_;
389 return unless $page =~ /^\d+$/;
392 $_[1]->search_rs({}, $p);
396 to implement paging and ordering against a L<DBIx::Class::ResultSet> object.
398 Note that if a parameter is specified as single and multiple values are found,
399 the last one will be used.
401 To get all parameters as a hashref of arrayrefs, write:
404 my ($self, $params) = @_;
407 To get two parameters as a hashref, write:
409 sub(?:user~&:domain~) {
410 my ($self, $params) = @_; # params contains only 'user' and 'domain' keys
412 You can also mix these, so:
414 sub (?foo=&@bar~&:coffee=&@*) {
415 my ($self, $foo, $bar, $params);
417 where $bar is an arrayref (possibly an empty one), and $params contains
418 arrayref values for all parameters -not- mentioned and a scalar value for
419 the 'coffee' parameter.
421 =head3 Combining matches
423 Matches may be combined with the + character - e.g.
425 sub (GET + /user/*) {
427 to create an AND match. They may also be combined withe the | character - e.g.
431 to create an OR match. Matches can be nested with () - e.g.
433 sub ((GET|POST) + /user/*) {
435 and negated with ! - e.g.
437 sub (!/user/foo + /user/*) {
439 ! binds to the immediate rightmost match specification, so if you want
440 to negate a combination you will need to use
442 sub ( !(POST|PUT|DELETE) ) {
444 and | binds tighter than +, so
446 sub ((GET|POST) + /user/*) {
450 sub (GET|POST + /user/*) {
454 sub ((GET + .html) | (POST + .html)) {
458 sub (GET + .html | POST + .html) {
460 are not - the latter is equivalent to
462 sub (GET + (.html|POST) + .html) {
464 which will never match.
468 Note that for legibility you are permitted to use whitespace -
470 sub (GET + /user/*) {
472 but it will be ignored. This is because the perl parser strips whitespace
473 from subroutine prototypes, so this is equivalent to
477 =head3 Accessing the PSGI env hash
479 To gain the benefit of using some middleware, specifically
480 Plack::Middleware::Session access to the ENV hash is needed. This is provided
481 in arguments to the dispatched handler. You can access this hash with the
482 exported +PSGI_ENV constant.
484 sub (GET + /foo + ?some_param=) {
485 my($self, $some_param, $env) = @_[0, 1, +PSGI_ENV];
487 =head1 EXPORTED SUBROUTINES
489 =head2 default_config
493 another_key => 'bar',
498 $self->config->{one_key} # 'foo'
500 This creates the default configuration for the application, by creating a
502 sub _default_config {
503 return (one_key => 'foo', another_key => 'bar');
506 in the application namespace when executed. Note that this means that
507 you should only run default_config once - calling it a second time will
508 cause an exception to be thrown.
514 [ 200, [ 'Content-type', 'text/plain' ], [ 'Hello world!' ] ]
517 [ 405, [ 'Content-type', 'text/plain' ], [ 'Method not allowed' ] ]
521 The dispatch subroutine calls NameOfApplication->_setup_dispatcher with
522 the return value of the block passed to it, which then creates your Web::Simple
523 application's dispatcher from these subs. The prototype of each subroutine
524 is expected to be a Web::Simple dispatch specification (see
525 L</DISPATCH SPECIFICATIONS> below for more details), and the body of the
526 subroutine is the code to execute if the specification matches.
528 Each dispatcher is given the dispatcher constructed from the next subroutine
529 returned as its next dispatcher, except for the final subroutine, which
530 is given the return value of NameOfApplication->_build_final_dispatcher
531 as its next dispatcher (by default this returns a 500 error response).
533 See L</DISPATCH STRATEGY> below for details on how the Web::Simple dispatch
534 system uses the return values of these subroutines to determine how to
535 continue, alter or abort dispatch.
537 Note that _setup_dispatcher creates a
540 return <root dispatcher object here>;
543 method in your class so as with default_config, calling dispatch a second time
544 will result in an exception.
546 =head2 response_filter
549 # Hide errors from the user because we hates them, preciousss
550 if (ref($_[1]) eq 'ARRAY' && $_[1]->[0] == 500) {
551 $_[1] = [ 200, @{$_[1]}[1..$#{$_[1]}] ];
556 The response_filter subroutine is designed for use inside dispatch subroutines.
558 It creates and returns a special dispatcher that always matches, and calls
559 the block passed to it as a filter on the result of running the rest of the
560 current dispatch chain.
562 Thus the filter above runs further dispatch as normal, but if the result of
563 dispatch is a 500 (Internal Server Error) response, changes this to a 200 (OK)
564 response without altering the headers or body.
568 redispatch_to '/other/url';
570 The redispatch_to subroutine is designed for use inside dispatch subroutines.
572 It creates and returns a special dispatcher that always matches, and instead
573 of continuing dispatch re-delegates it to the start of the dispatch process,
574 but with the path of the request altered to the supplied URL.
576 Thus if you receive a POST to '/some/url' and return a redipstch to
577 '/other/url', the dispatch behaviour will be exactly as if the same POST
578 request had been made to '/other/url' instead.
582 subdispatch sub (/user/*/) {
583 my $u = $self->user($_[1]);
586 sub (DELETE) { $u->delete },
590 The subdispatch subroutine is designed for use in dispatcher construction.
592 It creates a dispatcher which, if it matches, treats its return value not
593 as a final value but an arrayref of dispatch specifications such as could
594 be passed to the dispatch subroutine itself. These are turned into a dispatcher
595 which is then invoked. Any changes the match makes to the request are in
596 scope for this inner dispatcher only - so if the initial match is a
597 destructive one like .html the full path will be restored if the
600 =head1 CHANGES BETWEEN RELEASES
602 =head2 Changes since Antiquated Perl
606 =item * filter_response renamed to response_filter
608 This is a pure rename; a global search and replace should fix it.
610 =item * dispatch [] changed to dispatch {}
614 dispatch [ sub(...) { ... }, ... ];
618 dispatch { sub(...) { ... }, ... };
624 =head1 COMMUNITY AND SUPPORT
628 irc.perl.org #web-simple
630 =head2 No mailing list yet
632 Because mst's non-work email is a bombsite so he'd never read it anyway.
634 =head2 Git repository
636 Gitweb is on http://git.shadowcat.co.uk/ and the clone URL is:
638 git clone git://git.shadowcat.co.uk/catagits/Web-Simple.git
642 Matt S. Trout <mst@shadowcat.co.uk>
646 None required yet. Maybe this module is perfect (hahahahaha ...).
650 Copyright (c) 2009 the Web::Simple L</AUTHOR> and L</CONTRIBUTORS>
655 This library is free software and may be distributed under the same terms