[Catalyst-commits] r14531 - trunk/examples/CatalystAdvent/root/2014

jnapiorkowski at dev.catalyst.perl.org jnapiorkowski at dev.catalyst.perl.org
Mon Dec 1 17:05:41 GMT 2014


Author: jnapiorkowski
Date: 2014-12-01 17:05:41 +0000 (Mon, 01 Dec 2014)
New Revision: 14531

Modified:
   trunk/examples/CatalystAdvent/root/2014/3.pod
Log:
article 3

Modified: trunk/examples/CatalystAdvent/root/2014/3.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2014/3.pod	2014-12-01 16:45:23 UTC (rev 14530)
+++ trunk/examples/CatalystAdvent/root/2014/3.pod	2014-12-01 17:05:41 UTC (rev 14531)
@@ -1,53 +1,90 @@
-=head1 Plack::Middleware::HTTPExceptions 
+=head1 PSGI Environment Utilities 
 
 =head1 Overview
 
-Use an exception object as your response
+Help to properly localize your $PSGI env
 
 =head1 Introduction
 
-One of the great thing about L<Catalyst> is its strong separation of concerns.
-This of course is a hallmark of the MVC pattern.  However there are times when
-it is a bit onerous to always require a separate view to build a response.  For
-simple cases you can now just throw an exception in your controller (or in
-code called by the controller) and if that exception conforms to the interface
-defined by L<Plack::Middleware::HTTPExceptions> we automatically build a
-meaningful HTTP response.
+We added a feature to L<Catalyst> that allows you to use the response of another
+Plack type application as your main response.  In order to take better advantage
+of this new feature we added some utility helpers that lets you localize the
+$env under the current controller or action.
 
 =head1 Example
 
-    package MyApp::Controller::User;
+Here's a simple example that uses the bundled Plack static file appliaction to
+serve files under a L<Catalyst> controller;
 
+    package MyApp::Controller::Static;
+
     use base 'Catalyst::Controller';
-    use HTTP::Exception;
+    use Plack::App::File;
 
-    sub find_user_at :Path('') Args(1) {
-      my ( $self, $c, $arg ) = @_;
-      $c->stash(user => $c->model(‘DB::User’)->from_id($arg) || 	
-        HTTP::Exception->throw(404, status_message=>”Not Found"));
+    my $app = Plack::App::File->new(root => "static")->to_app;
+
+    sub serve :Path('') Args {
+      my ( $self, $c) = @_;
+      my $env = $c->req->env;
+      $c->res->from_psgi_response($app->($env));
     }
 
     1;
 
 =head1 Discussion
 
-In the above example we have a URL template like "/user/{:arg}" and we expect
-the $arg to be an ID that can be used to find a User resource from some storage
-such as a L<DBIx::Class> backed database.  However it is possible that the user
-will not be found from th given ID.  In that case we want to return something
-meaningful to the client, such as a 404 NOT FOUND response.  In the example above
-this is what we do.
+This would not work as expected since the C<$env>) passed to the File serving
+application will have "/static/@args" (like /static/favicon.ico, /static/js/app.js)
+as its PATH info.  This means that your directory structure would need to be like
+"./static/static/favicon.ico" or "./static/static/js/apps.js".  It is likely you
+would prefer and expect this to work similiarly to how L<Plack::Builder>'s 
+'mount' works.  This 'localizes' the C<$env> such as to make the underlying
+application think the mounted path is the root path or in other words instead
+of /static/static/favicon.ico you have /static/favicon.ico.
 
-L<Catalyst> supports this via the now included L<Plack::Middleware::HTTPExceptions>
-and you can use L<HTTP::Exception> or L<HTTP::Throwable>.  However the interface is
-trival and its easy to roll your own expection objects.
+For these cases L<Catalyst> now bundles three utility functions to localize the
+C<$env> under the controller namespace, the action namespace or the current 
+path.  Of the three localizing under the action namespace is the one you are most
+likely to use since it most closely resembles how L<Plack::Builder>'s mount works.
+Lests rewrite the above.
 
-I find this technique works well when I need to rapidly mock up an API or in the
-beginning stages of development when I don't have all the error response pages I
-need.  Its also great for simple demos!  I find it falls apart when the response
-case is more complex, such as if the response needs to be subject to content
-negotiation (for example when you API can support XML or JSON).
+    package MyApp::Controller::Static;
 
+    use base 'Catalyst::Controller';
+    use Plack::App::File;
+    use Catalyst::Utils;
+
+    my $app = Plack::App::File->new(root => "static")->to_app;
+
+    sub serve :Path('') Args {
+      my ( $self, $c) = @_;
+      my $env = $c->Catalyst::Utils::env_at_action;
+      $c->res->from_psgi_response($app->($env));
+    }
+
+    1;
+
+and lets assume you have a directory structure like this:
+
+    /$ROOT
+      /lib
+      /t
+      /static
+        /js
+          app.js
+          jquery.js
+        /css
+          main.css
+          locale.css
+        favicon.ico
+
+Now when you GET localhost://static/js/app.js this will service the file located
+at $ROOT/static/js/app.js
+
+See L<https://metacpan.org/pod/Catalyst::Utils#PSGI-Helpers> for more.
+
+Alternatives include L<Catalyst::Action::FromPSGI> and L<CatalystX::Controller::PSGI>.
+
 =head1 More Information
 
 You should review L<Plack::Middleware::HTTPExceptions> for more details.




More information about the Catalyst-commits mailing list