[cgiapp] RFC: first-class support for PSGI in CGI::Application

Mark Stosberg mark at summersault.com
Fri Feb 12 12:23:55 EST 2010


I have been following the development of PSGI and Plack closely [1], and I
recommend that CGI::Application provide first-class support for the PSGI
protocol.

  1. http://plackperl.org/

PSGI is a port of the WSGI protocol used by Python, which has already proven
successful in that language community. I see first-class support bringing the
following benefits to the CGI::Application community:

A. Access to additional web servers. I predict a rise in the trend of using
Pure-Perl web servers, and some of these are made explictly to work with
the PSGI protocol. Some recent exapmles include Starman [2] and Tatsumaki [3]
  2. http://github.com/miyagawa/Starman
  3. http://github.com/miyagawa/Tatsumaki
You might choose a Pure Perl web server to distribute a fully
standalone Perl application, or perhaps your static content is already handled by
another web server, and all your webserver needs to do is to efficiently integrate with
your Perl application.

B. Access to additional "middleware". Already there are dozens of published 
"Middleware" modules published that are available via PSGI. Some of these duplicate
features already provided by CGI::App plugins, but a number of them are novel. Review
the list for yourself:
    http://search.cpan.org/search?m=module&q=plack+middleware&s=1&n=100

C. Increased collaboration with other Perl frameworks. Because PSGI allows
sharing of servers and middleware across frameworks, the whole Perl ecosystem
benefits. Now Catalyst has Test::WWW::Mechanize::Catalyst and we have
Test::WWW::Mechanize::CGIApp. Both could usefully be replaced by
Test::WWW::Mechanize::PSGI, which already exists. Also, Plack provides a more
flexible alternative to CGI::Application::Server. To illustrate this
point, you may be aware of Smolder [4], a nice Smokebot server built on
CGI::Application, currently using CGI::Application::Server. This works
OK, but requires a number of manual changes if it want it to run on a
different webserver. A PSGI/Plack solution would make it easier to
deploy the application on more webservers.

###

You may have noticed, but there are already numerous modules available to help
run CGI::Application projects on PSGI:

  CGI::PSGI
  CGI::Application::PSGI
  CGI::Application::Emulate::PSGI
  CGI::Application::Dispatch::PSGI

So far, all of these have accomplished their goals without any modifications to
the CGI::Application core. And perhaps your head is already swimming trying to
guess why we need four modules to accomplish PSGI support, or how they all fit
together.

So, when I talk about proposing first-class support for PSGI, I'm
talking about making this much simpler than what's already possible. I
propose making small modifications to CGI::Application and
CGI::Application::Dispatch, which will essentially eliminate the need
for these three modules:

  CGI::Application::PSGI
  CGI::Application::Emulate::PSGI
  CGI::Application::Dispatch::PSGI

The change in CGI::Application would be a new simple "run_as_psgi()" method that returns
a result in the format required by the PSGI protocol.  I already have a working patch
for this in my darcs repo, and you can review the new POD for the method below.

As you may have noticed, I have been very conservative about adding anything
new to the CGI::Application core. Providing first-class support for PSGI is a
forward-looking change to support an open standard based on an
already-successful precedent.

Now is your chance to provide feedback about the possibility of adding PSGI
support to the CGI::Application core.

The POD for the new proposed method follows.

###

run_as_psgi

   my $psgi_aref = $webapp->run_as_psgi;

Just like "run", but prints no output and returns the data structure
required by the PSGI specification. Use this if you want to run the
application on top of a PSGI-compatible handler, such as Plack provides.

If you are just getting started, just use "run()". It's easy to switch
to using "run_as_psgi" later.

Why use "run_as_psgi()"? There are already solutions to run
CGI::Application-based projects on several web servers with dozens of
plugins. Running as a PSGI-compatible application provides the ability
to run on additional PSGI-compatible servers, as well as providing
access to all of the "Middleware" solutions available through the Plack
project.

The structure returned is an arrayref, containing the status code, an
arrayref of header key/values and an arrayref containing the body.

 [ 200, [ 'Content-Type' => 'text/html' ], [ $body ] ]

By default the body is a single scalar, but plugins may modify this to
return other value PSGI values. See "The Response" in PSGI for details
about the response format.

Note that calling "run_as_psgi" only handles the *output* portion of the
PSGI spec. to handle the input, you need to use a CGI.pm-like query
object that is PSGI-compliant, such as CGI::PSGI. This query object must
provide psgi_header and psgi_redirect methods.

The final result might look like this:

    use WebApp;
    use CGI::PSGI;

    my $handler = sub {
        my $env = shift;
        my $webapp = WebApp->new({ QUERY => CGI::PSGI->new($env) });
        $webapp->run_as_psgi;
    };

#######


-- 
http://mark.stosberg.com/





More information about the cgiapp mailing list