[Catalyst-commits] r14469 - in trunk/examples/CatalystAdvent/root:
. 2013
jnapiorkowski at dev.catalyst.perl.org
jnapiorkowski at dev.catalyst.perl.org
Mon Dec 2 02:42:17 GMT 2013
Author: jnapiorkowski
Date: 2013-12-02 02:42:17 +0000 (Mon, 02 Dec 2013)
New Revision: 14469
Added:
trunk/examples/CatalystAdvent/root/2013/
trunk/examples/CatalystAdvent/root/2013/01.pod
trunk/examples/CatalystAdvent/root/2013/02.pod
trunk/examples/CatalystAdvent/root/2013/03.pod
trunk/examples/CatalystAdvent/root/2013/04.pod
trunk/examples/CatalystAdvent/root/2013/05.pod
trunk/examples/CatalystAdvent/root/2013/06.pod
trunk/examples/CatalystAdvent/root/2013/07.pod
trunk/examples/CatalystAdvent/root/2013/08.pod
trunk/examples/CatalystAdvent/root/2013/09.pod
trunk/examples/CatalystAdvent/root/2013/10.pod
trunk/examples/CatalystAdvent/root/2013/11.pod
trunk/examples/CatalystAdvent/root/2013/12.pod
trunk/examples/CatalystAdvent/root/2013/13.pod
trunk/examples/CatalystAdvent/root/2013/14.pod
trunk/examples/CatalystAdvent/root/2013/15.pod
Log:
first 15 articles
Added: trunk/examples/CatalystAdvent/root/2013/01.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/01.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/01.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,172 @@
+=head1 Title
+
+Perl Catalyst in 2013 - The Year in Review!
+
+=head1 Overview
+
+Introduction to Advent 2013 and a review of all the things we accomplished.
+
+=head1 Welcome to Perl Catalyst Advent 2013!
+
+Its that time once again where the Perl hackers and stakeholders of various
+projects come together to congratulates themselves a bit for all the time and
+effort spent over the past year. So we review a bit, and we try to share our
+knowledge with people that are seeking to learn it. And we have a bit of fun
+at the same time!
+
+We need to remember that this is a time of year which is traditionally associated
+with giving gifts and receiving them graciously. But in a larger sense the gifts
+have already been sent along. Because for those of us involved in Free / Open
+source software, every act of participation is a gift. Whether you write code,
+fix documentation, submit test reports or just advocate on twitter, blogs, or
+whatever, you are gifting time and effort. That's in my mind one of the top
+gifts a person can give, since our time is one of our most precious and limited
+resources. To give that away is a pretty big deal in my book. And for those
+who choose Free / Open source, well I think its very cool to be part of a
+ethical movement like this whose focus is the betterment of all by working in
+common for those things with are common to all. Things like Perl, L<PSGI>,
+L<Moose> and of course lets not forget L<Catalyst>!
+
+So lets take a brief spin through the main events for L<Catalyst> in 2013!
+
+=head1 Main accomplishments
+
+Here's a brief rundown of some of the stuff that was added and changed in
+L<Catalyst> in 2013. This is just the highlights, you should checkout
+the Changes file for more details:
+
+L<https://metacpan.org/source/JJNAPIORK/Catalyst-Runtime-5.90051/Changes>
+
+=over 4
+
+=item HTTP Method Matching
+
+We added new action attributes that let you constrain on the expected HTTP
+method. For example:
+
+ sub start : ChainedParent
+ PathPrefix CaptureArgs(0) { }
+
+ sub list_users : Chained('start')
+ GET PathPart('') Args(0) { }
+
+ sub add_users : Chained('start')
+ POST PathPart('') Args(0) { }
+
+See L<Catalyst::Controller/GET> for more.
+
+=item Unicode in Core
+
+Just turn on the switch and you'll be sure to have greatly improved ability to
+handle utf8 encoding.
+
+ $c->config->{encoding} = 'UTF-8'
+
+=item Handle the PSGI writer object for more control on output
+
+Useful for streaming and working with event loops, or just for when you want
+more control on how content is returned.
+
+=item Support for accessing IO streams when allowed.
+
+Use this for when you want to do websockets or long polling.
+
+=item Support PSGI middleware in configuration
+
+Lets you declare middleware as part of your L<Catalyst> application
+
+=item Added 'global data handlers' for parsing request content
+
+Lets you handle more than classic form POST parameters. Yes, this mean
+L<Catalyst> now handlers JSON POST out of the box!
+
+=item Mount a PSGI response
+
+Now your actions can mount PSGI applications and return PSGI reponses
+directly. Great for when you want to graft into you L<Catalyst> application
+bits of other frameworks such as L<Web::Simple> or L<Web::Machine> (or even
+other L<Catalyst> applications.)
+
+=item Constrain Actions on HTTP Request Content-Type
+
+Lets you constrain an action to a particular HTTP request content type. This
+lets you have one action that handles form data and another that handles JSON.
+Useful for building web APIs and is a nice augmentation of what you get with
+L<Catalyst::Action::REST>
+
+=item Configuration flag to use Hash::MultiValue for Request Parameters
+
+Lets you use L<Hash::MultiValue> for query and body parameters, which can solve
+some situtations when you are not sure if incoming parameters are scalar or
+arrays. Very commonly used on other L<Plack> based systems.
+
+=back
+
+And there was a lot of under the hood stuff as well. We cleared out that nasty
+Regexp based dispatch stuff into its own repo (makes it easier to remove later on).
+We did a bunch of stuff to make sure we'd play nice with other Plack applications
+that L<Catalyst> might dispatch to (such as making sure input is properly
+buffered). Ether (who works with me at Campus Explorer) dug in deep and cleaned
+up some old and no longer good practice Moosisms (replacing them with new, shiny
+Moosey goodness). And quite a few people checked in docs and other improvements.
+
+Here's a nice chart of people that checked in code to the L<Catalyst> repo:
+
+L<https://github.com/perl-catalyst/catalyst-runtime/graphs/contributors?from=2013-01-01&to=2013-11-16&type=c>
+
+And that doesn't count people that checked in code to other important bits of
+the ecosystem. Lots of people contributed doc patches and fixes to stuff around
+the session and authentication as well. So '++' to all of you!
+
+Excited to learn more? Well, go check out the docs, ponder test cases and look
+forward to more upcoming advent articles where we hope to cover all this and
+more!
+
+=head1 Project management
+
+In order to facilitate more participation, we mirrored the main L<Catalyst> git
+repository over on Github (see: L<https://github.com/perl-catalyst/>). This
+repository mirrors the canonical repository which for the time being will remain
+on shadowgit (L<catagits at git.shadowcat.co.uk:Catalyst-Runtime.git>). And we
+setup TravisCI on the github repo in order to help us track problems with
+changes (thanks Chris Weyl L<https://metacpan.org/author/RSRCHBOY> for the help
+with that).
+
+In addition we setup a Questhub for helping us to track and discuss possible
+changes to L<Catalyst> (See L<http://questhub.io/realm/perl/explore/latest/tag/catalyst>)
+
+I've also tried to blog as much as possible, and be sure to announce the
+important bits on the mailing list and in many cases I've tried to make use of
+external sites like Reddit and social media.
+
+Lastly we tried to be a little more transparent regarding what we are targeting
+for L<Catalyst> changes. We had several named development cycles ( Zombie-boomstick,
+Sicilian-buttercup and Hamburg) which all had targeted goals, announcements,
+as much discussion as I could squeeze out of the community and retrospectives.
+
+I personally believe that open source works best when it works for all of us
+and the best way I can think to do that is to try and make everything as
+transparent as possible. I believe we succeeded in that, and I hope we can
+build on that into the coming year.
+
+=head1 Summary
+
+2013 was another big year for L<Catalyst>. We worked hard at making it even
+more flexible and useful out of the box by exposing more L<PSGI> and grafting
+in a few missing bits. I expect 2014 to be even a bigger year as we look hard
+at L<Catalyst> and try to find a strong direction that lets it remain the best
+full stack web application framework for Perl!
+
+=head1 For More Information
+
+CPAN: L<Catalyst>
+Github: L<https://github.com/perl-catalyst/>
+Code Repository: L<catagits at git.shadowcat.co.uk:Catalyst-Runtime.git>
+Questhub: L<http://questhub.io/realm/perl/explore/latest/tag/catalyst>
+Mailing List Info: L<http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst>
+
+=head1 Author
+
+Your Name <your at email.com> | IRC nick
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/02.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/02.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/02.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,278 @@
+=head1 Title
+
+Roll your own Catalyst Controller with Mooselike imports
+
+=head1 Overview
+
+Learn how to create a custom Catalyst base controller with Mooselike
+imported keywords and more.
+
+=head1 Introduction
+
+Most L<Catalyst> applications of a certain age and complexity have a lot of
+controllers. Quite often your controllers have excessive boilerplate code
+even before you add anything related to your business logic. Here's the
+canonical controller as often documented.
+
+ package MyApp::Controller::MyController;
+
+ use Moose;
+ use namespace::autoclean;
+
+ BEGIN { extends 'Catalyst::Controller' }
+
+ ## -- Your code
+
+ __PACKAGE__->meta->make_immutable
+
+I've always disliked how the C<extends> needs to be in a BEGIN block, which is
+a side effect of how L<MooseX::MethodAttributes> works with the existing code
+base as ported to L<Moose> several years ago. It just looks odd and is a
+surprise to people new (and even old) to the framework. People generally just
+cargo cult it.
+
+Additionally every action typically starts by shifting or slurping the same
+arguments:
+
+ sub my_action :Action {
+ my ($self, $c) = @_'
+ }
+
+And that's before you add in any of a number of things special to your logic.
+Is there anything we can do to centralize some of this boilerplate? And what
+if you like to use a handful of other syntax enhancing modules like
+L<Function::Parameters> or L<CatalystX::Syntax::Action>? If you wanted that,
+you'd end up with a controller something like:
+
+ package MyApp::Controller;
+
+ use Moose;
+ BEGIN { extends 'Catalyst::Controller' }
+
+ use Function::Parameters;
+ use CatalystX::Syntax::Action;
+ use namespace::autoclean;
+
+ ## -- You custom actions and methods
+
+ __PACKAGE__->meta->make_immutable;
+
+And doing this allows you to write a controller like this:
+
+ package MyApp::Controller::Root;
+
+ use Moose;
+ BEGIN { extends 'Catalyst::Controller' }
+
+ use Function::Parameters;
+ use CatalystX::Syntax::Action;
+ use namespace::autoclean;
+
+ has 'test_attribute' => (
+ is=>'ro',
+ default=>'example value');
+
+ method generate_helloworld { 'Hello world!' }
+
+ action helloworld : GET Path('/helloworld') {
+ $ctx->res->body( $self->generate_helloworld);
+ }
+
+ action echo($arg) : GET Path('/echo') Args(1) {
+ $ctx->res->body( $arg );
+ }
+
+ 1;
+
+=head1 Moose and Import::Into to the Rescue!
+
+Our goal is to take the controller example from above and reduce it so that
+you can just do:
+
+ package MyApp::Controller;
+
+ use MyApp::ControllerObject;
+
+ ## -- You custom actions and methods
+
+ __PACKAGE__->meta->make_immutable;
+
+This yields an example controller like so:
+
+ package MyApp::Controller::Root;
+
+ use MyApp::ControllerObject;
+
+ has 'test_attribute' => (
+ is=>'ro',
+ default=>'example value');
+
+ method generate_helloworld { 'Hello world!' }
+
+ action helloworld : GET Path('/helloworld') {
+ $ctx->res->body( $self->generate_helloworld);
+ }
+
+ action echo($arg) : GET Path('/echo') Args(1) {
+ $ctx->res->body( $arg );
+ }
+
+L<Catalyst> is build on L<Moose> so out of the box you get some built in
+features that allow you to create a custom Controller object class that slurps
+up everything you get with L<Moose> and allows you to add in whatever it is you
+like. along with L<Import::Into>'s consistent interface for importing features
+into your package, its very trivial to make a custom controller that does all
+we want (and can easily be extended to do much more, if you think that is wise).
+
+So, what would C<MyApp::ControllerObject> look like? Lets take a look a the
+full code and then do a walkdown:
+
+ package MyApp::ControllerObject;
+
+ use strict;
+ use warnings;
+
+ use Moose::Exporter;
+ use Import::Into;
+ use Module::Runtime;
+
+ my ($import, $unimport, $init_meta) =
+ Moose::Exporter->build_import_methods( also => ['Moose'] );
+
+ sub importables {
+ 'Function::Parameters',
+ 'CatalystX::Syntax::Action',
+ 'namespace::autoclean',
+ }
+
+ sub base_class { 'Catalyst::Controller' }
+
+ sub init_meta {
+ my ($class, @args) = @_;
+ Moose->init_meta( @args,
+ base_class => $class->base_class );
+ goto $init_meta if $init_meta;
+ }
+
+ sub import {
+ use_module($_)->import::into(scalar caller)
+ for shift->importables;
+ goto $import;
+ }
+
+ 1;
+
+So you can see there's not a lot of needed code to do this, mostly because of
+all the existing art that the L<Moose> cabal put into making extending L<Moose>
+easy, and because of the wonder clean, consistent API that L<Import::Into>
+gives you. Let's take it again from the top:
+
+ package MyApp::ControllerObject;
+
+ use strict;
+ use warnings;
+
+ use Moose::Exporter;
+ use Import::Into;
+ use Module::Runtime;
+
+So we setup the module namespace and use three modules (plus the ever present
+L<strict> and L<warnings> pragmas) which brings in all the required functionality.
+L<Moose::Exporter> sets us up with a Moosey import and later on you will see
+it lets us import all the normal Moose goodies. L<Import::Info> provides a clean,
+consistent interface for importing a module features into a package other than
+your own (used to inject syntax and pragmas into a calling system). Lastly, we
+use L<Module::Runtime> to make it easy to dynamically load modules in running
+code.
+
+ my ($import, $unimport, $init_meta) =
+ Moose::Exporter->build_import_methods( also => ['Moose'] );
+
+Here we use L<Moose::Exporter> to build for use some coderefs to handle how to
+properly import and initialize L<Moose>
+
+ sub importables {
+ 'Function::Parameters',
+ 'CatalystX::Syntax::Action',
+ 'namespace::autoclean',
+ }
+
+ sub base_class { 'Catalyst::Controller' }
+
+Here's the features we want imported into our controllers, and the base controller
+we want to use. I wrote it out as a separate function to make it easy for you to
+use and for people to subclass and override. You can add here whatever you want
+(but I recommend sanity, and remember too much magic can make it hard to debug
+stuff down the road).
+
+ sub init_meta {
+ my ($class, @args) = @_;
+ Moose->init_meta( @args,
+ base_class => $class->base_class );
+ goto $init_meta if $init_meta;
+ }
+
+This method gets called at startup and it initializes L<Moose> and sets the actual
+base class. This way when you do C<use MyApp::ControllerObject> you are already
+inheriting from L<Catalyst::Controller>.
+
+ sub import {
+ use_module($_)->import::into(scalar caller)
+ for shift->importables;
+ goto $import;
+ }
+
+Here's where the bulk of the action is. AS you should recall, when you write
+code like:
+
+ use MyApp::ControllerObject;
+
+That loads the code representing that namespace, and then calls the C<import>
+method on it. So we loop through each module we want to import, make sure it
+is loaded via C<use_module> and then use the interface that L<Import::Into>
+gives us. After that, we forward on to the C<import> coderef that
+L<Moose::Exporter> setup for us early on.
+
+Oh, what's up with that C<goto>? Yeah, generally C<goto> is evil, but this is
+a secondary use of C<goto> which is a lot like a subroutine call, but it acts more
+like a subroutine swap (nothing is added to the callstack, and @_ is preserved).
+So its nothing to worry about!
+
+And that is it!
+See the code on Github for a full example distribution you can review:
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/MyApp-ControllerObject>
+
+This has a full sample distribution with test cases and all that. So take a
+look to see the bigger picture.
+
+=head1 Summary
+
+We reviewed one approach to using built in features of L<Moose>, the object
+system upon which L<Catalyst> is built, to reduce boilerplate when several
+desired features are needed across a large project. Along with L<Import::Into>'s
+simple and consistent API, you now have all you need to reduce boilerplate
+code in your larger Perl L<Catalyst> projects!
+
+=head1 Limitations and Concerns
+
+Although this method does allow one to centralize some boilerplate, I highly
+recommend being careful with the amount of extra behavior you place in this
+common class, as excessive magic can ultimately cause confusion and make it
+harder to debug issue. This method is not intended as a replacement for
+proper use of standard Perl design (Roles, etc).
+
+=head1 More Information
+
+I recommend reading the excellent documentation for extending L<Moose> via
+its build in exporter, L<Moose::Exporter> as well as any of the related
+documentation in the L<Moose> distribution, as well as the following:
+
+L<Catalyst>, L<Moose>, L<Import::Into>, L<Function::Parameters>,
+L<namespace::autoclean>, L<CatalystX::Syntax::Action>
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
+
Added: trunk/examples/CatalystAdvent/root/2013/03.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/03.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/03.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,145 @@
+=head1 Title
+
+HTTP Method Matching in Catalyst
+
+=head1 Overview
+
+A quick example of how to use the HTTP Method matching feature
+in L<Catalyst> along with some tips and caveats.
+
+=head1 Introduction
+
+Beginning in the v5.90020 release of L<Catalyst> we introduced into core the
+ability to match your controller actions to incoming HTTP method verbs. It
+does this by extending the standard L<Catalyst> approach of using subroutine
+attributes to tag your actions with 'metadata' that the dispatcher uses to
+figure out how to assign a given incoming request to a controller and action.
+Generic and shortcut attributes are allowed, and in addition we support some
+of the common approaches to use HTTP extended headers to 'tunnel' a method
+verb for the cases when the client is restricted (such as is common in many
+browsers to only support GET and POST).
+
+=head1 Why dispatch on HTTP Methods?
+
+Most modern web frameworks give you some high level ability to match an
+incoming request based on its HTTP verb. Programmers find it useful for
+a variety of tasks, from crafting RESTful APIs to allowing one to just have
+more meaningful URLs. L<Catalyst> has allowed this via a few add on
+distributions but often people don't find them. Having this feature in core
+means one can perform those tasks 'out of the box'. It also means that we
+can count on the presence of that ability as we continue to craft L<Catalyst>
+core codebase into the future.
+
+=head1 How Does it Work?
+
+Let's look at an example action:
+
+ sub is_get : Method('GET') Path('/example') { ... }
+ sub is_any : Path('/example') { ... }
+
+In this case the URL '/example' would get executed by the C<is_get> method
+of this controller when the HTTP method is a GET and by the C<is_any> method
+for all other cases. The generical uses is "Method($verb)" where $verb is
+any standard or custom value that shows up in the HTTP method header. Since
+several are common, we provide some shortcuts:
+
+ sub is_get : GET Path('/example') { ... }
+ sub is_post : POST Path('/example') { ... }
+ sub is_put : PUT Path('/example') { ... }
+ sub is_delete : DELETE Path('/example') { ... }
+
+In these cases the '/example' url would get mapped to the action as expected
+by the incoming HTTP method verb. Finally, you may add more than one method
+matching attribute:
+
+ sub post_and_put : POST PUT Path('/example) { ... }
+
+=head1 HTTP Extended Header Tunneling
+
+Since not all clients support a rich HTTP method vocabulary (classic HTML
+forms come to mind, since they typically only support GET and POST) it has
+become standard practice to use HTTP extended headers to 'tunnel' a verb
+not supported by a given client over one that does. For example, one might
+use this feature to tunnel a DELETE or PUT over a POST.
+
+For broad compatibility, we support HTTP method tunneling over the following
+HTTP headers:
+
+=over 4
+
+=item X-HTTP-Method (Microsoft)
+
+=item X-HTTP-Method-Override (Google/GData)
+
+=item X-METHOD-OVERRIDE (IBM)
+
+=item x-tunneled-method (used in many other similar systems on CPAN)
+
+=back
+
+Typically you won't need to set these headers yourself, they are usually
+created for you by the Javascript or similar toolkits but you should be aware
+of there function so you are not caught by surprise when they are active.
+
+=head1 A Full Example
+
+An example controller:
+
+ package MyApp::Controller::Root;
+
+ use base 'Catalyst::Controller';
+
+ sub is_get : GET Path('/test') { pop->res->body('GET') }
+
+ sub is_post : POST Path('/test') { pop->res->body('POST') }
+
+ sub is_put : PUT Path('/test') { pop->res->body('PUT') }
+
+ sub is_delete : DELETE Path('/test') { pop->res->body('DELETE') }
+
+ 1;
+
+And the test case for this:
+
+ use Test::Most;
+ use Catalyst::Test 'MyApp';
+ use HTTP::Request::Common qw(GET PUT POST DELETE);
+
+ is request(GET '/test')->content, 'GET';
+ is request(PUT '/test')->content, 'PUT';
+ is request(POST '/test')->content, 'POST';
+ is request(DELETE '/test')->content, 'DELETE';
+
+ done_testing;
+
+You can see the full application source on Github:
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/HTTP-Method-Matching>.
+
+=head1 Caveats and Gotchas
+
+You should remember that Catalyst will typically match on the first action
+that meets the minimum requirement. This means you need to put you more
+specific matches 'higher' in the controller than the catchall actions. When
+running L<Catalyst> in debug mode (via CATALYST_DEBUG=1, for example) the
+initial informations screen now contains information about what HTTP methods a
+given action will try to match, so that should help you figure out if something
+is going wrong.
+
+Also, this feature does not attempt to set some standard HTTP header information
+in the response regarding which methods are and are not allowed (as does for
+example L<Web::Machine>. If you are trying to create a strong, RESTful API
+you should not forget to set the response HTTP headers around allowed HTTP
+methods in your controller code.
+
+=head1 Summary
+
+HTTP Method Matching in core L<Catalyst> gives you a bit more flexibility
+to craft how the dispatcher maps incoming requests to your actions. Although
+the feature has limitations it should prove useful when mapping complex
+client server interactions.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/04.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/04.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/04.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,344 @@
+=head1 Title
+
+Using PSGI Integration in Catalyst: Middleware and More
+
+=head1 Overview
+
+This is an example application that shows you how to use the
+new L<Catalyst> support for PSGI middleware, and why you might
+want to use it.
+
+=head1 Introduction
+
+Modern versions of L<Catalyst> use L<Plack> as the underlying engine to
+connect your application to an http server. This means that you can take
+advantage of the full L<Plack> software ecosystem to grow your application
+and to better componentize and re-use your code.
+
+Middleware is a large part of this ecosystem. L<Plack::Middleware> wraps your
+PSGI application with additional functionality, such as adding Sessions ( as in
+L<Plack::Middleware::Session>), Debugging (as in L<Plack::Middleware::Debug>)
+and logging (as in L<Plack::Middleware::LogDispatch> or
+L<Plack::Middleware::Log4Perl>).
+
+Generally you can enable middleware in your C<psgi> file, as in the following
+example
+
+ #!/usr/bin/env plackup
+
+ use strict;
+ use warnings;
+
+ use MyApp::Web; ## Your subclass of 'Catalyst'
+ use Plack::Builder;
+
+ builder {
+
+ enable 'Debug';
+ enable 'Session', store => 'File';
+
+ mount '/' => MyApp::Web->psgi_app;
+
+ };
+
+Here we are using our C<psgi> file and tools that come with L<Plack> in order
+to enable L<Plack::Middleware::Debug> and L<Plack::Middleware::Session>. This
+is a nice, clean approach that cleanly separates your L<Catalyst> application
+from enabled middleware.
+
+However there may be cases when you'd rather enable middleware via you L<Catalyst>
+application, rather in a stand alone file. For example, you may wish to let your
+L<Catalyst> application have control over the middleware configuration, so that
+you could enable certain middleware in production, and others development. You
+can do this with an external C<.psgi> file, but it can get complex and ugly fast
+if your use of middleware is complex. Also, if middleware is part of the way
+your application works, it makes sense from a design viewpoint for the middleware
+to be part of the application rather than a layer on top.
+
+Starting on v5.90050, L<Catalyst> allows you to add middleware as part of your
+normal setup and configuration. Let's port the above example:
+
+ package MyApp::Web;
+
+ use Catalyst;
+
+ __PACKAGE__->config(
+ psgi_middleware => [
+ 'Debug',
+ 'Session' => {store => 'File'},
+ ]);
+
+C<psgi_middleware> is just a key in your application configuration, so you can
+use other tools in the configuration ecosystem (such as
+L<Catalyst::Plugin::ConfigLoader>) to manage it. The key takes an ArrayRef
+where elements can be the name of distribution under L<Plack::Middleware> (the
+named middleware C<Debug> would refer to L<Plack::Middleware::Debug>, an
+instance of a middleware object, a subroutine reference for inlined middlware
+or middleware under your application namespace. The following is all correctly
+formed:
+
+ __PACKAGE__->config(
+ 'psgi_middleware', [
+ 'Debug',
+ '+MyApp::Custom',
+ $stacktrace_middleware,
+ 'Session' => {store => 'File'},
+ sub {
+ my $app = shift;
+ return sub {
+ my $env = shift;
+ $env->{myapp.customkey} = 'helloworld';
+ $app->($env);
+ },
+ },
+ ],
+ );
+
+See L<Catalyst/PSGI-MIDDLEWARE> for more details.
+
+=head1 Why Use Middleware?
+
+Use middleware in cases where there is existing middleware who's functionality
+you want to reuse in your L<Catalyst> application, or when you have some logic
+that is global to the request / response cycle that you wish to isolate. Very
+often when you are thinking of writing a L<Catalyst::Plugin> or hacking into
+L<Catalyst::Request> / L<Catalyst::Response> or you are using controller end
+actions to modify the outgoing response, then middleware might be a better
+choice.
+
+=head1 How Does it Work?
+
+Think of middleware as layers in an onion, with you application at the center.
+As a request comes in, you go down each layer in the onion til you hit the
+the application. Then, as you go out, you pass each layer again (but this time
+from the center outward).
+
+So as the request comes in, your middleware can access and alter the psgi $env.
+On the way out it can alter the response.
+
+You can even use middleware as a way to produce responses (such as to have a
+default not found page, or to catch exceptions that your application throws)
+or to redirect the flow of the request to a totally different application.
+For example, you might wish to port your old application to run on L<Catalyst>;
+you can wrap some middleware to send the request to your new L<Catalyst> based
+application, and if it returns a 'not found' response, allow it to continue on
+to the old application. In this way you can port your website to a modern
+framework 'url by url' rather than try to do a ground up redo in one release.
+
+See L<Plack::Middleware> for more on middleware.
+
+=head1 A Full Example
+
+Let's build a L<Catalyst> application that uses middleware to redirect some
+of the requests to a L<Web::Simple> application. A good use for something
+like this could be a case when you have some time sensitive responses, such
+as autocomplete or similar json API and your L<Catalyst> application has too
+much overhead (sessions, authentication, etc.) To make it more fun, lets
+have the L<Web::Simple> application use some components from your main
+L<Catalyst> application (lets say to use the L<Catalyst> view) so we can see
+how this approach lets you mix and match the best of both worlds.
+
+Full example code can be found here:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/PSGI-Middleware>
+
+Let's start with the application class:
+
+ package MyApp::Web;
+
+ use Catalyst;
+ use MyApp::Web::Simple;
+
+ __PACKAGE__->config(
+ psgi_middleware => [
+ 'Delegate' => { psgi_app =>
+ MyApp::Web::Simple->new(
+ app => __PACKAGE__
+ )->to_psgi_app },
+ ]);
+
+ __PACKAGE__->setup;
+
+So there's a few things going on here but the gist of it is that we are saying
+this application uses the 'Delegate' middleware. Since we didn't specify the
+full middleware namespace, it will look first for L<MyApp::Web::Middleware::Delegate>
+and then L<Plack::Middleware::Delegate> (this is so that you can wrap and customize
+existing middleware, should you choose). In this case there is a
+C<MyApp::Web::Middleware::Delegate> so that gets passed a single parameterized
+argument, which in this case is pointing to your L<Web::Simple> based
+application. That, BTW has an argument which points back to your L<Catalyst>
+application, but we'll look at that in a bit! Lets look at our custom middleware:
+
+ package MyApp::Web::Middleware::Delegate;
+
+ use strict;
+ use warnings;
+ use base 'Plack::Middleware';
+ use Plack::Util::Accessor 'psgi_app';
+
+ sub call {
+ my ($self, $env) = @_;
+ my $psgi_response = $self->psgi_app->($env);
+
+ return $psgi_response->[0] == 404 ?
+ $self->app->($env) : $psgi_response;
+ }
+
+Since L<Catalyst> is L<Moose> based, we tend to use L<Moose> quite a bit, however
+in the case of this middleware there's no reason to not just follow how most other
+middleware projects work and just inherit from L<Plack::Middleware>.
+
+There's one function of important here, which middleware expects you to define,
+which is C<call>. This function is basically that onion layer I spoke of before
+where you get the C<PSGI> $env on the way in, and then access to the $psgi_response
+on the way out.
+
+What this code is saying is, "I get $env and pass it to C<psgi_app> (which is
+the L<Web::Simple> application that got added in the L<Catalyst> application
+configuration) and if that application returns a code 404 (Not Found) then send
+$env along to the L<Catalyst> application, otherwise use the L<Web::Simple>
+response and short circuit calling L<Catalyst>."
+
+BTW, this functionality is not unlike what you might see with some common
+middleware on CPAN (such as L<Plack::App::Cascade>) but I thought it instructive
+to write our own, just for learning.
+
+Ok great, lets look at the nice and speedy L<Web::Simple> application!
+
+ package MyApp::Web::Simple;
+
+ use Web::Simple;
+
+ has 'app' => (is=>'ro', required=>1);
+
+ sub render_hello {
+ my ($self, $where) = @_;
+ return $self->app->view('HTML')->render($self->app,
+ 'hello.html', {where=>'web-simple'} );
+ }
+
+ sub dispatch_request {
+ my $self = shift;
+ sub (/websimple-hello) {
+ [ 200, [ 'Content-type', 'text/html' ],
+ [$self->render_hello]
+ ],
+ },
+ }
+
+Basically L<Web::Simple> will handle the URL "/websimple-hello" and return a
+404 Not Found response for anything else (the 404 Not Foundis actually built
+into L<Web::Simple>, unlike L<Catalyst> where the default is to not return
+anything at all.)
+
+When rendering the response it uses the HTML View you defined in the base
+L<Catalyst> application. So you can use a similar technique to share views
+and models between applications and frameworks but all running under the same
+core application. Lets glance at the View template (hello.html):
+
+ <html>
+ <head>
+ <title>Hello From [% where %]</title>
+ </head>
+ <body>
+ <h1>Hello From [% where %]</h1>
+ </body>
+ </html>
+
+Not a complicated template, but it gets the idea across. This expects one
+variable C<where> which in L<Catalyst> gets stuffed into the stash, but in
+L<Web::Simple> we just add it to the C<render> arguments of the view.
+
+Other possible uses for this approach code be:
+
+=over 4
+
+=item Using L<Web::Machine> to handle your API
+
+L<Web::Machine> has great support for writing truely RESTful applications. What
+it doesn't have is L<Catalyst>'s great ability to bring data from lots of
+models, or to generate HTML views. This way you can use the best tool for the
+given job without be forced to given up the ease and structure of L<Catalyst>.
+
+=item Converting a legacy application to run on L<Catalyst>
+
+This lets you port your web application over 'url by url'. You can even use
+this to help you refactor an existing L<Catalyst> application that has gotten
+a bit more crusty over the years than you'd prefer.
+
+=back
+
+Other ideas might commend themselves to you. Lets see the L<Catalyst> side
+of things and look at the controller:
+
+package MyApp::Web::Controller::Root;
+
+ use Moose;
+ use MooseX::MethodAttributes;
+
+ extends 'Catalyst::Controller';
+
+ sub start : Chained('/')
+ PathPrefix CaptureArgs(0)
+ {
+ my ($self, $ctx) = @_;
+ }
+
+ sub hello : Chained('start')
+ PathPart('catalyst-hello') Args(0)
+ {
+ my ($self, $ctx) = @_;
+ $ctx->stash(where=>'Catalyst');
+ $ctx->forward($ctx->view('HTML'));
+ }
+
+ __PACKAGE__->config(namespace => '' );
+ __PACKAGE__->meta->make_immutable;
+
+The chaining here might be a bit gratuitious but you get the idea I hope.
+Finallty lets see the test cases to make sure everything works as expected:
+
+ use Test::Most;
+ use Catalyst::Test 'MyApp::Web';
+
+ ok( get('/catalyst-hello') =~ /Catalyst/ );
+ ok( get('/websimple-hello') =~ /web-simple/ );
+
+ done_testing;
+
+Go see the linked code on Github:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/PSGI-Middleware>
+
+For more code and more tests to see how the whole distribution is put
+together.
+
+=head1 Final Comments
+
+I personally see a big role for middleware in future L<Catalyst>. When
+it comes down to it, the idea of a L<Plack::Component> (which is the
+parent class of L<Plack::Middleware>) is not terrible different from
+L<Catalyst::Component>...
+
+Stay tuned!
+
+=head1 Also See
+
+L<Catalyst::Plugin::EnableMiddleware> gives you similar functionality for
+older versions of L<Catalyst>.
+
+=head1 Summary
+
+Middleware is another way to build and extend your L<Catalyst> based
+applications. It can be used to bring functionality from other common
+code (opensource or otherwise) and it opens the door to new approaches
+to solving many existing problems. Next time you need better control
+over your L<Catalyst> request and response, or you think of using a
+global plugin, ask yourself if middleware might not be the better option.
+
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/05.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/05.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/05.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,124 @@
+=head1 Title
+
+Using the L<Hash::MultiValue> configuration option in L<Catalyst>
+
+=head1 Overview
+
+L<Catalyst> has always supported HTML POST form parameters and
+query parameters using a simple API via the L<Catalyst::Request>
+object. However this API has a flaw when said parameters can be
+multi, leading to ackward boilerplate defensive code. The L<Plack>
+community introduced L<Hash::MultiValue> as one approach to better
+manage this issue. Starting in version 5.90050, L<Catalyst> lets
+you use L<Hash::MultiValue> via a configuration option so that you
+may use this approach in your L<Catalyst> code as well.
+
+=head1 Introduction
+
+Have you ever written code like this:
+
+ sub myaction :Path(something) {
+ my $p = (my $c = pop)->request->body_parameters;
+ my @vals = ref $p->{field} eq 'ARRAY'
+ ? @{$p->{field}}
+ : ($p->{field});
+ }
+
+You might write code like this if the incoming body (or query) parameters can
+be single or arrays. You might have a form with checkboxes or with select with
+multiple options. In that case you need to do that ugly dance of checking to
+see if the field is an arrayref or a single value.
+
+One solution to this problem is to use an instance of L<Hash::MultiValue> to
+contain your field parameters. L<Hash::MultiValue> comes out of L<Plack> and
+was a Perlish port of a similar class in the Python WSGI framework C<Webob>.
+Its one way to approach this problem, since it gives you a consistent API
+to dealing with query and form parameters.
+
+=head1 How Does it Work?
+
+Instead of $c->request->body_parameters (and ->query_parameters) containing
+a simple hash whose values could be single or could be an arrayref, we use
+an instance of L<Hash::MultiValue> instead. You enable this as a global
+L<Catalyst> configuration option, for example:
+
+ package MyApp;
+
+ use Catalyst;
+
+ __PACKAGE__->config(use_hash_multivalue_in_request=>1);
+ __PACKAGE__->setup;
+
+Now, whenever you call for request parameters, we build an instance of
+L<Hash::MultiValue> and store that instead of the HashRef that classic versions
+of L<Catalyst> uses. L<Hash::MultiValue> has an API that lets you get the
+values of field keys in a consistent manner no matter what the actual underlying
+values are. In additional, it uses overloading to support the classic 'as an
+arrayref' interface, which works just like L<Catalyst> does today, except it
+will always return a single value (whichever the last one was). This is likely
+a preferable behavior than the current, which can give you one or the other
+and leading your code to error out in those cases. Here's an example:
+
+ # suppose incoming POST parameters are such
+
+ name: John
+ age: 25
+ age: 44
+
+ sub myaction :Path(something) {
+ my $p = (my $c = pop)->request->body_parameters;
+
+ {
+ my $name = $p->{name}; # 'John'
+ my $age = $p->{age}; # 44
+ }
+
+ {
+ my $name = $p->get('name'); # 'John'
+ my $age = $p->get('age'); # 44
+ }
+
+ my @ages = $p->get_all('age'); # 26,44
+ }
+
+The approach is arguable less prone to error and reduces the need to write
+defensive code to figure out when form parameters are single values or are
+array referenences.
+
+=head1 A Full Example
+
+See the example application
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/Hash-MuliValue>
+
+For more help and test cases.
+
+=head1 Caveats and Gotchas
+
+Although L<Hash::MultiValue> overloads to support the 'as hashref' interface,
+it is quite likely to have different values in the multi field case, and as a
+result it might break existing code (or reveal previously undetected issues
+with your code, depending on your outlook).
+
+if you are in the habit of modifying the parameter hashref directly (for example
+adding or deleting keys) like so:
+
+ $c->req->body_parameters->{some_new_field} = 'bogus field';
+
+That won't work with L<Hash::MultiValue> which instead offers an API for adding
+and deleting fields in a consistent way.
+
+=head1 Summary
+
+L<Hash::MultiValue> is an approach to better encapsulate access to classic HTML
+form POST and query parameters. It provides a consistent API and smooths over
+some common issues you might have with the existing L<Catalyst> approach. If
+so, you can enable this new feature with a single, global configuration option!
+
+=head1 Also See
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/06.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/06.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/06.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,130 @@
+=head1 Title
+
+Using Body Data Handlers in Catalyst
+
+=head1 Overview
+
+The v5.90050 Release of Catalyst introduced a new way to process request body
+content. Out of the box L<Catalyst> now offers basic support for request
+content types of JSON and some of the more common approaches to nesting data
+structures in HTML form parameters. You can modify how this works globally
+by adding support for additional types or overriding default types.
+
+=head1 Introduction
+
+L<Catalyst> has supported classic HTML Form type POST parameters, as well
+as GET request query parameters for a long time. Although the built in support
+has a few gotchas (many of which we fixed by allowing you to configure
+L<Hash::MultiValue> as field storage for request parameters) it has generally
+served well.
+
+However times have changed quite a bit since L<Catalyst> was first put on CPAN.
+Common alternatives for client - server communication, typically using JSON,
+are the order of the day, and its normal for a web framework to support at
+least that out of the box. L<Catalyst> has long met this need via the external
+framework L<Catalyst::Action::REST> which is a toolkit for parsing and rendering
+various types of content. However L<Catalyst::Action::REST> can quite often be
+a lot more than you need. If you are just trying to support AJAXy style HTML
+form submission and validation, you probably don't want all the extra bits and
+structure that L<Catalyst::Action::REST> gives you. So, starting in version
+5.90050, L<Catalyst> has a new system for parsing common incoming request
+bodies, which out of the box will support JSON as well as the more common
+idioms for nested form parameters. We'll take a look out how this works for
+JSON request bodies and how you can modify and augment this new 'body data'
+system
+
+=head1 How Does it Work?
+
+There's two parts to the system. The first is part of L<Catalyst> application
+class, and takes the form of a new configuration option and key C<data_handlers>.
+It works like this:
+
+ package MyApp;
+
+ use Catalyst;
+
+ __PACKAGE__->config(
+ data_handlers => {
+ 'application/json' => sub {
+ # $_ is localized to a readable filehandle of the request body content.
+ },
+ },
+ );
+
+Basically L<Catalyst> defines a new global configuration option C<data_handlers>
+which is a hashref where the key is a standard MIME content-type and the value
+is a subroutine reference that is intended to parse that content type.
+
+The subroutine reference has C<$_> localized to the filehandle of the request
+body content, so you can read the content any way you like (you can use non
+blocking techniques should an event loop exist although it is doubtful that
+will help much since the filehandle has already been fully buffered).
+
+There is no defined return type. You can return a parsed data as a hashref
+or return an object, whatever makes sense for the content type and the size
+you are dealing with. For example, here's the code for the built in JSON
+parsing:
+
+ 'application/json' => sub {
+ Class::Load::load_first_existing_class('JSON::MaybeXS', 'JSON')
+ ->can('decode_json')->(do { local $/; $_->getline });
+ },
+
+Basically we just slurp up the JSON in one big line and parse it all in one
+go. Please note this might not be the best approach if the incoming JSON
+is expected to be very large!
+
+Your hashref under C<data_handlers> can include as many types as you deem
+required, and you can override the build in JSON parsing since we apply
+you customizations ontop of the defaults.
+
+So, how do you access this new parsed content? We've added a new attributes
+to L<Catalyst::Request> called C<body_data>. This attribute is lazy, so
+unless you actually ask for it, we don't attempt to parse any request content
+against the defined L<data_handlers>. So if you wrote a ton of your own
+JSON decoding stuff, and/or are using L<Catalyst::Action::REST> you can
+keep on doing that without any impact at all on your request overhead.
+
+Here's how this could look in you controller. Lets assume the incoming is
+C<application/json> like "{'name':'Jason','age':'25'}":
+
+ sub update_user : POST Path(/User) Consumes(JSON) {
+ my $p = (my $c = pop)->req->body_data;
+ $c->res->body("My name is $posted->{name} and my age is $p->{age}");
+ }
+
+Basically this is very similar to the request object's C<body_parameters>
+method but is data focused on alternative POSTed or PUT request content.
+
+The built in JSON decoder just returns a hashref, which is similar to many
+other frameworks but there's nothing stopping you from returning any type
+of scalar reference, including an object.
+
+So that's really it!
+
+=head1 Caveats, gotchas...
+
+Although unicode is supported out of the box with L<Catalyst> information
+in the C<$_> localized filehandle is basically just as it comes from the
+client. You may need to do additional decoding. This might change in
+the future, but in the absence of clear requirements the authors felt it best
+to not guess to far in advance.
+
+=head1 Summary
+
+Starting in version 5.90050, L<Catalyst> offers useful support for JSON
+POSTed content out of the box, reducing one's need to lean on heavier
+addins such as L<Catalyst::Action::REST> while maintaining our desire
+to keep L<Catalyst> modular and flexible.
+
+=head1 For More Information
+
+Setting data handler configutation: L<Catalyst/DATA-HANDLERS>
+
+Accessing the parsed content: L<Catalyst::Request/req-body_data>
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/07.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/07.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/07.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,332 @@
+=head1 Title
+
+How To Hack On Catalyst Core - Adding $response->from_psgi_response
+
+=head1 Overview
+
+A lot of people want to contribute to the L<Catalyst> project, but get scared
+off due to an assumption that the code is highly complex and requires an
+experts touch. This article will review how we added the feature that allows
+a L<Catalyst::Response> to be filled from the response of a PSGI appliction.
+
+See L<Catalyst::Response/from_psgi_response> for more.
+
+=head1 Introduction
+
+L<Catalyst> has been L<PSGI> native for a while, but to date has not really
+taken much advantage of that fact beyond the ability to use L<Plack> based
+web servers in replacement of the L<Catalyst::Engine> namespace. This is not a
+small think to be sure, but it would be great if L<Catalyst> could not flex its
+L<PSGI> abilities even more. One thing that would be possible is for L<Catalyst>
+to allow one to populate a reponse via a L<Plack::App> such as L<Plack::App::File>
+(which would make a possible replacement for L<Catalyst::Plugin::Static::Simple>).
+Or you could use L<Catalyst> to mount other frameworks, such as L<Web::Machine>
+which excel in a particular domain such as building RESTful APIs.
+
+So, how can one do this? Let's look into it!
+
+=head1 Prequisite Tasks
+
+Two features added to L<Catalyst> in previous releases where necessary to
+perform this task properly. The first was to allow one to have more control
+over how we write output to the server and out to the requesting client. This
+was the feature to expose the writer filehandle, and it was primarily added
+to make it easier to write asynchronous and/or streaming output, although as
+we will see, that feature enabled us to do stuff we'd not thought of at that
+point.
+
+See L<Catalyst::Response/res-write_fh> for more on using $Response->write_fh.
+
+This was needed as we will see later to make sure we could properly deal with
+a streaming or delayed PSGI response. Without it we'd be forced to fully buffer
+the response, which would be a shame since L<Catalyst> can support these types
+of responses.
+
+For more information see L<PSGI/Delayed-Response-and-Streaming-Body>.
+
+The second feature was added as a development version of this summer past, and
+it supports adding an input buffer object should one not exist in the case
+where the underlying L<Plack> engine does not provide one. This is needed because
+L<Catalyst> slurps up any POST or PUT content that might be part of the request
+and that means that any PSGI application that gets called later on won't get
+that (in other words it won't have access to POSTed form parameters or file
+uploads). Some PSGI webservers like L<Starman> provide a readable, buffered
+filehandle of this request content, others (like ModPerl and FastCGI) do not.
+This leads to issues where some code works fine in development (when you are
+using L<Starman>) but then break in a FastCGI (or *shudder* mod_perl) setup.
+So now in newer versions of L<Catalyst> when it is slurping up the request
+content, if we notice there is no input buffer, we create one so that anyone
+that needs it down the line will get access to it.
+
+Between these two features we have everything in L<Catalyst> we need to complete
+this task.
+
+=head1 The Test Cases
+
+Prior to working on this task, I wrote out the minimal test cases in the form
+of a new controller test. Here's a version of those test cases:
+
+ package TestFromPSGI::Controller::Root;
+
+ use base 'Catalyst::Controller';
+
+ sub from_psgi_array : Local {
+ my ($self, $c) = @_;
+ my $res = sub {
+ my ($env) = @_;
+ return [200, ['Content-Type'=>'text/plain'],
+ [qw/hello world today/]];
+ }->($c->req->env);
+
+ $c->res->from_psgi_response($res);
+ }
+
+ sub from_psgi_code : Local {
+ my ($self, $c) = @_;
+
+ my $res = sub {
+ my ($env) = @_;
+ return sub {
+ my $responder = shift;
+ return $responder->([200, ['Content-Type'=>'text/plain'],
+ [qw/hello world today2/]]);
+ };
+ }->($c->req->env);
+
+ $c->res->from_psgi_response($res);
+ }
+
+ sub from_psgi_code_itr : Local {
+ my ($self, $c) = @_;
+ my $res = sub {
+ my ($env) = @_;
+ return sub {
+ my $responder = shift;
+ my $writer = $responder->([200, ['Content-Type'=>'text/plain']]);
+ $writer->write('hello');
+ $writer->write('world');
+ $writer->write('today3');
+ $writer->close;
+ };
+ }->($c->req->env);
+
+ $c->res->from_psgi_response($res);
+ }
+
+So if you go and read the L<PSGI> documentation, you know there's three types
+of responses we need to deal with. The first is the classic PSGI example
+of a tuple (ArrayRef of Status, Headers and BodyArray/Body Filehandle). The
+second and third are variations of delayed response. These types of responses
+return a coderef instead of a tuple and can including streaming types of
+responses (see the third action C<from_psgi_code_itr> for example of this).
+
+Ok, so we created what are now failing test cases. Lets write the method to
+make them pass!
+
+=head1 The Code
+
+Let's take a look at the full method added to L<Catalyst::Response> and then
+well do a walkthrough:
+
+ sub from_psgi_response {
+ my ($self, $psgi_res) = @_;
+ if(ref $psgi_res eq 'ARRAY') {
+ my ($status, $headers, $body) = @$psgi_res;
+ $self->status($status);
+ $self->headers(HTTP::Headers->new(@$headers));
+ if(ref $body eq 'ARRAY') {
+ $self->body(join '', grep defined, @$body);
+ } else {
+ $self->body($body);
+ }
+ } elsif(ref $psgi_res eq 'CODE') {
+ $psgi_res->(sub {
+ my $response = shift;
+ my ($status, $headers, $maybe_body) = @$response;
+ $self->status($status);
+ $self->headers(HTTP::Headers->new(@$headers));
+ if($maybe_body) {
+ if(ref $maybe_body eq 'ARRAY') {
+ $self->body(join '', grep defined, @$maybe_body);
+ } else {
+ $self->body($maybe_body);
+ }
+ } else {
+ return $self->write_fh;
+ }
+ });
+ } else {
+ die "You can't set a Catalyst response from that, expect a valid PSGI response";
+ }
+ }
+
+The example usage is as follows:
+
+ package MyApp::Web::Controller::Test;
+
+ use base 'Catalyst::Controller';
+ use Plack::App::Directory;
+
+ my $app = Plack::App::Directory
+ ->new({ root => "/path/to/htdocs" })
+ ->to_app;
+
+ sub myaction :Local {
+ my ($self, $c) = @_;
+ $c->response->from_psgi_response(
+ $app->($c->request->env));
+ }
+
+So basically given a L<PSGI> response, as you would get from running it against
+the current $env (part of the L<PSGI> specification), let that response be
+the response that L<Catalyst> returns. We could use a bit of sugar here to
+make it easier to mount the L<PSGI> application under the current action
+namespace (for example) but this really is the minimal viable useful feature
+upon which all that coould later be built, should we find it useful to do so.
+
+Alll things being equal, I'd prefer to see this method refactored a bit, rather
+than one big method with so many conditionals. However I was concerned about
+adding to the L<Catalyst::Response> namespace, particularly since the request
+object is something L<Catalyst> explicitly makes public and replacable. We have
+no idea whats going on in the darkpan, so its best to err on the side of making
+the smallest footprint in the code that we can.
+
+=head1 Code Walkthrough
+
+Starting from the top:
+
+ sub from_psgi_response {
+ my ($self, $psgi_res) = @_;
+
+Declare the new method and slurp up the expected arguments. In this case we
+expect just a single argument which is the L<PSGI> compliant response. This
+is sure to be a reference of some type, but we'll need to inspect it a bit
+to figure out the correct handling:
+
+ if(ref $psgi_res eq 'ARRAY') {
+ my ($status, $headers, $body) = @$psgi_res;
+ $self->status($status);
+ $self->headers(HTTP::Headers->new(@$headers));
+
+So if you recall from the test case, we know that the L<PSGI> response is going
+to be an ArrayRef or a CodeRef. Let's handle the easy case first, since if the
+response is an ArrayRef that means its all complete and we can just map it to
+the L<Catalyst::Response> directly. As you can see mapping the C<status> and
+C<headers> is straightforward. Let's see the code to map the C<body>:
+
+ if(ref $body eq 'ARRAY') {
+ $self->body(join '', grep defined, @$body);
+ } else {
+ $self->body($body);
+ }
+
+This is a bit more tricky since the C<body> can be a filehandle like object
+or an ArrayRef. L<Catalyst> allows for string bodies or filehandles, which
+means in the case of it being an ArrayRef we need to flatten it to a string.
+
+I seriously considered changing L<Catalyst> to allow for a ArrayRef body,
+but in the end I felt it was too much risk for what seemed like small reward
+at this time. Perhaps in a future release?
+
+So, what about the second case, when the L<PSGI> response is a coderef?
+
+ } elsif(ref $psgi_res eq 'CODE') {
+
+The specification says when the response is a coderef (this is considered a
+delayed response) the server should obtain the actual response by calling that
+coderef with coderef of its own. In this case since L<Catalyst> is hosting the
+L<PSGI> application, we can consider it the server for now. Lets build the
+coderef we want to pass to the delayed response (if you look at L<PSGI> and
+related L<Plack> examples, this second coderef is often call the responder,
+and conventionally called $responder or $respond in code examples).
+
+ $psgi_res->(sub {
+ my $response = shift;
+ my ($status, $headers, $maybe_body) = @$response;
+ $self->status($status);
+ $self->headers(HTTP::Headers->new(@$headers));
+
+The L<PSGI> application that is returning a delayed response has two options
+but the both start the same way. It must call the $responder coderef with
+at least the first two parts of the classic L<PSGI> tuple, the C<status> and
+C<headers>. It then may or may not return the C<body> arrayref or filehandle
+at this point. If you refer back to the test case we wrote for L<Catalyst>
+you can see what such an application would look like:
+
+ my $psgi_app = sub {
+ my $responder = shift;
+ return $responder->([200, ['Content-Type'=>'text/plain'],
+ [qw/hello world today2/]]);
+ };
+
+In this example the L<PSGI> application is returning the full tuple. This
+is the case we handle first:
+
+ if($maybe_body) {
+ if(ref $maybe_body eq 'ARRAY') {
+ $self->body(join '', grep defined, @$maybe_body);
+ } else {
+ $self->body($maybe_body);
+ }
+ }
+
+Here we find that the C<body> is ready to go, so we do the "is it an arrayref
+or a filehandle" dance again and then we are done.
+
+However there's yet one final option. The L<PSGI> application may choose to
+not return the C<body> immediately. You would do this in cases where the
+body response is streamed, or if you are running the application in an event
+loop and the body is being created in response to events (such as the result
+of a database query). In this case, the $responder coderef is expected to
+return a L<PSGI> writer object, which does at least two methods, C<write> and
+C<close>. This way your application can continue to stream output via the
+C<write> method and when its done you call C<close>.
+
+Its actually a bit more complicated, since ideally you'd also monitor for the
+case where you lose the connection between the client and server, but for ease
+of illustration, lets assume the streaming response is just like in the test
+case above:
+
+ my $psgi_app = sub {
+ my $responder = shift;
+ my $writer = $responder->([200, ['Content-Type'=>'text/plain']]);
+ $writer->write('hello');
+ $writer->write('world');
+ $writer->write('today3');
+ $writer->close;
+ };
+
+This is a very trivial case, but it shows the basics of the interface. How do
+we handle this?
+
+ else {
+ return $self->write_fh;
+ }
+
+The C<write_fh> accessor of L<Catalyst::Response> gives you the raw writer
+object which has been passed down to L<Catalyst> from the server under which
+it runs. All such objects must do the C<write> and C<close> methods but the
+actual clase of the object will be specific to the server you are running
+L<Catalyst> on. The C<writer> object gets returned up to the delayed L<PSGI>
+application via the C<responder> for that case when the application does not
+provide the full C<body>.
+
+And that's the walkthrough!
+
+=head1 Prior Art
+
+Much of the inspiration and incentive to do this work came from
+L<Catalyst::Action::FromPSGI>
+
+=head1 Summary
+
+Diving into Catalyst codebase can be a bit daunting, due to its age and how its
+changed over the years. By detailing the steps involved in extending L<Catalyst>
+its our hope you will have a better understanding of the process and have an
+easier time should you try yourself.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/08.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/08.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/08.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,170 @@
+=head1 Title
+
+Matching Actions on Request Content Types
+
+=head1 Overview
+
+A quick example of how to use the Request Content Type matching feature
+in L<Catalyst> version 5.90050+.
+
+=head1 Introduction
+
+Beginning in the v5.90050 release of L<Catalyst> we introduced into core the
+ability to match your controller actions to the content types of incoming
+HTTP requests. This allows you to match actions to the contents of the
+HTTP request content type header. As a result, you can dispatch to your
+actions based on if the incoming request is a JSON post, a classic form
+data post, or some other type.
+
+=head1 Why dispatch on Request Content Type?
+
+Modern web developers consider RESTful principles when crafting web APIs
+and in creating meaninful URL structures for thier websites. One core principle
+of REST is that a given resource (in this case a URL) can have many
+representations (HTML, XML, JSON, etc.) In the past, many people used a
+L<Catalyst> addin, L<Catalyst::Action::REST>, which provided a toolkit to
+deserialize many different content types and provide them to an action. This
+works well and we still recommend L<Catalyst::Action::REST> for this and for
+many of its other features. However there are cases when you want to process
+things differently depending on the request content type. In addition, there
+might be times when you don't need all the power and features of
+L<Catalyst::Action::REST> but still want to dispatch on incoming request types
+(for example you might have a website with a form and you'd like to support
+both JSON and classic HTML POSTing). In those cases the ability to dispatch to
+a given action based on matching a content type is useful.
+
+=head1 How Does it Work?
+
+Let's look at some example actions:
+
+ sub as_json : POST Path('/echo')
+ Consumes('application/json') { ... }
+
+ sub as_formdata : POST Path('/echo')
+ Consumes('application/x-www-form-urlencoded') { ... }
+
+In this example the same URL ('/echo') would be server by either JSON or by
+classic form data. The L<Catalyst> dispatcher will choose the correct action
+based on the information tagged to the action by the subroutine attribute
+C<Consumes>. The generic form of usages is "Consumes($type)" where $type is
+a standard content type. Here's a few of the more common types you might
+encounter:
+
+=over 4
+
+=item application/json
+
+JSON encoded data "{'message' : 'hello'}"
+
+=item application/x-www-form-urlencoded
+
+HTML form post
+
+=item multipart/form-data
+
+Form posting with file uploads
+
+=back
+
+Since there's several content types that are in common usage, we provide
+shortcuts, which work in the form "Consumes($shortcut)" where $shortcut is:
+
+ JSON => 'application/json',
+ JS => 'application/javascript',
+ PERL => 'application/perl',
+ HTML => 'text/html',
+ XML => 'text/xml',
+ Plain => 'text/plain',
+ UrlEncoded => 'application/x-www-form-urlencoded',
+ Multipart => 'multipart/form-data',
+ HTMLForm => ['application/x-www-form-urlencoded','multipart/form-data'],
+
+And would look like:
+
+ sub as_json : POST Path('/echo')
+ Consumes(JSON) { ... }
+
+ sub as_formdata : POST Path('/echo')
+ Consumes(HTMLForm) { ... }
+
+As with other such subroutine attributes, you can match more than one on a
+given action (which does an OR style match).
+
+ sub is_more_than_one
+ : Chained('start')
+ : Consumes(UrlEncoded)
+ : Consumes(Multipart)
+
+See L<Catalyst::Controller/Consumes> and L<Catalyst::ActionRole::ConsumesContent>
+for more details and examples.
+
+=head1 A Full Example
+
+An example controller:
+
+ package MyApp::Controller::Root;
+
+ use base 'Catalyst::Controller';
+
+ sub as_json : POST Path('/echo')
+ Consumes('application/json') {
+ my ($self, $c) = @_;
+ $c->response->body(
+ $c->request->body_data->{message});
+
+ }
+
+ sub formdata : POST Path('/echo')
+ Consumes('application/x-www-form-urlencoded') {
+ my ($self, $c) = @_;
+ $c->response->body(
+ $c->request->body_parameters->{message});
+ }
+
+You should note the use the new L<Catalyst::Request> method C<body_data>
+to parsing incoming JSON. This was added in v5.90050 in the Fall of 2013.
+For more information on C<body_data> see L<Catalyst::Request/req-body_data>
+and L<Catalyst/DATA-HANDLERS>.
+
+The test case for this controller:
+
+ use Test::Most;
+ use Catalyst::Test 'MyApp';
+ use HTTP::Request::Common;
+ use JSON::MaybeXS;
+
+ {
+ ok my $req = POST '/echo',
+ Content_Type => 'application/json',
+ Content => encode_json +{message=>'test'};
+
+ ok my $res = request $req;
+
+ is $res->content, 'test', 'Handles JSON post';
+ }
+
+ {
+ ok my $req = POST '/echo', [message=>'test'];
+ ok my $res = request $req;
+
+ is $res->content, 'test', 'Handles classic HTML post';
+ }
+
+ done_testing;
+
+You can see the full application source on Github:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging>.
+
+=head1 Summary
+
+Request content matching is a useful feature to have in Core L<Catalyst> which
+lets you make more meaningful URLs. It also plays nice with existing addons
+such as L<Catalyst::Action::REST> when you are using L<Catalyst> to craft your
+web APIs.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/09.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/09.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/09.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,330 @@
+=head1 TITLE
+
+An Example Catalyst Plugin - Catalyst::Plugin::RunRequest
+
+=head1 OVERVIEW
+
+Port L<Web::Simple>'s feature C<run_test_request> to a L<Catalyst> plugin.
+
+=head1 INTRODUCTION
+
+Generally I tell people there are few good reasons to write a L<Catalyst::Plugin>.
+As a unit of reusability, its a pretty heavy hammer, since a plugin become part
+of your application and context, that means its available everywhere all the time
+and of course it also means that your $c and $app are a little bigger memory wise
+and you incur any startup penalties for every single request. With so many ways
+to wrap and reuse functionality (as a Model, ControllerRole or ActionRole, for
+example) there's nearly never a good reason to write a Plugin. And now that
+L<Catalyst> is L<PSGI> native, I usually say anything related to the global
+request or response is probably better off written as L<Plack::Middleware>.
+
+However, if you are looking for something that is global, and is related to
+application functionality, a plugin is still a rational option. Here's an
+example plugin I did that mimics some functionality from another Perl web
+framework, L<Web::Simple>.
+
+=head1 Web::Simple::Application->run_test_request
+
+L<Web::Simple> has a neat feature that makes it easy to run a sample request
+in a test case or via the command line. We'll leave the CLI for now (its a bit
+trickier based on the way L<Catalyst> does setup) but as it turns out, mimicing
+the underlying function is very easy to do. It would make a rational plugin and
+its also a good opportunity to review some of Catalyst's PSGI guts.
+
+Here's how it works in L<Web::Simple>. You write a basic web application
+like so:
+
+ package MyWSApp;
+
+ use Web::Simple;
+
+ sub dispatch_request {
+ sub (GET + /helloworld) {
+ [ 200, [ 'Content-type', 'text/plain' ], [ 'Hello world!' ] ]
+ },
+ sub (POST + /echo + %:val=) {
+ [ 200, [ 'Content-type', 'text/plain' ], [ $_{val} ] ]
+ },
+ }
+
+ __PACKAGE__->run_if_script;
+
+Now, in a test case you could write:
+
+ use Test::Most;
+ use MyWSApp;
+
+ {
+ ok my $http_response = MyWSApp->run_test_request(GET '/helloworld');
+ is $http_response->content, 'Hello world!';
+ }
+
+ {
+ ok my $http_response = MyWSApp->run_test_request(POST '/echo', [val=>'posted']);
+ is $http_response->content, 'posted';
+ }
+
+ {
+ ok my $http_response = MyWSApp->run_test_request('GET' => '/helloworld');
+ is $http_response->content, 'Hello world!';
+ }
+
+ {
+ ok my $http_response = MyWSApp->run_test_request('POST' => '/echo', {val=>'posted'});
+ is $http_response->content, 'posted';
+ }
+
+ done_testing;
+
+In L<Web::Simple> the C<run_test_request> method accepts either a L<HTTP::Request>
+object (built by hand or via L<HTTP::Request::Common> which is my personal
+favored approach) or it can take a data structure so you don't need to load any
+additional modules (if you look carefully at the given example, its very similar
+to the L<HTTP::Request::Common> style code). The idea here is to take any sort
+of L<HTTP::Request> and get the L<HTTP::Response> out of it.
+
+So that's nice, concise and simple. Sure, L<Catalyst::Runtime> ships with
+L<Catalyst::Test> and there's even more powerful testing options on CPAN, but
+there's something to say for having a straightup solution when writing trival
+test cases, or for when you want to demo some code. So, let's write a plugin
+for L<Catalyst> that does this!
+
+=head1 The Plugin
+
+Lets take this line by line. Lets assume you've create a proper directory
+structure for a Perl distribution (look for links to Github near the end of the
+post for examples) for a new L<Catalyst> plugin called
+'Catalyst::Plugin::RunTestRequest'. Here's the start of the file that would go
+in 'lib/Catalyst/Plugin/RunTestRequest.pm'.
+
+ package Catalyst::Plugin::RunTestRequest;
+
+ use Moose::Role;
+
+ requires 'psgi_app';
+
+In the post L<Moose> port of L<Catalyst> world, its best to write a new plugin
+as a L<Moose::Role>. We specify this role can only be composed into a class
+that has the C<psgi_app> method, which we'll see in moment is needed by the
+new method we are adding to your application class.
+
+Next, let's write the method that will be composed into your application
+subclass:
+
+ sub run_test_request {
+ my ($self, @req) = @_;
+ my $http_request = $_test_request_spec_to_http_request->(@req);
+
+ require HTTP::Message::PSGI;
+ my $psgi_env = HTTP::Message::PSGI::req_to_psgi($http_request);
+ my $psgi_response = $self->psgi_app->($psgi_env);
+ my $http_response = HTTP::Message::PSGI::res_from_psgi($psgi_response);
+
+ return $http_response;
+ }
+
+The first two lines creates the method and slurps up incoming args. We will
+normalize C<@req> via an anonymous subroutine so that we are always dealing
+with an instance of L<HTTP::Request> (and I've simply cribbed a similiarly
+named method from L<Web::Simple::Application>, so I won't go into it, just give
+a big shout out to the L<Web::Simple> cabal). I'll link to the full file at
+the end of the article.
+
+Followed by the required module L<HTTP::Message::PSGI> which lets us convert
+between the various types of requests and responses we'll need to deal with.
+We C<require> this module rather than declare it as a C<use> near the top of
+the file so that we can avoid loading it in the cases when this method is
+never called (thereby saving a bit of memory) and it we also don't call the
+modules C<import> method, so we avoid importing unneeded functions into our
+namespace.
+
+Next we take the normalized L<HTTP::Request> and convert it into a HashRef
+that conforms to the L<PSGI> specification. We pass this to the C<psgi_app>
+method, which is returning a L<PSGI> application, basically a coderef that
+wants that $psgi_env we just made. This is the coderef that kicks off the
+full L<Catalyst> request / response cycle. It returns a $psgi_response,
+which we then convert to a L<HTTP::Response>. Which gets returned to the
+caller.
+
+The full plugin looks like this (and again see links to Github near the end).
+
+ package Catalyst::Plugin::RunTestRequest;
+
+ use Moose::Role;
+
+ requires 'psgi_app';
+
+ our $VERSION = '0.001';
+
+ ## Block of code gratuitously stolen from Web::Simple::Application
+ my $_test_request_spec_to_http_request = sub {
+ my ($method, $path, @rest) = @_;
+
+ # if it's a reference, assume a request object
+ return $method if ref($method);
+
+ if ($path =~ s/^(.*?)\@//) {
+ my $basic = $1;
+ require MIME::Base64;
+ unshift @rest, 'Authorization:', 'Basic '.MIME::Base64::encode($basic);
+ }
+
+ require HTTP::Request;
+
+ my $request = HTTP::Request->new($method => $path);
+
+ my @params;
+
+ while (my ($header, $value) = splice(@rest, 0, 2)) {
+ unless ($header =~ s/:$//) {
+ push @params, $header, $value;
+ }
+ $header =~ s/_/-/g;
+ if ($header eq 'Content') {
+ $request->content($value);
+ } else {
+ $request->headers->push_header($header, $value);
+ }
+ }
+
+ if (($method eq 'POST' or $method eq 'PUT') and @params) {
+ my $content = do {
+ require URI;
+ my $url = URI->new('http:');
+ $url->query_form(@params);
+ $url->query;
+ };
+ $request->header('Content-Type' => 'application/x-www-form-urlencoded');
+ $request->header('Content-Length' => length($content));
+ $request->content($content);
+ }
+
+ return $request;
+ };
+
+ sub run_test_request {
+ my ($self, @req) = @_;
+ my $http_request = $_test_request_spec_to_http_request->(@req);
+
+ require HTTP::Message::PSGI;
+ my $psgi_env = HTTP::Message::PSGI::req_to_psgi($http_request);
+ my $psgi_response = $self->psgi_app->($psgi_env);
+ my $http_response = HTTP::Message::PSGI::res_from_psgi($psgi_response);
+
+ return $http_response;
+ }
+
+ 1;
+
+There's not a lot to it, most if it is the normalization code that lets you
+have a bit of flexibility using the method. Lets build a quick application.
+
+Here's the application class:
+
+ package MyCatApp;
+
+ use Catalyst 'RunTestRequest';
+
+ __PACKAGE__->setup;
+
+L<Catalyst> seems to get a bad rap as needing a lot of boilerplate, but really
+that's all you need for this simple application. Lets make a controller:
+
+ package MyCatApp::Controller::Root;
+
+ use base 'Catalyst::Controller';
+
+ sub root : GET Path('/helloworld') {
+ pop->res->body('Hello world!');
+ }
+
+ sub test_post : POST Path('/echo') {
+ my ($self, $c) = @_;
+ $c->res->body( $c->req->body_parameters->{val} );
+ }
+
+ 1;
+
+Again, there's not a lot of work here. Its realy not many more lines than the
+L<Web::Simple> version, but its spread across more files. That would make more
+sense down the road when you application has 20 controllers and nearly 100
+URL endpoints, but for a simple, demo app like this its still not too bad :)
+
+To be fair, L<Web::Simple> is nice that it has built in support for matching
+on a POST parameter and gives you a default 'not found page', so we'd need
+a little more code to be completely comparable, but this is good enough for a
+demo.
+
+Lets look at the test case. It looks nearly the same as the L<Web::Simple>
+one:
+
+ use HTTP::Request::Common;
+ use Test::Most;
+ use MyCatApp;
+
+ {
+ ok my $http_response = MyCatApp->run_test_request(GET '/helloworld');
+ is $http_response->content, 'Hello world!';
+ }
+
+ {
+ ok my $http_response = MyCatApp->run_test_request(POST '/echo', [val=>'posted']);
+ is $http_response->content, 'posted';
+ }
+
+ {
+ ok my $http_response = MyCatApp->run_test_request('GET' => '/helloworld');
+ is $http_response->content, 'Hello world!';
+ }
+
+ {
+ ok my $http_response = MyCatApp->run_test_request('POST' => '/echo', {val=>'posted'});
+ is $http_response->content, 'posted';
+ }
+
+ done_testing;
+
+And that's really it! Here's the full application with test cases and
+organized as a proper CPAN style distribution:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/Catalyst-Plugin-RunTestRequest>
+
+=head1 Limitations
+
+Since we run the L<HTTP::Request> (or request specification) directly against
+the C<psgi_app> method of L<Catalyst> if you are using a standalone C<psgi>
+file that declares additional middleware or URL mountpoints, those additional
+bits will not be tested. If you are using middleware are a critical part of
+your L<Catalyst> application, I recommend using the the new middleware
+configuration option: L<Catalyst\PSGI-MIDDLEWARE>. For mounting PSGI
+applications you may prefer to consider L<Catalyst::Response\from_psgi_response>
+or look at the following independent distributions of you are on an older
+version of L<Catalyst>.
+
+L<Catalyst::Plugin::EnableMiddleware>, L<Catalyst::Action::FromPSGI>.
+
+=head1 What other things could you do with this?
+
+I've never loved the way L<Catalyst::Plugin::SubRequest> worked. It would be
+very easy to rewrite or offer another approach using this.
+
+It might be nice to have a sort of commandline REPL that let you run test
+requests against your L<Catalyst> application, with a full request/response
+trace.
+
+=head1 Summary
+
+We reviewed when one might wish to write a L<Catalyst> plugin, what such a
+plugin looks like. We also took a look at how the L<PSGI> underpinnings of
+L<Catalyst> provide a useful gateway to provide novel features.
+
+=head1 For More Information
+
+L<Catalyst>
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
+
Added: trunk/examples/CatalystAdvent/root/2013/10.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/10.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/10.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,342 @@
+=head1 Title
+
+Nonblocking and Streaming
+
+=head1 Overview
+
+Modern versions of L<Catalyst> allow you to take charge of how your
+write operations work. This enables better support for working inside
+common event loops such as L<AnyEvent> and <IO::Async> to support
+non blocking writes to stream large files.
+
+Lets explore how L<PSGI> implements delayed and streaming responses
+and how we can use streaming response with an event loop to enable
+use of nonblocking IO. Then lets see how L<Catalyst> exposes that
+API. This part one of a four part series.
+
+=head1 Introduction
+
+When L<Catalyst> was ported to run as a native L<PSGI> application,
+great pains were taken to make sure we could properly support delayed
+and streaming responses. However only recently was that ability
+properly exposed as L<Catalyst> API. In order to better understand
+how L<Catalyst> works, lets step back and refresh on the L<PSGI>
+specification.
+
+=head1 PSGI Delayed Response and Streaming
+
+You are likely familiar with the basic L<PSGI> 'hello world' application
+which goes something like this:
+
+ my $psgi_app = sub {
+ my $env = (@_);
+ return [ 200,
+ [ 'Content-Type' => 'text/plain' ],
+ [ 'Hello World!'] ];
+ };
+
+If you put the above into a file C<hello-classic.psgi> you could run it under a decent
+webserver very easily:
+
+ $ plackup -s Starman bin/hello-classic.psgi
+
+ 013/11/27-09:18:04 Starman::Server (type Net::Server::PreFork) starting! pid(69860)
+ Resolved [*]:5000 to [0.0.0.0]:5000, IPv4
+ Binding to TCP port 5000 on host 0.0.0.0 with IPv4
+ Setting gid to "20 20 20 12 61 79 80 81 98 33 100 204 398 399"
+ Starman: Accepting connections at http://*:5000/
+
+And now you can use a commandline tool like telnet to hit that server and
+execute HTTP requests:
+
+ $ telnet 127.0.0.1 5000
+ Trying 127.0.0.1...
+ Connected to localhost.
+ Escape character is '^]'.
+ GET / HTTP/1.1
+ Host: www.test.org
+
+ HTTP/1.1 200 OK
+ Content-Type: text/plain
+ Transfer-Encoding: chunked
+ Date: Wed, 27 Nov 2013 22:49:39 GMT
+ Connection: keep-alive
+
+ c
+ Hello World!
+ 0
+
+ Connection closed by foreign host.
+
+Take note of the Response header 'Transfer-Encoding: chunked'. Since L<Starman>
+understand HTTP/1.1 it can send chunked responses in the case when you fail to
+provide the content length (or, you give an expected length but specify 'chunked'
+anyway). In this case that 'c' that you see is the length in hexadecimal (12
+bytes). That final '0' means there's no more chunks to send.
+
+Now, L<PSGI> offers a few more tricks for the case when you don't want to fully
+pre-generate your response. In this case instead of returning a tuple (Status,
+Headers, Body) from your L<PSGI> application, you return a code reference:
+
+ my $psgi_app = sub {
+ my $env = shift;
+ return my $delayed_response = sub {
+ my $responder = shift;
+ my $writer = $responder->(
+ [200, [ 'Content-Type' => 'text/plain' ]]);
+
+ $writer->write('Hello');
+ $writer->write(' ');
+ $writer->write('World');
+ $writer->close;
+ };
+ };
+
+In this case the C<$delayed_response> coderef gets run by the underlying
+server, which is required to pass it a second coderef, the C<$responder>.
+So basically your application is 'delayed' it doesn't actually run until
+the server runs it, which can allow you to take advantage of event loops
+like L<AnyEvent> or L<IO::Async> to schedule your response better. But
+its still useful even under a blocking server like L<Starman>.
+
+Lets look a bit more at the code example. The C<$responder> coderef can
+accept the full $Status, \@Headers, \@Body tuple, but a more interesting
+use is to give it just the first two elements of the tuple, as we do in
+this example application. In this case the C<$responder> returns the server's
+C<$writer> object, which basically is like a filehandle that points at the
+client which originated the request (for example a web browser or the
+C<telnet> commandline application). This object defines two methods,
+C<write> and C<close>. Each time you call C<write> you stream some data
+out to the client. Generally the connection stays open until you call
+C<close>, which means you can use this for long responses or for techniques
+like cometd where you keep a connection to the client open for a long time.
+
+B<*Note:> Even thought I say the $writer object can be thought of as a file
+handle to the client, the underlying architecture is both more complex and
+yet lacking in some of the features we expect from a filehandle. For
+example, in the current PSGI spec, there's no clear and common way to detect
+when you can't write due to some issue with the client or network. Also,
+there's nothing stopping the server from buffering your writes before sending
+them on to the client, if it is necessary to do so for scheduling purposes.
+For example, the server might buffer your write in memory, or to some other
+temporary store if needed.
+
+Hopefully someday the plack-cabal can get together on a specification to
+expose and clarify some of these important missing bits.
+
+Let's see what this application looks like under telnet. We start the psgi
+application with C<plackup> as in the previous case.
+
+ $ plackup -s Starman bin/hello-delayed.psgi
+ 2013/11/27-09:52:15 Starman::Server (type Net::Server::PreFork) starting! pid(69989)
+ Resolved [*]:5000 to [0.0.0.0]:5000, IPv4
+ Binding to TCP port 5000 on host 0.0.0.0 with IPv4
+ Setting gid to "20 20 20 12 61 79 80 81 98 33 100 204 398 399"
+ Starman: Accepting connections at http://*:5000/
+
+And hit it with telnet:
+
+ $ telnet 127.0.0.1 5000
+ Trying 127.0.0.1...
+ Connected to localhost.
+ Escape character is '^]'.
+ GET / HTTP/1.1
+ Host: www.test.org
+
+ HTTP/1.1 200 OK
+ Content-Type: text/plain
+ Transfer-Encoding: chunked
+ Date: Wed, 27 Nov 2013 22:57:11 GMT
+ Connection: keep-alive
+
+ 5
+ Hello
+ 1
+
+ 5
+ World
+ 0
+
+ Connection closed by foreign host.
+
+You'll note this time each of the writes is a separate chunk, with a separate
+length. Now, we used the chunked encoding here to help illustrate how each
+call to ->write pushes a separate 'chunk', but to be clear, we could have
+used this streaming interface without chunked transfer encoding. For example,
+the same code with estimated length in the header:
+
+ my $psgi_app = sub {
+ my $env = shift;
+ return sub {
+ my $responder = shift;
+ my $writer = $responder->(
+ [200, [
+ 'Content-Type' => 'text/plain',
+ 'Content-Length' => '11', ]]);
+
+ $writer->write('Hello');
+ $writer->write(' ');
+ $writer->write('World');
+ $writer->close;
+ };
+ };
+
+And the telent trace:
+
+ $ telnet 127.0.0.1 5000
+ Trying 127.0.0.1...
+ Connected to localhost.
+ Escape character is '^]'.
+ GET / HTTP/1.1
+ Host: www.test.org
+
+ HTTP/1.1 200 OK
+ Content-Type: text/plain
+ Content-Length: 11
+ Date: Wed, 27 Nov 2013 23:06:33 GMT
+ Connection: keep-alive
+
+ Hello WorldConnection closed by foreign host.
+
+so we still streamed the information, just its not as easy to see from looking
+at the telent trace, as it is when using chunked transfer encoding. But its
+definitely still streaming, as you can see if you start Starman in DEBUG mode
+and examine the debug output for that request:
+
+ >$ STARMAN_DEBUG=1 plackup -s Starman bin/hello-delayed-with-length.psgi
+ 2013/11/27-17:09:44 Starman::Server (type Net::Server::PreFork) starting! pid(71887)
+ Resolved [*]:5000 to [0.0.0.0]:5000, IPv4
+ Binding to TCP port 5000 on host 0.0.0.0 with IPv4
+ Setting gid to "20 20 20 12 61 79 80 81 98 33 100 204 398 399"
+ Using no serialization
+ Starman: Accepting connections at http://*:5000/
+ Beginning prefork (5 processes)
+ Starting "5" children
+ Child Preforked (71888)
+ Child Preforked (71889)
+ Child Preforked (71890)
+ Parent ready for children.
+ Child Preforked (71891)
+ Child Preforked (71892)
+
+ 2013/11/27-17:09:51 CONNECT TCP Peer: "[127.0.0.1]:61580" Local: "[127.0.0.1]:5000"
+ [71888] Read 16 bytes: "GET / HTTP/1.1\r\n"
+ [71888] Read 20 bytes: "Host: www.test.org\r\n"
+ [71888] Read 2 bytes: "\r\n"
+ 127.0.0.1 - - [27/Nov/2013:17:09:52 -0600] "GET / HTTP/1.1" 200 - "-" "-"
+ [71888] Wrote 126 bytes
+ [71888] Wrote 5 bytes
+ [71888] Wrote 1 byte
+ [71888] Wrote 5 bytes
+ [71888] Request done
+ [71888] Waiting on previous connection for keep-alive request...
+ [71888] Closing connection
+
+Here you can see the output very clearly. Starman sends 126 bytes to the client
+(this is the HTTP header information) followed by three writes of 5, 1 and 5 bytes
+each.
+
+BTW, if you actually go at run the code you'll actually see the 1 second 'keep
+alive' delay at the end of the response. Basically after the write calls
+->close, it spends a bit of time waiting to see if that connection sends a
+a request to hold the connection open. For Starman this is 1 second, but you
+can configure it. This keep alive is a big part of HTTP 1.1 and all HTTP 1.1
+connects are considered persistent unless declared otherwise, so that's why
+its important for Starman and other HTTP 1.1 servers to have that ability to
+timeout if the client isn't doing anything with the persistent connection.
+
+You can actually see this keep alive in action with STARMAN_DEBUG and if
+you are speedy with the second request (or bump up the starman keepalive
+timeout). For example:
+
+ $ telnet 127.0.0.1 5000
+ Trying 127.0.0.1...
+ Connected to localhost.
+ Escape character is '^]'.
+ GET / HTTP/1.1 (first request which initiates the connection)
+ Host: www.test.org
+
+ HTTP/1.1 200 OK
+ Content-Type: text/plain
+ Content-Length: 11
+ Date: Wed, 27 Nov 2013 23:20:13 GMT
+ Connection: keep-alive
+
+ Hello World
+
+ GET / HTTP/1.1 (second request over the same connection)
+ Host: www.test.org
+
+ HTTP/1.1 200 OK
+ Content-Type: text/plain
+ Content-Length: 11
+ Date: Wed, 27 Nov 2013 23:20:14 GMT
+ Connection: keep-alive
+
+ Hello World
+
+ Connection closed by foreign host.
+
+Here's the L<Starman> debugging output.
+
+ 2013/11/27-17:20:12 CONNECT TCP Peer: "[127.0.0.1]:61630" Local: "[127.0.0.1]:5000"
+ [71889] Read 16 bytes: "GET / HTTP/1.1\r\n"
+ [71889] Read 20 bytes: "Host: www.test.org\r\n"
+ [71889] Read 2 bytes: "\r\n"
+ 127.0.0.1 - - [27/Nov/2013:17:20:13 -0600] "GET / HTTP/1.1" 200 - "-" "-"
+ [71889] Wrote 126 bytes
+ [71889] Wrote 5 bytes
+ [71889] Wrote 1 byte
+ [71889] Wrote 5 bytes
+ [71889] Request done
+ [71889] Waiting on previous connection for keep-alive request...
+ [71889] Read 36 bytes: "GET / HTTP/1.1\r\nHost: www.test.org\r\n"
+ [71889] Read 2 bytes: "\r\n"
+ 127.0.0.1 - - [27/Nov/2013:17:20:14 -0600] "GET / HTTP/1.1" 200 - "-" "-"
+ [71889] Wrote 126 bytes
+ [71889] Wrote 5 bytes
+ [71889] Wrote 1 byte
+ [71889] Wrote 5 bytes
+ [71889] Request done
+ [71889] Waiting on previous connection for keep-alive request...
+ [71889] Closing connection
+
+So you can see one connection, two requests. This keep alive forms the basis
+of many long polling and similar techniques (like cometd) for keeping a persistent
+connection between the client and the server, for the purposes of enabling speedy
+(semi - realtime) type interfaces. Although of course since L<Starman> is a forked,
+blocking server, you'd be limited to the number of persistent connections by the
+number of forked children (in L<Starman> the default is 5). If you want to scale
+such a thing, you probably need to switch to a non blocking server, which we will
+discuss later.
+
+Again, keep alive and chunked responses are separate matters, just it makes it a
+bit easier to visually see what is going on. Some reasons for streaming
+(in my mind) are for when you have very large responses that you'd rather not
+buffer in memory or to a temp file, but would prefer to send in bits (sort of like
+when you have a very large SQL query and you use a cursor to iterate row by row
+rather than load all the rows into an array). On the other hand, chunked encoding
+is useful when you don't know upfront the length you are sending (such as when
+getting the length is computationally expensive, or can't be known initially, or
+when the intention is to send infinitely. The two concepts overlap in use case
+but the technology themselves is separate.
+
+Great, so that's how L<PSGI> does delayed response and streaming. In the
+following article, we'll take look at how this works under L<Catalyst>.
+
+=head1 For More Information
+
+Code associated with this article:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/1to4-Nonblocking-Streaming>
+
+=head1 Summary
+
+We've reviewed various parts of the L<PSGI> specification, and set a good
+foundation of understanding to proceed with the remaining articles.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/11.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/11.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/11.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,178 @@
+=head1 Title
+
+Nonblocking and Streaming
+
+=head1 Overview
+
+Modern versions of L<Catalyst> allow you to take charge of how your
+write operations work. This enables better support for working inside
+common event loops such as L<AnyEvent> and <IO::Async> to support
+non blocking writes to stream large files.
+
+Lets explore how L<PSGI> implements delayed and streaming responses
+and how we can use streaming response with an event loop to enable
+use of nonblocking IO. Then lets see how L<Catalyst> exposes that
+API. This part two of a four part series.
+
+=head1 Introduction
+
+Previous We've seem how L<PSGI> does delayed and streaming responses. Now lets
+translate that to how L<Catalyst> works.
+
+=head1 The Catalyst PSGI application
+
+So you've probably seen the following example of using L<Catalyst> as a L<PSGI>
+application:
+
+ use MyCatalystApp;
+ my $app = MyCatalystApp->psgi_app;
+
+And if that file is called C<mycatalystapp.psgi> you can run it under L<Starman>
+exactly like the simple examples above:
+
+ $ plackup -s Starman mycatalystapp.psgi
+
+But what is going on under the hood with L<Catalyst>? What kind of L<PSGI>
+application is it? As it turns out, the actual L<PSGI> coderef follows the
+delayed and streaming model that we discussed in length during the preceding
+article. I really recommend that you see the full coder over here:
+
+L<https://metacpan.org/source/JJNAPIORK/Catalyst-Runtime-5.90051/lib/Catalyst/Engine.pm#L702>
+
+But here's a snip for discussion, which is from L<Catalyst::Engine>
+
+ sub build_psgi_app {
+ my ($self, $app) = @_;
+
+ return sub {
+ my ($env) = @_;
+
+ return sub {
+ my ($respond) = @_;
+ confess("Did not get a response callback for writer, cannot continue") unless $respond;
+ $app->handle_request(env => $env, response_cb => $respond);
+ };
+ };
+ }
+
+In this case <$app> is you L<Catalyst> application (not to be confused with the
+context, which munges together your application along with request and response
+information). $app at this point is fully initialized, and all the models, views
+and controllers are loaded up.
+
+So what happens is that L<Catalyst> returns to the server a L<PSGI> app in the delayed
+response form. Right here in this method we are not building any responses, we are just
+grabbing the PSGI env and the $responder and sending that off to the ->handle_request
+method of the main $app.
+
+You can refer to the handle_request method here, btw:
+
+L<https://metacpan.org/source/JJNAPIORK/Catalyst-Runtime-5.90051/lib/Catalyst.pm#L2019>
+
+This is a longer method so we won't snip the full code, but the important thing
+to note is that it is this method that prepares the $context, dispatches the
+request, and then calls finalize to serve up the response. The finalize method, you
+can see here:
+
+L<https://metacpan.org/source/JJNAPIORK/Catalyst-Runtime-5.90051/lib/Catalyst.pm#L1830>
+
+And that finalizes the response and also does some housecleaning around stats and logs.
+It finalized the response by calling a method called (oddly enough :) ) C<finalize_body>.
+BTW, it finalized the headers first, as you might expect.
+
+L<Catalyst> plays a bit of a game here, since C<finalize_body> on Catalyst.pm just
+delegates the work to the same named method in L<Catalyst::Engine>. This might just be
+a holdover from the pre PSGI days, but that's what it does now. So to see the real
+guts of how the body gets finalized you need to look over here:
+
+L<https://metacpan.org/source/JJNAPIORK/Catalyst-Runtime-5.90051/lib/Catalyst/Engine.pm#L69>
+
+Now that is a method worth snipping and discussing:
+
+ sub finalize_body {
+ my ( $self, $c ) = @_;
+ return if $c->response->_has_write_fh;
+
+ my $body = $c->response->body;
+ no warnings 'uninitialized';
+ if ( blessed($body) && $body->can('read') or ref($body) eq 'GLOB' ) {
+ my $got;
+ do {
+ $got = read $body, my ($buffer), $CHUNKSIZE;
+ $got = 0 unless $self->write( $c, $buffer ); # same as $c->response->write($body)
+ } while $got > 0;
+
+ close $body;
+ }
+ else {
+ $self->write( $c, $body ); # same as $c->response->write($body)
+ }
+
+ my $res = $c->response;
+ $res->_writer->close;
+ $res->_clear_writer;
+
+ return;
+ }
+
+Ok, breaking it down. $res->_writer is the $writer object you get when
+you call $responder with just the status and headers. Remember, at this
+point L<Catalyst> has already finalized the headers, so its safe to use them.
+If you go look at the C<write> method in L<Catalyst::Response> you'll see what
+I mean here.
+
+Ok so, when you give $c->response->body a string, that string gets written all
+at once, and if you give it a filehandle, it calls ->read on that in blocks
+of size $CHUNKSIZE (which is a global variable you can monkey patch to a higher
+or lower value, btw.). So that's how L<Catalyst> can handle streaming of your
+filehandles. Its very similar to the examples we saw in the previous article
+where we call $writer->write a bunch of times, followed by $writer->close.
+L<Catalyst> is just playing into the L<PSGI> specification here, but of course
+we need to adapt the L<Catalyst> object MVC approach to what L<PSGI> expects.
+
+So this is what happens if you set $c->response->body( $string ) or
+$c->response->body( $filehandle ).
+
+Additionally, L<Catalyst> has long supported the ability to stream writes
+programatically in your Controllers via the L<Catalyst::Response/res-write-data>
+method. This would allow you to stream a response in bits, as you have them.
+For example you could do:
+
+ sub myaction :Local {
+ my ($self, $c) = @_;
+ $c->res->write("Hello");
+ $c->res->write(" ");
+ $c->res->write("World");
+ }
+
+And that would work nearly identically to the much similar example L<PSGI>
+application we've already looked at. The C<finalize_body> method will close
+the writer for you, so you don't need to worry about it.
+
+So between calling the C<write> method on L<Catalyst::Response> and setting
+the response body to a filehandle (or filehandle like, for example this could
+be an in memory filehandle or an object that presented the filehandle API)
+L<Catalyst> leverages a lot of what you can do with a L<PSGI> delayed and/or
+streaming application.
+
+So, what is that "return if $c->response->_has_write_fh;" right at the very top
+of the method all about? In order to understand that we need to step back
+and think about running your L<PSGI> under an event loop and using nonblocking,
+asynchronous I/O, which is our next topic!
+
+=head1 For More Information
+
+Code associated with this article:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/1to4-Nonblocking-Streaming>
+
+=head1 Summary
+
+We've seen how L<Catalyst> leverages its L<PSGI> roots to support delayed and
+streaming responses.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/12.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/12.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/12.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,301 @@
+=head1 Title
+
+Nonblocking and Streaming
+
+=head1 Overview
+
+Modern versions of L<Catalyst> allow you to take charge of how your
+write operations work. This enables better support for working inside
+common event loops such as L<AnyEvent> and <IO::Async> to support
+non blocking writes to stream large files.
+
+Lets explore how L<PSGI> implements delayed and streaming responses
+and how we can use streaming response with an event loop to enable
+use of nonblocking IO. Then lets see how L<Catalyst> exposes that
+API. This part three of a four part series.
+
+=head1 Introduction
+
+We've seen how L<PSGI> allows us to stream long responses and even how
+it works with HTTP 1.1 features such as keep alive. Now, lets see how
+those features can take advantage of non blocking IO, and how L<PSGI>
+runs under event loops.
+
+=head1 Nonblocking
+
+Sometimes when you are streaming data you encounter a process that takes a
+long time. For example, you page requires several long running SQL queries
+to build. Or you have a simple case where you want to stream something
+infinitely. For example, here's an application that sends the time as a
+string followed my a newline once a second, and continues doing so unless
+the client breaks the connection:
+
+ my $psgi_app = sub {
+ my $env = shift;
+ return sub {
+ my $responder = shift;
+ my $writer = $responder->(
+ [200, [ 'Content-Type' => 'text/plain' ]]);
+
+ while(1) {
+ $writer->write(scalar localtime);
+ sleep 1;
+ }
+
+ };
+ };
+
+You might do something like this as a heartbeat monitor, or to stream date
+infinitely to a client (stuff like log into, server status, anything you
+want realtime, or even for gaming applications where you are sending out
+information about the location of a character in realtime).
+
+The problem here is that when using a blocking server like L<Starman>
+you can never have more infinite connections than you have running forks
+(defaults to 5 in the current version of L<Starman>.) So, if you are
+running a huge gaming server that wants to send out continuous information
+about the realtime locations of characters and actions what can you do?
+You can run lots and lots of servers (expensive). Or you can change your
+architecture to have the clients poll the server at regular intervals to
+get updated data. This is a good option and can scale very well, but it
+is not suitable for all use cases. If you have that specific use case
+where you need to maintain a long lived connection to each client, and you
+expect 100s or thousands or more clients, what can you do?
+
+Modern operating systems allow for a concept called 'non blocking I/O'
+this means that when you initiate I/O, over a socket, or a filehandle,
+you don't need to wait until the process is complete, but instead you can
+register a callback (basically an anonymous subroutine) that gets
+called when the I/O job is complete. You can even register callbacks
+to handle exceptional events. This means that instead of having a limited
+number of forked processes that can handled one connection each, you can
+have many (limited by how your operating system is setup and what resources it
+has) connections all at once. The trick here is that instead of doing
+one thing at a time, we have an event loop which manages a schedule of
+events.
+
+Lets rewrite the blocking application to run under an evented server:
+
+ use AnyEvent;
+ use warnings;
+ use strict;
+
+ my $watcher;
+ my $timer_model = sub {
+ my $writer = shift;
+ $watcher = AnyEvent->timer(
+ after => 0,
+ interval => 1,
+ cb => sub {
+ $writer->write(scalar localtime ."\n");
+ });
+ };
+
+ my $psgi_app = sub {
+ my $env = shift;
+ return sub {
+ my $responder = shift;
+ my $writer = $responder->(
+ [200, [ 'Content-Type' => 'text/plain' ]]);
+
+ $timer_model->($writer);
+
+ };
+ };
+
+There's a number of popular systems for managing event loops under Perl,
+including L<POE>, L<AnyEvent> and L<IO::Async>. For this example I choose
+to use L<AnyEvent>. Let's break down the application and see what (if anything)
+this is buying use.
+
+First off, instead of just creating an infinite loop, we create an anonymous
+subroutine to encapsulate the L<AnyEvent> timer model. If you look carefully
+you'll notice this is a closure, which we need in order to make sure the
+C<$watcher> doesn't go out of scope. C<$watcher> is a sort of pointer to
+the event loop, and if it gets undefined by going out of scope, then the timer
+itself would get removed from the event loop, and never run. We could have
+just as easily made this a real object, but a closure is simpler for this case.
+
+Then, when the the L<PSGI> application runs and receives a request, it invokes
+the closure with the C<$writer> object. This then starts a timer event, which
+every second runs the callback to output the time.
+
+So, how is this better than the shorter an more simple version that runs under
+L<Starman>? This timer is not waiting a second between callback. It not
+blocking the server. As a result, the L<Twiggy> based server can accept many
+more connections than L<Starman> with relatively low overhead in doing so.
+Generally you can have hundreds or even thousands of concurrent connections
+using this technique and have far lower overhead than if you have L<Starman>
+running with 1000 or 2000 forked children. We can see this in action
+
+ $ TWIGGY_DEBUG=1 plackup bin/time-server-evented.psgi
+ Listening on 0.0.0.0:5000
+ Twiggy: Accepting connections at http://0.0.0.0:5000
+
+Now lets open this in telnet
+
+ $ telnet 127.0.0.1 5000
+ Trying 127.0.0.1...
+ Connected to localhost.
+ Escape character is '^]'.
+ GET / HTTP/1.0
+
+ HTTP/1.0 200 OK
+ Content-Type: text/plain
+
+ Thu Nov 28 18:12:33 2013
+ Thu Nov 28 18:12:34 2013
+ Thu Nov 28 18:12:35 2013
+ Thu Nov 28 18:12:36 2013
+ Thu Nov 28 18:12:37 2013
+ Thu Nov 28 18:12:38 2013
+ Thu Nov 28 18:12:39 2013
+ Thu Nov 28 18:12:40 2013
+ Thu Nov 28 18:12:41 2013
+
+If you run this yourself (just checkout the repo on Github, links below) you
+will note two things. First of all, L<Twiggy> is not HTTP/1.1 compliant,
+so we send a HTTP/1.0 GET request. So L<Twiggy> isn't supporting chunked
+encoding and you'd have to request keep alive if you want it. Its not a big
+deal just something to pay attention to.
+
+Another thing you'd note is that unlike L<Starman>, L<Twiggy> does not have
+a timeout on the connection. This is because with L<Twiggy> the overhead on
+the connection is very low, each incoming request does not need to tie up an
+entire child fork (like with L<Starman>, or other forking and/or blocking
+servers.) Instead, the server listens for events and when an event comes in
+the appropriate callback gets to handle it. In the background, the event loop
+is managing all the events.
+
+The big win here is that the new version of this app can allow many, many
+connections all at once, and each connection can listen to the infinite
+stream (unlike with L<Starman> where you are limited to the number of running
+workers).
+
+Lets prove that by using Apache C<ab> ( a simple load tester that comes with
+the apache webserver). First, lets change the application to finalize the
+connection after 4 seconds:
+
+ use AnyEvent;
+ use warnings;
+ use strict;
+
+ my $watcher;
+ my $timer_model = sub {
+ my $writer = shift;
+ my $count = 1;
+ $watcher = AnyEvent->timer(
+ after => 0,
+ interval => 1,
+ cb => sub {
+ $writer->write(scalar localtime ."\n");
+ if(++$count > 5) {
+ $writer->close;
+ undef $watcher;
+ }
+ });
+ };
+
+ my $psgi_app = sub {
+ my $env = shift;
+ return sub {
+ my $responder = shift;
+ my $writer = $responder->(
+ [200, [ 'Content-Type' => 'text/plain' ]]);
+
+ $timer_model->($writer);
+
+ };
+ };
+
+Start this up:
+
+ $ TWIGGY_DEBUG=1 plackup bin/five-times-evented.psgi
+ Listening on 0.0.0.0:5000
+ Twiggy: Accepting connections at http://0.0.0.0:5000/
+
+Ok so each request is going to take 4 seconds to finish. We can see that
+via telnet:
+
+ $ telnet 127.0.0.1 5000
+ Trying 127.0.0.1...
+ Connected to localhost.
+ Escape character is '^]'.
+ GET / HTTP/1.0
+
+ HTTP/1.0 200 OK
+ Content-Type: text/plain
+
+ Thu Nov 28 19:56:15 2013
+ Thu Nov 28 19:56:16 2013
+ Thu Nov 28 19:56:17 2013
+ Thu Nov 28 19:56:18 2013
+ Thu Nov 28 19:56:19 2013
+ Connection closed by foreign host.
+
+So, if a similar application was running under L<Starman>, with 5 running forks
+(the default), and you hit the server with 100 simultaneous requests, you'd
+expect the entire thing to take about 80 seconds (likely more because of network
+latency and so forth, but it would never be faster). What happens if we hit
+this with Apache C<ab> with the same concurrent 100 requests?
+
+ $ ab -n100 -c100 http://127.0.0.1:5000/
+ This is ApacheBench, Version 2.3 <$Revision: 655654 $>
+ Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
+ Licensed to The Apache Software Foundation, http://www.apache.org/
+
+ Benchmarking 127.0.0.1 (be patient).....done
+
+ Server Hostname: 127.0.0.1
+ Server Port: 5000
+
+ Document Path: /
+ Document Length: 0 bytes
+
+ Concurrency Level: 100
+ Time taken for tests: 4.039 seconds
+ Complete requests: 100
+ Failed requests: 2
+ (Connect: 0, Receive: 0, Length: 2, Exceptions: 0)
+ Write errors: 0
+ Total transferred: 4650 bytes
+ HTML transferred: 150 bytes
+ Requests per second: 24.76 [#/sec] (mean)
+ Time per request: 4039.357 [ms] (mean)
+ Time per request: 40.394 [ms] (mean, across all concurrent requests)
+ Transfer rate: 1.12 [Kbytes/sec] received
+
+So the whole thing took a bit over four seconds! And we handled the 100 connections
+all at the same time!
+
+That's the upside of the extra work of running everything in an evented manner
+and taking advantage of nonblocking IO.
+
+B<Note> I just want to point out to make a robust system you need to take care
+to monitor and handle error events, since everything is running under one big
+process any uncaught errors can crash the server!
+
+B<Note> I also want to point out that although high concurrency is a great trick
+to have, concurrency alone isn't the only answer to high scale. Depending on the
+type of application you are building it may or may not have value.
+
+Ok, so now you have the basics of evented and nonblocking IO! Lets port this
+very application to run as a L<Catalyst> application! (In the next article
+of course...)
+
+=head1 For More Information
+
+Code associated with this article:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/1to4-Nonblocking-Streaming>
+
+=head1 Summary
+
+We've introduced how to use an event loop with a non blocking webserver such as
+L<Twiggy> to write a non blocking PSGI application.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/13.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/13.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/13.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,260 @@
+=head1 Title
+
+Nonblocking and Streaming
+
+=head1 Overview
+
+Modern versions of L<Catalyst> allow you to take charge of how your
+write operations work. This enables better support for working inside
+common event loops such as L<AnyEvent> and <IO::Async> to support
+non blocking writes to stream large files.
+
+Lets explore how L<PSGI> implements delayed and streaming responses
+and how we can use streaming response with an event loop to enable
+use of nonblocking IO. Then lets see how L<Catalyst> exposes that
+API. This part four of a four part series,
+
+=head1 Introduction
+
+So now we know how to use a L<PSGI> application under an event loop
+and how to write non blocking applications. Let's port our five second
+heartbeat application to L<Catalyst>!
+
+=head1 Catalyst Non Blocking Streams
+
+In the past we've discussed in detail how the L<Catalyst> L<PSGI> application
+is created, and did a bit of tracing regarding what happens when a request to
+that application is made. So at this point you know that L<Catalyst> is using
+the delayed form of a L<PSGI> app, and whats more, it finalizes headers early
+so that you can access to a L<$writer> object, suitable for streaming. And
+we've discussed how one can use $response->write to write to that, (and briefly
+spoke about chunked transfer encoding.)
+
+So that is all fine for streaming under a blocking server like L<Starman>. But
+how might we convert the non blocking timer we wrote in the previous example?
+
+As it turns out, its quite trivial to do so. Here's a simple translation of
+the 5 second timer example. This is probably not the best way to write this
+using L<Catalyst>, but it would work (L<Catalyst> is after all just Perl, and
+a controller is just a class, sometimes we seem to forget).
+
+ package MyApp::Controller::Root;
+
+ use base 'Catalyst::Controller';
+ use AnyEvent;
+
+ my $watcher;
+ my $timer_model = sub {
+ my $writer = shift;
+ my $count = 1;
+ $watcher = AnyEvent->timer(
+ after => 0,
+ interval => 1,
+ cb => sub {
+ $writer->write(scalar localtime ."\n");
+ if(++$count > 5) {
+ $writer->close;
+ undef $watcher;
+ }
+ });
+ };
+
+ sub time_server :Path(/) {
+ my ($self, $c) = @_;
+ $timer_model->($c->response->write_fh);
+ }
+
+ 1;
+
+Its actually quite similar to the plain old PSGI version. We create a closure
+over an L<AnyEvent> timer watcher, and then call that with the $writer object.
+In L<Catalyst> one gets access to the $writer via the L<Catalyst::Response/res-write_fh>
+method. Now, you need to know, once you've requested this object, you are
+expected to close the writer manually. That's because 'finalize_body'
+checks a flag to see if you've requested the writer and if you have, it skips
+the rest of the body finalization. You might have noticed that in the code
+to finalize_body, over in L<Catalyst::Engine> (if you don't thi might be a good
+time to have a second look). So, once you've asked for manual control you have
+to drive stick all the way home!
+
+So this works just as it is, but its not a great L<Catalyst> application. The
+controller is pretty heavy and there's no reusable bits. Lets spend a bit of
+time to refactor this into something that starts to resemble what a L<Catalyst>
+application should be.
+
+First lets take that closure and convert it into a class. There's a few
+approaches but this comes to mind, after pondering it a bit.
+
+ package MyApp::Timer;
+
+ use Moose;
+ use AnyEvent;
+
+ has 'writer' => (
+ is => 'bare',
+ required => 1,
+ handles => ['write', 'close']);
+
+ has 'counter' => (
+ traits => ['Counter'],
+ is => 'ro',
+ required => 1,
+ handles => {
+ decrement_counter => 'dec'});
+
+ has 'watcher' => (
+ is => 'ro',
+ lazy_build => 1,
+ init_arg => undef,
+ clearer => 'clear_watcher');
+
+ sub _build_watcher {
+ my $self = shift;
+ return AnyEvent->timer(
+ after => 0,
+ interval => 1,
+ cb => sub { $self->write_or_finalize } );
+ }
+
+ sub start { shift->watcher }
+
+ sub write_or_finalize {
+ my $self = shift;
+ $self->decrement_counter >= 0
+ ? $self->write_timestamp
+ : $self->finalize;
+ }
+
+ sub write_timestamp {
+ my $self = shift;
+ $self->write(scalar localtime ."\n");
+ }
+
+ sub finalize {
+ my $self = shift;
+ $self->close;
+ $self->clear_watcher;
+ }
+
+ __PACKAGE__->meta->make_immutable;
+
+This version has a few additional tricks in that you can set the counter via
+initialization. We also try to split up the functionality a bit, and we do our
+best to take advantage of the bits that L<Moose> gives us. But all in all it
+basically does the same thing, just this time in a neater package that you can
+write unit tests for, and hopefully this is a step toward reusable code.
+
+Ok, now that we've written the class, how do we expose it to yout L<Catalyst>
+application. I've always found that L<Catalyst::Model::Adaptor> is pretty
+great at this. Here's one way to adapt this class for L<Catalyst>, via an
+application specific model:
+
+ package MyApp::Model::Timer;
+
+ use Moose;
+
+ extends 'Catalyst::Model::Factory';
+
+ has 'counter' => (is=>'ro', isa=>'Num', required=>1);
+
+ sub prepare_arguments {
+ my ($self, $c, $args) = @_;
+ return +{
+ writer => $c->res->write_fh,
+ counter => $self->counter};
+ }
+
+ __PACKAGE__->meta->make_immutable;
+
+We're using the factory version of L<Catalyst::Model::Adaptor> because we want
+a new timer for each request. Since this adaptor does C<ACCEPT_CONTEXT> we can
+go ahead and grab the $writer right out of the request. Last, we'll configure
+the counter via general L<Catalyst> configuration. Let's take a look at that
+next:
+
+ package MyApp;
+
+ use Catalyst;
+
+ __PACKAGE__->config(
+ 'Model::Timer' => {
+ class => 'MyApp::Timer',
+ counter => 5});
+
+ __PACKAGE__->setup;
+
+If you are using something like the ConfigLoader plugin, you could have one
+version of this for development (with a debug version of the timer for example)
+and another for production. Its just a neat trick that L<Catalyst> lets you do
+by having this clean separation.
+
+So we need a bit of configuration and that sets up the evented timer! All that
+is left is the controller. What does that look like now?
+
+ package MyApp::Controller::Root;
+
+ use base 'Catalyst::Controller';
+
+ sub time_server :Path(/) {
+ my ($self, $c) = @_;
+ $c->model('Timer')->start;
+ }
+
+ 1;
+
+Ok, that's the skinny controller I wanted to see! Now we have a much better
+designed application. Most of the real work is in a stand alone class, and the
+L<Catalyst> bits is mostly glue to tie that model to a request. Now, if we
+run this application:
+
+ plackup -Ilib -MMyApp -s Twiggy -e 'MyApp->psgi_app'
+ Twiggy: Accepting connections at http://0.0.0.0:5000/
+ 127.0.0.1 - - [28/Nov/2013:22:26:28 -0600] "GET / HTTP/1.0" 200 - "-" "-"
+
+We can hit it with telnet, Apache AB, whatever, and it works just like the
+plain old PSGI version (except I hope we have a stronger structure going
+forward)
+
+ $ telnet 127.0.0.1 5000
+ Trying 127.0.0.1...
+ Connected to localhost.
+ Escape character is '^]'.
+ GET / HTTP/1.0
+
+ HTTP/1.0 200 OK
+
+ Thu Nov 28 21:08:32 2013
+ Thu Nov 28 21:08:33 2013
+ Thu Nov 28 21:08:34 2013
+ Thu Nov 28 21:08:35 2013
+ Thu Nov 28 21:08:36 2013
+ Connection closed by foreign host.
+
+If you do careful testing you'll probably note that the L<Catalyst> version
+has a bit more overhead overall (the five second test takes maybe 5.150 verses
+5.050) due to the fact a lot more code is involved. But you get a lot for that
+payment, in my opinion at least!
+
+This concludes our four part article on the basics of L<Catalyst> streaming and
+non blocking. L<Catalyst> has only had these features exposed in public API
+for less than a year, so its up to you, the user community, to take charge of
+all the great stuff and do awesome work with it. Hopefully Advent 2014 will be
+chock full of examples along these lines!
+
+=head1 For More Information
+
+Code associated with this article:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/1to4-Nonblocking-Streaming>
+
+=head1 Summary
+
+You've learned how to take charge the the L<PSGI> writer that sits underneath
+every L<Catalyst> response in order to take advantage of some basic non blocking
+code, running under L<AnyEvent> and L<Twiggy>.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/14.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/14.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/14.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,217 @@
+=head1 Title
+
+Streaming Nonblocking Files
+
+=head1 Overview
+
+Use Nonblocking IO and an Event Loop to concurrently stream a large file.
+
+=head1 Introduction
+
+In previous articles this advent, we explored how L<Catalyst> can work with the
+L<PSGI> specification and an event loop like L<AnyEvent> to support high
+concurrency. Lets put it together with what we've learned about streaming and
+build a L<Catalyst> powered high concurrency, large file stream.
+
+=head1 Using IO::AIO with AnyEvent and PSGI to enable nonblocking streams
+
+L<IO::AIO> is a CPAN distribution to enable non blocking file level operations
+and it is compatible with many event loops including L<AnyEvent>. Using this
+library you can open and read a large file in a non blocking manner. Lets take
+a quick look at how we might use this with L<PSGI> to serve up a file:
+
+ use warnings;
+ use strict;
+ use AnyEvent::AIO;
+ use IO::AIO;
+
+ my $read_chunk;
+ $read_chunk = sub {
+ my ($writer, $fh, $offset) = @_;
+ my $buffer = '';
+ aio_read $fh, $offset, 65536, $buffer, 0, sub {
+ my $status = shift;
+ die "read error[$status]: $!" unless $status >= 0;
+ if($status) {
+ $writer->write($buffer);
+ $read_chunk->($writer, $fh, ($offset + 65536));
+ } else {
+ $writer->close;
+ aio_close $fh, sub { };
+ }
+ }
+ };
+
+ my $psgi_app = sub {
+ my $env = shift;
+ return sub {
+ my $responder = shift;
+ my $writer = $responder->(
+ [200, [ 'Content-Type' => 'text/plain' ]]);
+
+ aio_open 'root/lorem.txt', IO::AIO::O_RDONLY, 0, sub {
+ my ($fh) = @_ or die $!;
+ $read_chunk->($writer, $fh, 0);
+ };
+ };
+ };
+
+Again we'll use a closure since that's the simple thing to do. The most
+important bits here are the C<aio_open> and C<aio_read>. C<aio_open> initiates
+the request to open the file and associates a callback that gets run when the
+open file handle is ready. We then recursively call C<aio_read> on this open
+filehandle and with each chuck we read, we call C<write> on the L<PSGI> $writer
+object we've spoken of in such great detail previously. When there is no more
+data, we close the filehandle and the $writer object. And that's really there
+is too it!
+
+=head1 Porting this to Catalyst
+
+We could do a dumb port and have everything in one controller, but since we are
+using L<Catalyst> and have such great tools to compartmentalize code, lets try
+to do the right thing. First, let's create a model for the code the reads a
+file and writes it.
+
+ package MyApp::Stream;
+
+ use Moose;
+ use AnyEvent::AIO;
+ use IO::AIO;
+
+ has 'writer' => (
+ is => 'bare',
+ required => 1,
+ handles => ['write', 'close']);
+
+ has 'path' => (is=>'ro', required=>1);
+
+ sub start {
+ my $self = shift;
+ aio_open $self->path, IO::AIO::O_RDONLY, 0, sub {
+ my ($fh) = @_ or die "${\$self->path}: $!";
+ warn scalar localtime;
+ $self->read_chunk($fh, 0);
+ };
+ }
+
+ sub read_chunk {
+ my ($self, $fh, $offset) = @_;
+ my $buffer = '';
+ aio_read $fh, $offset, 65536, $buffer, 0, sub {
+ my $status = shift;
+ die "read error[$status]: $!" unless $status >= 0;
+ if($status) {
+ $self->write($buffer);
+ $self->read_chunk($fh, ($offset + 65536));
+ } else {
+ $self->close;
+ aio_close $fh, sub { };
+ }
+ }
+ }
+
+One nice thing about doing this is how easy it is to write a test case and to
+mock the writer object.
+
+ use MyApp;
+ use MyApp::Stream;
+
+ {
+ package MockWriter;
+ use Test::Most;
+
+ sub new { bless {lines=>[]}, shift }
+
+ sub write {
+ my ($self, $line) = @_;
+ push @{$self->{lines}}, $line;
+ }
+
+ sub close {
+ my ($self) = @_;
+ ok 1;
+ ok @{$self->{lines}};
+ done_testing;
+ }
+ }
+
+ my $mocker = MockWriter->new;
+ my $streamer = MyApp::Stream->new(
+ path => MyApp->path_to('root','lorem.txt')->stringify,
+ writer => $mocker);
+
+ $streamer->start;
+
+I know there's a bunch of Test mock objects on CPAN but I usually find it just
+as easy to make my own, particularly with this tricky asynchronous stuff.
+
+Anyway, lets adapt this model into L<Catalyst>
+
+ package MyApp::Model::Stream;
+
+ use Moose;
+
+ extends 'Catalyst::Model::Factory';
+
+ has 'path' => (is=>'ro', required=>1);
+
+ sub prepare_arguments {
+ my ($self, $c, $args) = @_;
+ return +{
+ writer => $c->res->write_fh,
+ path => $self->path->stringify };
+ }
+
+ __PACKAGE__->meta->make_immutable;
+
+This should look pretty familiar if you've read the previous articles on
+nonblocking and streaming.
+
+This of course requires a bit of configuration
+
+ package MyApp;
+
+ use Catalyst;
+
+ __PACKAGE__->config(
+ 'Model::Stream' => {
+ class => 'MyApp::Stream',
+ path => __PACKAGE__->path_to('root','lorem.txt') });
+
+ __PACKAGE__->setup;
+
+I suppose that could all just go into the adaptor class. but L<Catalyst> makes
+it so easy and fun to do this type of configuaration I usually just go ahead!
+
+Finally the controller is nice and skinny, just the way we like it!
+
+ package MyApp::Controller::Root;
+
+ use base 'Catalyst::Controller';
+
+ sub streamer :Path(/) {
+ my ($self, $c) = @_;
+ $c->model('Stream')->start;
+ }
+
+ 1;
+
+So that should give you something to play with, and one more nonblocking example
+to help you figure out how to use this technique in your own projects.
+
+=head1 For More Information
+
+Code associated with this article:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/NonBlocking-File-Streaming>
+
+=head1 Summary
+
+We've taken a look at one way to stream a large file with L<Catalyst> using a
+nonblocking approach.
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
Added: trunk/examples/CatalystAdvent/root/2013/15.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2013/15.pod (rev 0)
+++ trunk/examples/CatalystAdvent/root/2013/15.pod 2013-12-02 02:42:17 UTC (rev 14469)
@@ -0,0 +1,219 @@
+=head1 Title
+
+A Websocket's Echo Server in L<Catalyst>
+
+=head1 Overview
+
+This past year L<Catalyst> got the basics of support for long / persistent
+connections so that you could build realtime applications over cometd and
+websockets. Lets build the classic websockets echo server.
+
+=head1 Introduction
+
+"The websockets specification defines an API that enables web pages to use the
+WebSockets protocol for two-way communication with a remote host." - L<http://www.websocket.org/aboutwebsocket.html>.
+
+One of the basic examples you find on the websockets website is the Echo server
+which you can see over here: L<http://www.websocket.org/echo.html> Any web
+framework which claims support should provide a version, just to show off the
+basics. Let's do it in L<Catalyst>!
+
+=head1 The Controller
+
+ package MyApp::Controller::Root;
+
+ use base 'Catalyst::Controller';
+ use Protocol::WebSocket::Handshake::Server;
+ use AnyEvent::Handle;
+
+
+ sub index :Path(/)
+ {
+ my ($self, $c) = @_;
+ my $url = $c->uri_for_action($self->action_for('ws'));
+
+ $url->scheme('ws');
+ $c->stash(websocket_url => $url);
+ $c->forward($c->view('HTML'));
+ }
+
+ sub ws :Path(/echo)
+ {
+ my ($self, $c) = @_;
+ my $io = $c->req->io_fh;
+ my $hs = Protocol::WebSocket::Handshake::Server
+ ->new_from_psgi($c->req->env);
+
+ $hs->parse($io);
+
+ my $hd = AnyEvent::Handle->new(fh => $io);
+ $hd->push_write($hs->to_string);
+ $hd->push_write($hs->build_frame(buffer => "Echo Initiated")->to_bytes);
+
+ $hd->on_read(sub {
+ (my $frame = $hs->build_frame)->append($_[0]->rbuf);
+ while (my $message = $frame->next) {
+ $message = $hs->build_frame(buffer => $message)->to_bytes;
+ $hd->push_write($message);
+ }
+ });
+ }
+
+ __PACKAGE__->config( namespace => '');
+
+So there's a controller with jsut two actions. Lets look at the first:
+
+ sub index :Path(/)
+ {
+ my ($self, $c) = @_;
+ my $url = $c->uri_for_action($self->action_for('ws'));
+
+ $url->scheme('ws');
+ $c->stash(websocket_url => $url);
+ $c->forward($c->view('HTML'));
+ }
+
+All we are doing here is creating a single URL in the stash and sending it
+on to the view. This is the URL of the websockets handler (which is why we
+need to change the schema to 'ws'.
+
+We are not using the standard 'renderview' actionclass in this trivial
+application so I go ahead and forward on the view. Personally I am not a fan
+of the renderview actionclass and quite often just handle it like this.
+
+Lets look at the view (warning Javascript ahead for the unwilling).
+
+ <!DOCTYPE html>
+ <html lang="en">
+ <head>
+ <title>WebSocket Echo Client</title>
+ <meta charset="UTF-8" />
+ <script>
+ "use strict";
+ window.addEventListener("load", function(event) {
+ var status = document.getElementById("status");
+ var url = document.getElementById("url");
+ var open = document.getElementById("open");
+ var close = document.getElementById("close");
+ var send = document.getElementById("send");
+ var text = document.getElementById("text");
+ var message = document.getElementById("message");
+ var socket;
+
+ status.textContent = "Not Connected";
+ url.value = "[% websocket_url %]";
+ close.disabled = true;
+ send.disabled = true;
+
+ // Create a new connection when the Connect button is clicked
+ open.addEventListener("click", function(event) {
+ open.disabled = true;
+ socket = new WebSocket(url.value);
+
+ socket.addEventListener("open", function(event) {
+ close.disabled = false;
+ send.disabled = false;
+ status.textContent = "Connected";
+ });
+
+ // Display messages received from the server
+ socket.addEventListener("message", function(event) {
+ message.textContent = "Server Says: " + event.data;
+ });
+
+ // Display any errors that occur
+ socket.addEventListener("error", function(event) {
+ message.textContent = "Error: " + event;
+ console.log("my object: %o", event);
+ });
+
+ socket.addEventListener("close", function(event) {
+ open.disabled = false;
+ status.textContent = "Not Connected";
+ });
+ });
+
+ // Close the connection when the Disconnect button is clicked
+ close.addEventListener("click", function(event) {
+ close.disabled = true;
+ send.disabled = true;
+ message.textContent = "";
+ socket.close();
+ });
+
+ // Send text to the server when the Send button is clicked
+ send.addEventListener("click", function(event) {
+ socket.send(text.value);
+ text.value = "";
+ });
+ });
+ </script>
+ </head>
+ <body>
+ Status: <span id="status"></span><br />
+ URL: <input id="url" /><br />
+ <input id="open" type="button" value="Connect" />
+ <input id="close" type="button" value="Disconnect" /><br />
+ <input id="send" type="button" value="Send" />
+ <input id="text" /><br />
+ <span id="message"></span>
+ </body>
+ </html>
+
+As this is a L<Catalyst> article, I am not going to step through this line by
+line, but to cover it in general I am using the plainest Javascript here (yes
+if we used a Javascript framework there'd be less code, but I don't want to
+obscure the point with yet another framework). I associate various callbacks
+as event handlers for the most important bits of DOM here. The biggest part
+is the bit that opens the websocket and does the send and receive. That gets
+hooked up to the 'ws' action. Lets look at that.
+
+ sub ws :Path(/echo)
+ {
+ my ($self, $c) = @_;
+ my $io = $c->req->io_fh;
+ my $hs = Protocol::WebSocket::Handshake::Server
+ ->new_from_psgi($c->req->env);
+
+ $hs->parse($io);
+
+ my $hd = AnyEvent::Handle->new(fh => $io);
+ $hd->push_write($hs->to_string);
+ $hd->push_write($hs->build_frame(buffer => "Echo Initiated")->to_bytes);
+
+ $hd->on_read(sub {
+ (my $frame = $hs->build_frame)->append($_[0]->rbuf);
+ while (my $message = $frame->next) {
+ $message = $hs->build_frame(buffer => $message)->to_bytes;
+ $hd->push_write($message);
+ }
+ });
+ }
+
+Since websocket support is new in L<Catalyst> there's not a lot of pretty helpers
+and shortcut methods. So we need to call L<Protocol::WebSocket> to initiate the
+websocket, and then we create a 'on_read' handler to listen on the socket, and the
+we add to the write queue whatver shows up.
+
+The key to the magic is the L<Catalyst::Request> method C<io_fh>. This gives you
+low level access to the underlying C<psgix.io> socket, and is also a flag to
+L<Catalyst> so that it never tries to finalize the body (since you are never really
+closing the connection).
+
+So, that's really it!
+
+=head1 Summary
+
+Although support for techniques like websockets is still rather new to
+L<Catalyst> you can still use it for testing and for helping us figure
+out where to go next. So, go play!
+
+Code associated with this article:
+
+L<https://github.com/perl-catalyst/2013-Advent-Staging/tree/master/Websocket-Echo>
+
+=head1 Author
+
+John Napiorkowski L<email:jjnapiork at cpan.org>
+
+=cut
More information about the Catalyst-commits
mailing list