File Coverage

blib/lib/Catalyst/View/Errors/JSON.pm
Criterion Covered Total %
statement 12 34 35.2
branch 0 6 0.0
condition 0 3 0.0
subroutine 4 10 40.0
pod 3 6 50.0
total 19 59 32.2


line stmt bran cond sub pod time code
1             package Catalyst::View::Errors::JSON;
2              
3 1     1   1972 use Moose;
  1         2  
  1         10  
4 1     1   7841 use JSON::MaybeXS;
  1         2  
  1         90  
5 1     1   7 use CatalystX::Utils::ContentNegotiation;
  1         3  
  1         23  
6 1     1   6 use CatalystX::Utils::ErrorMessages;
  1         2  
  1         757  
7              
8             extends 'Catalyst::View';
9              
10             has extra_encoder_args => (is=>'ro', required=>1, default => sub { +{} });
11              
12             has encoder => (
13             is => 'ro',
14             init_arg => undef,
15             required => 1,
16             lazy => 1,
17             default => sub { JSON::MaybeXS->new(utf8=>1, %{shift->extra_encoder_args}) },
18             );
19              
20             has cn => (
21             is => 'ro',
22             init_arg => undef,
23             required => 1,
24             default => sub { CatalystX::Utils::ContentNegotiation::content_negotiator },
25             );
26              
27             has default_language => (is=>'ro', required=>1, default=>'en_US');
28              
29             sub http_default {
30 0     0 0   my ($self, $c, $code, %args) = @_;
31 0           my $lang = $self->get_language($c);
32 0           my $message_info = $self->finalize_message_info($c, $code, $lang, %args);
33              
34 0           my $json = $self->render_json($c, $message_info);
35            
36 0           $c->response->body($json);
37 0           $c->response->content_type('application/json');
38 0           $c->response->status($code);
39             }
40              
41             sub get_language {
42 0     0 0   my ($self, $c) = @_;
43 0 0         if(my $lang = $c->request->header('Accept-Language')) {
44 0   0       return $self->cn->choose_language([$self->available_languages($c)], $lang) || $self->default_language;
45             }
46 0           return $self->default_language;
47             }
48              
49             sub available_languages {
50 0     0 1   my ($self, $c) = @_;
51 0           return my @lang_tags = CatalystX::Utils::ErrorMessages::available_languages;
52             }
53              
54             sub finalize_message_info {
55 0     0 1   my ($self, $c, $code, $lang, %args) = @_;
56 0           my $message_info = $self->get_message_info($c, $lang, $code);
57             return +{
58             info => {
59             lang => $lang,
60             uri => delete($args{uri}),
61 0 0         %{$args{info}||+{} },
62             },
63             errors => [
64             {
65             status => delete($args{code}),
66             title => $message_info->{title},
67             description => $message_info->{message},
68             },
69 0 0         @{$args{errors}||[] },
  0            
70             ],
71             };
72             }
73              
74             sub get_message_info {
75 0     0 1   my ($self, $c, $lang, $code) = @_;
76 0           return my $message_info_hash = CatalystX::Utils::ErrorMessages::get_message_info($lang, $code);
77             }
78              
79             sub render_json {
80 0     0 0   my ($self, $c, $message_info) = @_;
81 0           return $self->encoder->encode($message_info);
82             }
83              
84             __PACKAGE__->meta->make_immutable;
85              
86             =head1 NAME
87              
88             Catalyst::View::Errors::JSON - Standard HTTP Errors Responses in JSON
89              
90             =head1 SYNOPSIS
91              
92             package MyApp::View::JSON;
93              
94             use Moose;
95             extends 'Catalyst::View::Errors::JSON';
96              
97             __PACKAGE__->meta->make_immutable;
98              
99             =head1 DESCRIPTION
100              
101             Used to generate a JSON error response in standard way.
102              
103             =head1 METHODS
104              
105             This view exposes the follow methods for public use or for a programmer to override
106             to change function.
107              
108             =head2 available_languages
109              
110             An array of the languages available for serving error responses. By default we use
111             L<CatalystX::Utils::ErrorMessages> but if you have your own list of translations you can override
112             this.
113              
114             =head2 get_message_info
115              
116             Return error message info by code and language. By default we use
117             L<CatalystX::Utils::ErrorMessages> but if you have your own list of translations you can override
118             this.
119              
120             =head2 finalize_message_info
121              
122             Finalizes the hash of data that is sent to the template handler to make the body of the error
123             response. You can override if you want to change or add to this data.
124              
125             By default you get an error message that looks like this:
126              
127             {
128             "info" : {
129             "lang" : "en_US",
130             "uri" : "http://localhost:5000/"
131             },
132             "errors" : [
133             {
134             "title" : "Resource not found",
135             "description" : "The requested resource could not be found but may be available again in the future.",
136             "status" : 404
137             }
138             ]
139             }
140              
141             When dispatching an error you can add to the C<info> and C<errors> keys by passing information
142             via the arguments to C<$c->dispatch_error>. For example:
143              
144             $c->dispatch_error(400 =>
145             info => { error_count = 2 },
146             errors => [
147             {
148             field => 'name',
149             message => 'too short',
150             },
151             errors => [
152             {
153             field => 'age',
154             message => 'too young',
155             },
156             ],
157             );
158              
159             Will result in:
160              
161             {
162             "info" : {
163             "lang" : "en_US",
164             "uri" : "http://localhost:5000/"
165             },
166             "errors" : [
167             {
168             "title" : "Resource not found",
169             "description" : "The requested resource could not be found but may be available again in the future.",
170             "status" : 404
171             },
172             {
173             "field" : "name",
174             "message" : "too short",
175             },
176             {
177             "field" : "age",
178             "message" : "too old",
179             }
180             ]
181             }
182              
183             If you want a different error setup you'll need to override this method to do as you wish.
184              
185             =head1 CONFIGURATION
186              
187             This View exposes the following configuration options
188              
189             =head2 extra_encoder_args
190              
191             Extra args used to initialize the L<JSON::MaybeXS> object.
192              
193             =head2 default_language
194              
195             When doing content negotiation if there's no language preferred by the client
196             use this language. Default is C<en_US>.
197              
198             =head1 SEE ALSO
199            
200             L<CatalystX::Errors>.
201              
202             =head1 AUTHOR
203            
204             L<CatalystX::Errors>.
205            
206             =head1 COPYRIGHT & LICENSE
207            
208             L<CatalystX::Errors>.
209              
210             =cut