Mark Stosberg | 16 Dec 04:13 2010
Picon

Proposed PSGI support for CGI::App, CGI::App::Dispatch, code moved to github


Hello,

I've now moved the CGI::Application and CGI::Application::Dispatch code
repos from darcs to git/github. You can access them here:

https://github.com/markstos/CGI--Application
https://github.com/markstos/CGI--Application--Dispatch/

I also have added proposed updates to both to add native PSGI support.
( More context about that is below ).

For CGI::Application, I proposed two methods be added. One,
"run_as_psgi()" returns the output in the format required by PSGI.
A second one, psgi_app(), makes creating a PSGI app a simple as it was
to call new(). The proposed POD for CGI::Application to explain both of
these is below.

For CGI::Application::Dispatch, I propose leaving
CGI::Application::Dispatch alone, and starting over with a clean,
implementation of CGI::Application::Dispatch::PSGI. The current
implementation inefficiently parses and regenerates headers, when it
can take advantage of the new native PSGI support to generate PSGI
headers correctly the first time. Plus the new implementation won't
have any of the Apache/Apache2 logic in the code line-- getting server
specific code out of your frameworks is one of the benefits of PSGI.

Please provide any feedback here, or through GitHub on these changes.

#####

Proposed docs for CGI::Appplication:

PSGI support
    CGI::Application offers native PSGI support. The default query object
    for this is CGI::PSGI, which simply wrappers CGI.pm to provide PSGI
    support to it.

   psgi_app()
     $psgi_coderef = WebApp->psgi_app({ ... args to new() ... });

    The simplest way to create and return a PSGI-compatible coderef. Pass in
    arguments to a hashref just as would to new. This return a
    PSGI-compatible coderef, using CGI:::PSGI as the query object. To use a
    different query object, construct your own object using "run_as_psgi()",
    as shown below.

    It's possible that we'll change from CGI::PSGI to a
    different-but-compatible query object for PSGI support in the future,
    perhaps if CGI.pm adds native PSGI support.

   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.

If you want to review this more on GitHub, make sure you are looking at
the PSGI-support branch:
https://github.com/markstos/CGI--Application/tree/psgi-support

##############################################################

CGI::Application::Dispatch::PSGI works essentially like the old
dispatcher. By outsourcing functionality to PSGI, the lines-code-count
was trimmed down by 33% !  For common cases, you can simply update your
existing code to catch the package name and rename dispatch() to
as_psgi().

Here's the part of the updated ::Dispatch pod which details the
differences:

Differences with CGI::Application::Dispatch
    new() - error_document argument
        Specifiying error documents internally is no longer supported. Use
        the Plack::Middleware::ErrorDocument or another PSGI solution
        instead.

    dispatch()
        Use "as_psgi()" instead.

    dispatch_path()
        The dispatch_path() method is not supported. The alternative is to
        reference "$env->{PATH_INFO}" which is available per the PSGI spec.

    handler()
        This provided an Apache-specific handler. Other PSGI components like
        Plack::Handler::Apache2 provide Apache handlers now instead.

    _http_method()
        This method has been eliminated. Check "$env->{REQUEST_METHOD}"
        directly instead.

    _parse_path()
        The private _parse_path() method now accepts an additional argument,
        the PSGI $env hash.

    _run_app()
        The private _run_app() method now accepts an additional argument,
        the PSGI $env hash.

    _r()
        This method has been eliminated. It does not apply in PSGI.

Note that the new ::Dispatch code depends on the new CGI::App code. It
can be found on github here:

https://github.com/markstos/CGI--Application--Dispatch/tree/psgi-support

More context about PSGI and CGI::App from a previous thread is below.

   Mark

####

On 02/12/2010 12:23 PM, Mark Stosberg wrote:
> 
> 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;
>     };
> 
> #######

#####  CGI::Application community mailing list  ################
##                                                            ##
##  To unsubscribe, or change your message delivery options,  ##
##  visit:  http://www.erlbaum.net/mailman/listinfo/cgiapp    ##
##                                                            ##
##  Web archive:   http://www.erlbaum.net/pipermail/cgiapp/   ##
##  Wiki:          http://cgiapp.erlbaum.net/                 ##
##                                                            ##
################################################################


Gmane