Automatic JSON serializer breaks error page
Apparently you cannot have both serializer: "JSON" show_errors: 1 in your config.yml. Enabling the automatic JSON serializer defeats the error screen, returning the exception error object as JSON to the client: { "exception" : "Text::Xslate: LoadError: Cannot find 'foo.tx' (path: /home/bla/qux) at /usr/lib/perl5/site_perl/5.8.8/Dancer/Template/Xslate.pm line 52.\n", "error" : "Text::Xslate: LoadError: Cannot find 'foo.tx' (path: /home/bla/qux) at /usr/lib/perl5/site_perl/5.8.8/Dancer/Template/Xslate.pm line 52.\n" } Is there a way I can fix this without going back to manual JSON encoding? (i.e. Setting content_type('application/json') and using to_json() on objects in route handlers.)
On 14-03-13 08:57 PM, Warren Young wrote:
Is there a way I can fix this without going back to manual JSON encoding?
My first thought is: do something with the 'before_serializer' hook. hook 'before_serializer' => sub { my $res = shift; # set the answer to a glorious nothing if an exception is caught $rest->content({}) if $res->content->{exception}; }; disclaimer: I didn't try it, so I might be wrong. Joy, `/anick
On 3/13/2014 19:16, Yanick Champoux wrote:
On 14-03-13 08:57 PM, Warren Young wrote:
Is there a way I can fix this without going back to manual JSON encoding?
My first thought is: do something with the 'before_serializer' hook.
While Lee's solution works for me, it would be nice if Dancer would let me restrict the automatic serializer to a route prefix: serializer: format: JSON prefix: /api That would entirely replace Lee's solution. This wouldn't break backwards compatibility. If you give 'serializer' a scalar, it can use its current global behavior. Passing an array of hashes instead of a hash could allow different serializers for different parts of your route scheme: serializer: - format: JSON prefix: /api - format: Data::Dumper prefix: /debug
On Thu, 13 Mar 2014 18:57:04 -0600 Warren Young <warren@etr-usa.com> wrote:
Apparently you cannot have both
serializer: "JSON" show_errors: 1
in your config.yml. Enabling the automatic JSON serializer defeats the error screen, returning the exception error object as JSON to the client: <snip>
You could argue that's correct and desired behaviour - if you have set serialiser: "JSON", you are, presumably, writing an API, which will be used by API consumers expecting JSON. Suddenly dumping a HTML error page at them instead of the JSON they were expecting would be silly and wrong - returning JSON describing the error seems much more sane. So, I wouldn't say it breaks the error page, I'd say it's logical behaviour. If you don't want it, though, you could probably get round it with Yanick's suggestion of using before_serializer. -- David Precious ("bigpresh") <davidp@preshweb.co.uk> http://www.preshweb.co.uk/ www.preshweb.co.uk/twitter www.preshweb.co.uk/linkedin www.preshweb.co.uk/facebook www.preshweb.co.uk/cpan www.preshweb.co.uk/github
we've had this issue for a while since we run REST services and webapp out of same code base. We do this: hook before_error_init => sub { my $err_obj = shift; if ( request->path !~ m{^/api/} && ( my $ser = setting('serializer') ) ) { set 'serializer', undef; $err_obj->{_save_serializer} = $ser; } }; And then restore it: hook after_error_render => sub { my $response = shift; my $err_obj = vars->{_save_err_obj}; if ( my $ser = delete $err_obj->{_save_serializer} ) { set 'serializer', $ser; } }; I could see adding a config option to only do this in dev or test environments since i'd guess in production, you would want to log the error in JSON. HTH, Lee On Fri, Mar 14, 2014 at 5:20 AM, David Precious <davidp@preshweb.co.uk>wrote:
On Thu, 13 Mar 2014 18:57:04 -0600 Warren Young <warren@etr-usa.com> wrote:
Apparently you cannot have both
serializer: "JSON" show_errors: 1
in your config.yml. Enabling the automatic JSON serializer defeats the error screen, returning the exception error object as JSON to the client: <snip>
You could argue that's correct and desired behaviour - if you have set serialiser: "JSON", you are, presumably, writing an API, which will be used by API consumers expecting JSON. Suddenly dumping a HTML error page at them instead of the JSON they were expecting would be silly and wrong - returning JSON describing the error seems much more sane.
So, I wouldn't say it breaks the error page, I'd say it's logical behaviour.
If you don't want it, though, you could probably get round it with Yanick's suggestion of using before_serializer.
-- David Precious ("bigpresh") <davidp@preshweb.co.uk> http://www.preshweb.co.uk/ www.preshweb.co.uk/twitter www.preshweb.co.uk/linkedin www.preshweb.co.uk/facebook www.preshweb.co.uk/cpan www.preshweb.co.uk/github
_______________________________________________ dancer-users mailing list dancer-users@dancer.pm http://lists.preshweb.co.uk/mailman/listinfo/dancer-users
On 3/14/2014 07:46, Lee Carmichael wrote:
hook before_error_init => sub {
This is a beautiful solution to the problem. Thank you! We didn't have a formal API before, but fixing this problem gave me sufficient reason to refactor the route handlers so that we do. David makes a good point: route handlers that return JSON should be distinguishable from those that return HTML. Putting them all under /api/* accomplishes that. Thank you both.
On 3/14/2014 07:46, Lee Carmichael wrote:
We do this:
hook before_error_init => sub { my $err_obj = shift;
if ( request->path !~ m{^/api/} && ( my $ser = setting('serializer') ) ) { set 'serializer', undef; $err_obj->{_save_serializer} = $ser; } };
And then restore it:
hook after_error_render => sub { my $response = shift; my $err_obj = vars->{_save_err_obj};
if ( my $ser = delete $err_obj->{_save_serializer} ) { set 'serializer', $ser; } };
After using this for a while, I noticed that after an error happens, the serializer setting isn't getting restored. This simpler rewrite appears to have the same effect, without the problem: hook before_error_init => sub { set('serializer', undef) if request->path !~ m{^/api/}; }; hook after_error_render => sub { set('serializer', 'JSON') unless defined setting('serializer'); }; The restoration code is heavy-handed and violates the DRY principle, but I think it will work for our purposes.
participants (4)
-
David Precious -
Lee Carmichael -
Warren Young -
Yanick Champoux