If you save this file into your cgi-bin as hello-world.cgi and then visit:

http://my.server.name/cgi-bin/hello-world.cgi/

you'll get the "Hello world!" string output to your browser. At the same time this file will also act as a class module, so you can save it as HelloWorld.pm and use it as-is in test scripts or other deployment mechanisms.

Note that you should retain the ->run_if_script even if your app is a module, since this additionally makes it valid as a .psgi file, which can be extremely useful during development.

For more complex examples and non-CGI deployment, see Web::Simple::Deployment. To get help with Web::Simple, please connect to the irc.perl.org IRC network and join #web-simple.

DESCRIPTION

The philosophy of Web::Simple is to keep to an absolute bare minimum for everything. It is not designed to be used for large scale applications; the Catalyst web framework already works very nicely for that and is a far more mature, well supported piece of software.

However, if you have an application that only does a couple of things, and want to not have to think about complexities of deployment, then Web::Simple might be just the thing for you.

The only public interface the Web::Simple module itself provides is an import based one:

use Web::Simple 'NameOfApplication';

This sets up your package (in this case "NameOfApplication" is your package) so that it inherits from Web::Simple::Application and imports strictures, as well as installs a PSGI_ENV constant for convenience, as well as some other subroutines.

Importing strictures will automatically make your code use the strict and warnings pragma, so you can skip the usual:

use strict;
use warnings FATAL => 'aa';

provided you 'use Web::Simple' at the top of the file. Note that we turn on *fatal* warnings so if you have any warnings at any point from the file that you did 'use Web::Simple' in, then your application will die. This is, so far, considered a feature.

At the end of your app is that this call will create an instance of your app for you automatically, regardless of context. An easier way to think of this would be if the method were more verbosely named

NameOfApplication->run_request_if_script_else_turn_coderef_for_psgi;

DISPATCH STRATEGY

Web::Simple despite being straightforward to use, has a powerful system for matching all sorts of incoming URLs to one or more subroutines. These subroutines can be simple actions to take for a given URL, or something more complicated, including entire Plack applications, Plack::Middleware and nested subdispatchers.

The dispatch cycle

At the beginning of a request, your app's dispatch_request method is called with the PSGI $env as an argument. You can handle the request entirely in here and return a PSGI response arrayref if you want:

If you return a subroutine with a prototype, the prototype is treated as a match specification - and if the test is passed, the body of the sub is called as a method and passed any matched arguments (see below for more details).

You can also return a plain subroutine which will be called with just $env - remember that in this case if you need $self you must close over it.

If you return a normal object, Web::Simple will simply return it upwards on the assumption that a response_filter (or some arbitrary Plack::Middleware) somewhere will convert it to something useful. This allows:

This can be useful in situations where you are generating a dispatch table programmatically, where setting a subroutines protoype is difficult. Note that in the example above, handle_post is a method that would be called.

to render a user object to HTML, if there is an incoming URL such as:

http://myweb.org/user/111.html

This works because as we descend down the dispachers, we first match sub (.html), which adds a response_filter (basically a specialized routine that follows the Plack::Middleware specification), and then later we also match sub (/user/*) which gets a user and returns that as the response. This user object 'bubbles up' through all the wrapping middleware until it hits the response_filter we defined, after which the return is converted to a true html response.

However, two types of objects are treated specially - a Plack::Component object will have its to_app method called and be used as a dispatcher:

And that's it - but remember that all this happens recursively - it's dispatchers all the way down. A URL incoming pattern will run all matching dispatchers and then hit all added filters or Plack::Middleware.

Web::Simple match specifications

Method matches

sub (GET) {

A match specification beginning with a capital letter matches HTTP requests with that request method.

Path matches

sub (/login) {

A match specification beginning with a / is a path match. In the simplest case it matches a specific path. To match a path with a wildcard part, you can do:

sub (/user/*) {
$self->handle_user($_[1])

This will match /user/<anything> where <anything> does not include a literal / character. The matched part becomes part of the match arguments. You can also match more than one part:

This will result in a single element for the entire match. Note that you can do

sub (/page/**/edit) {

to match an arbitrary number of parts up to but not including some final part.

Note: Since Web::Simple handles a concept of file extensions, * and ** matchers will not by default match things after a final dot, and this can be modified by using *.* and **.* in the final position, e.g.:

Will match /foo/ on the beginning of the path and strip it. This is designed to be used to construct nested dispatch structures, but can also prove useful for having e.g. an optional language specification at the start of a path.

Note that the '...' is a "maybe something here, maybe not" so the above specification will match like this:

Please note the difference between sub(/foo/...) and sub(/foo...). In the first case, this is expecting to find something after /foo (and fails to match if nothing is found), while in the second case we can match both /foo and /foo/more/to/come. The following are roughly the same:

/foo and /foo/ are different specs

As you may have noticed with the difference between sub(/foo/...) and sub(/foo...), trailing slashes in path specs are significant. This is intentional and necessary to retain the ability to use relative links on websites. Let's demonstrate on this link:

<a href="bar">bar</a>

If the user loads the url /foo/ and clicks on this link, they will be sent to /foo/bar. However when they are on the url /foo and click this link, then they will be sent to /bar.

This makes it necessary to be explicit about the trailing slash.

Extension matches

sub (.html) {

will match .html from the path (assuming the subroutine itself returns something, of course). This is normally used for rendering - e.g.:

sub (.html) {
response_filter { $self->render_html($_[1]) }
}

Additionally,

sub (.*) {

will match any extension and supplies the extension as a match argument.

separated by the & character. The arguments added to the request are one per non-:/* parameter (scalar for normal, arrayref for multiple), plus if any :/* specs exist a hashref containing those values.

Please note that if you specify a multiple type parameter match, you are ensured of getting an arrayref for the value, EVEN if the current incoming request has only one value. However if a parameter is specified as single and multiple values are found, the last one will be used.

For example to match a page parameter with an optional order_by parameter one would write:

where $bar is an arrayref (possibly an empty one), and $params contains arrayref values for all parameters not mentioned and a scalar value for the 'coffee' parameter.

Note, in the case where you combine arrayref, single parameter and named hashref style, the arrayref and single parameters will appear in @_ in the order you defined them in the protoype, but all hashrefs will merge into a single $params, as in the example above.

Upload matches

The upload match system functions exactly like a query/body match, except that the values returned (if any) are Web::Dispatch::Upload objects.

Note that this match type will succeed in two circumstances where you might not expect it to - first, when the field exists but is not an upload field and second, when the field exists but the form is not an upload form (i.e. content type "application/x-www-form-urlencoded" rather than "multipart/form-data"). In either of these cases, what you'll get back is a Web::Dispatch::NotAnUpload object, which will die with an error pointing out the problem if you try and use it. To be sure you have a real upload object, call

$upload->is_upload # returns 1 on a valid upload, 0 on a non-upload field

and to get the reason why such an object is not an upload, call

$upload->reason # returns a reason or '' on a valid upload.

Other than these two methods, the upload object provides the same interface as Plack::Request::Upload with the addition of a stringify to the temporary filename to make copying it somewhere else easier to handle.

Combining matches

Matches may be combined with the + character - e.g.

sub (GET + /user/*) {

to create an AND match. They may also be combined withe the | character - e.g.

sub (GET|POST) {

to create an OR match. Matches can be nested with () - e.g.

sub ((GET|POST) + /user/*) {

and negated with ! - e.g.

sub (!/user/foo + /user/*) {

! binds to the immediate rightmost match specification, so if you want to negate a combination you will need to use

sub ( !(POST|PUT|DELETE) ) {

and | binds tighter than +, so

sub ((GET|POST) + /user/*) {

and

sub (GET|POST + /user/*) {

are equivalent, but

sub ((GET + /admin/...) | (POST + /admin/...)) {

and

sub (GET + /admin/... | POST + /admin/...) {

are not - the latter is equivalent to

sub (GET + (/admin/...|POST) + /admin/...) {

which will never match!

Whitespace

Note that for legibility you are permitted to use whitespace:

sub (GET + /user/*) {

but it will be ignored. This is because the perl parser strips whitespace from subroutine prototypes, so this is equivalent to

sub (GET+/user/*) {

Accessing parameters via %_

If your dispatch specification causes your dispatch subroutine to receive a hash reference as its first argument, the contained named parameters will be accessible via %_.

response_filter

The response_filter subroutine is designed for use inside dispatch subroutines.

It creates and returns a special dispatcher that always matches, and calls the block passed to it as a filter on the result of running the rest of the current dispatch chain.

Thus the filter above runs further dispatch as normal, but if the result of dispatch is a 500 (Internal Server Error) response, changes this to a 200 (OK) response without altering the headers or body.

redispatch_to

redispatch_to '/other/url';

The redispatch_to subroutine is designed for use inside dispatch subroutines.

It creates and returns a special dispatcher that always matches, and instead of continuing dispatch re-delegates it to the start of the dispatch process, but with the path of the request altered to the supplied URL.

Thus if you receive a POST to /some/url and return a redispatch to /other/url, the dispatch behaviour will be exactly as if the same POST request had been made to /other/url instead.

Note, this is not the same as returning an HTTP 3xx redirect as a response; rather it is a much more efficient internal process.

DEVELOPMENT HISTORY

Web::Simple was originally written to form part of my Antiquated Perl talk for Italian Perl Workshop 2009, but in writing the bloggery example I realised that having a bare minimum system for writing web applications that doesn't drive me insane was rather nice and decided to spend my attempt at nanowrimo for 2009 improving and documenting it to the point where others could use it.

As a valued partner and proud supporter of MetaCPAN, StickerYou is
happy to offer a 10% discount on all Custom Stickers,
Business Labels, Roll Labels,
Vinyl Lettering or Custom Decals. StickerYou.com
is your one-stop shop to make your business stick.
Use code METACPAN10 at checkout to apply your discount.