[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