File Coverage

blib/lib/HTTP/Throwable.pm
Criterion Covered Total %
statement 40 40 100.0
branch 5 6 83.3
condition 7 9 77.7
subroutine 13 13 100.0
pod 3 7 42.8
total 68 75 90.6


line stmt bran cond sub pod time code
1             package HTTP::Throwable;
2             our $AUTHORITY = 'cpan:STEVAN';
3             $HTTP::Throwable::VERSION = '0.027';
4 6     6   71715 use Types::Standard qw(Int Str ArrayRef);
  6         294814  
  6         65  
5              
6 6     6   6414 use Moo::Role;
  6         16136  
  6         44  
7              
8             use overload
9 6         46 '&{}' => 'to_app',
10             '""' => 'as_string',
11 6     6   2383 fallback => 1;
  6         15  
12              
13 6     6   2997 use Plack::Util ();
  6         51943  
  6         2261  
14              
15             with 'Throwable';
16              
17             has 'status_code' => (
18             is => 'ro',
19             isa => Int,
20             builder => 'default_status_code',
21             );
22              
23             has 'reason' => (
24             is => 'ro',
25             isa => Str,
26             required => 1,
27             builder => 'default_reason',
28             );
29              
30             has 'message' => (
31             is => 'ro',
32             isa => Str,
33             predicate => 'has_message',
34             );
35              
36             # TODO: type this attribute more strongly -- rjbs, 2011-02-21
37             has 'additional_headers' => ( is => 'ro', isa => ArrayRef );
38              
39             sub build_headers {
40 58     58 0 161 my ($self, $body) = @_;
41              
42 58         111 my @headers;
43              
44 58         106 @headers = @{ $self->body_headers($body) };
  58         213  
45              
46 58 100       307 if ( my $additional_headers = $self->additional_headers ) {
47 6         25 push @headers => @$additional_headers;
48             }
49              
50 58         179 return \@headers;
51             }
52              
53             sub status_line {
54 195     195 1 55575 my $self = shift;
55 195         1010 my $out = $self->status_code . " " . $self->reason;
56 195 50       662 $out .= " " . $self->message if $self->message;
57              
58 195         1062 return $out;
59             }
60              
61             requires 'body';
62             requires 'body_headers';
63             requires 'as_string';
64              
65             sub as_psgi {
66 58     58 1 138 my $self = shift;
67 58         223 my $body = $self->body;
68 58         915 my $headers = $self->build_headers( $body );
69 58 100       367 [ $self->status_code, $headers, [ defined $body ? $body : () ] ];
70             }
71              
72             sub to_app {
73 4     4 1 24839 my $self = shift;
74 4     4   9 sub { my $env; $self->as_psgi( $env ) }
  4         12  
75 4         20 }
76              
77             sub is_redirect {
78 54     54 0 109694 my $status = (shift)->status_code;
79 54   66     539 return $status >= 300 && $status < 400;
80             }
81              
82             sub is_client_error {
83 54     54 0 208 my $status = (shift)->status_code;
84 54   100     412 return $status >= 400 && $status < 500;
85             }
86              
87             sub is_server_error {
88 54     54 0 209 my $status = (shift)->status_code;
89 54   66     325 return $status >= 500 && $status < 600;
90             }
91              
92 6     6   56 no Moo::Role; 1;
  6         19  
  6         59  
93              
94             =pod
95              
96             =encoding UTF-8
97              
98             =head1 NAME
99              
100             HTTP::Throwable - a set of strongly-typed, PSGI-friendly HTTP 1.1 exception libraries
101              
102             =head1 VERSION
103              
104             version 0.027
105              
106             =head1 SYNOPSIS
107              
108             B: The interface for HTTP::Throwable has changed significantly
109             between 0.005 and 0.010. Further backward incompatibilities may appear in the
110             next few weeks, as the interface is refined. This notice will be removed when
111             it has stabilized.
112              
113             I, you probably want to use L, so here's a
114             sample of how that works:
115              
116             use HTTP::Throwable::Factory qw(http_throw http_exception);
117              
118             # you can just throw a generic exception...
119             HTTP::Throwable::Factory->throw({
120             status_code => 500,
121             reason => 'Internal Server Error',
122             message => 'Something has gone very wrong!'
123             });
124              
125             # or with a little sugar...
126             http_throw({
127             status_code => 500,
128             reason => 'Internal Server Error',
129             message => 'Something has gone very wrong!'
130             });
131              
132              
133             # ...but it's much more convenient to throw well-defined exceptions, like
134             # this:
135              
136             http_throw(InternalServerError => {
137             message => 'Something has gone very wrong!',
138             });
139              
140             # or you can use the exception objects as PSGI apps:
141             builder {
142             mount '/old' => http_exception(MovedPermanently => { location => '/new' }),
143             # ...
144             };
145              
146             =head1 DESCRIPTION
147              
148             HTTP-Throwable provides a set of strongly-typed, PSGI-friendly exception
149             implementations corresponding to the HTTP error status code (4xx-5xx) as well
150             as the redirection codes (3xx).
151              
152             This particular package (HTTP::Throwable) is the shared role for all the
153             exceptions involved. It's not intended that you use HTTP::Throwable
154             directly, although you can, and instructions for using it correctly are
155             given below. Instead, you probably want to use
156             L, which will assemble exception classes from
157             roles needed to build an exception for your use case.
158              
159             For example, you can throw a redirect:
160              
161             use HTTP::Throwable::Factory qw(http_throw);
162              
163             http_throw(MovedPermanently => { location => '/foo-bar' });
164              
165             ...or a generic fully user-specified exception...
166              
167             http_throw({
168             status_code => 512,
169             reason => 'Server on fire',
170             message => "Please try again after heavy rain",
171             });
172              
173             For a list of pre-defined, known errors, see L below.
174             These types will have the correct status code and reason, and will
175             understand extra status-related arguments like redirect location or authentication realms.
176              
177             For information on using HTTP::Throwable directly, see L
178             HTTP::THROWABLE>, below.
179              
180             =head2 HTTP::Exception
181              
182             This module is similar to HTTP::Exception with a few, well uhm,
183             exceptions. First, we are not implementing the 1xx and 2xx status
184             codes, it is this authors opinion that those not being errors or
185             an exception control flow (redirection) should not be handled with
186             exceptions. And secondly, this module is very PSGI friendly in that
187             it can turn your exception into a PSGI response with just a
188             method call.
189              
190             All that said HTTP::Exception is a wonderful module and if that
191             better suits your needs, then by all means, use it.
192              
193             =head2 Note about Stack Traces
194              
195             It should be noted that even though these are all exception objects,
196             only the 500 Internal Server Error error actually includes the stack
197             trace (albeit optionally). This is because more often then not you will
198             not actually care about the stack trace and therefore do not the extra
199             overhead. If you do find you want a stack trace though, it is as simple
200             as adding the L role to your exceptions.
201              
202             =head1 ATTRIBUTES
203              
204             =head2 status_code
205              
206             This is the status code integer as specified in the HTTP spec.
207              
208             =head2 reason
209              
210             This is the reason phrase as specified in the HTTP spec.
211              
212             =head2 message
213              
214             This is an additional message string that can be supplied, which I
215             be used when stringifying or building an HTTP response.
216              
217             =head2 additional_headers
218              
219             This is an arrayref of pairs that will be added to the headers of the
220             exception when converted to a HTTP message.
221              
222             =head1 METHODS
223              
224             =head2 status_line
225              
226             This returns a string that would be used as a status line in a response,
227             like C<404 Not Found>.
228              
229             =head2 as_string
230              
231             This returns a string representation of the exception. This method
232             B be implemented by any class consuming this role.
233              
234             =head2 as_psgi
235              
236             This returns a representation of the exception object as PSGI
237             response.
238              
239             In theory, it accepts a PSGI environment as its only argument, but
240             currently the environment is ignored.
241              
242             =head2 to_app
243              
244             This is the standard Plack convention for Ls.
245             It will return a CODE ref which expects the C<$env> parameter
246             and returns the results of C.
247              
248             =head2 &{}
249              
250             We overload C<&{}> to call C, again in keeping with the
251             L convention.
252              
253             =head1 WELL-KNOWN TYPES
254              
255             Below is a list of the well-known types recognized by the factory and
256             shipped with this distribution. The obvious 4xx and 5xx errors are
257             included but we also include the 3xx redirection status codes. This is
258             because, while not really an error, the 3xx status codes do represent an
259             exceptional control flow.
260              
261             The implementation for each of these is in a role with a name in the
262             form C. For example, "Gone"
263             is C. When throwing the exception
264             with the factory, just pass "Gone"
265              
266             =head2 Redirection 3xx
267              
268             This class of status code indicates that further action needs to
269             be taken by the user agent in order to fulfill the request. The
270             action required MAY be carried out by the user agent without
271             interaction with the user if and only if the method used in the
272             second request is GET or HEAD.
273              
274             =over 4
275              
276             =item 300 L
277              
278             =item 301 L
279              
280             =item 302 L
281              
282             =item 303 L
283              
284             =item 304 L
285              
286             =item 305 L
287              
288             =item 307 L
289              
290             =back
291              
292             =head2 Client Error 4xx
293              
294             The 4xx class of status code is intended for cases in which
295             the client seems to have erred. Except when responding to a
296             HEAD request, the server SHOULD include an entity containing an
297             explanation of the error situation, and whether it is a temporary
298             or permanent condition. These status codes are applicable to any
299             request method. User agents SHOULD display any included entity
300             to the user.
301              
302             =over 4
303              
304             =item 400 L
305              
306             =item 401 L
307              
308             =item 403 L
309              
310             =item 404 L
311              
312             =item 405 L
313              
314             =item 406 L
315              
316             =item 407 L
317              
318             =item 408 L
319              
320             =item 409 L
321              
322             =item 410 L
323              
324             =item 411 L
325              
326             =item 412 L
327              
328             =item 413 L
329              
330             =item 414 L
331              
332             =item 415 L
333              
334             =item 416 L
335              
336             =item 417 L
337              
338             =back
339              
340             =head2 Server Error 5xx
341              
342             Response status codes beginning with the digit "5" indicate
343             cases in which the server is aware that it has erred or is
344             incapable of performing the request. Except when responding to
345             a HEAD request, the server SHOULD include an entity containing
346             an explanation of the error situation, and whether it is a
347             temporary or permanent condition. User agents SHOULD display
348             any included entity to the user. These response codes are applicable
349             to any request method.
350              
351             =over 4
352              
353             =item 500 L
354              
355             =item 501 L
356              
357             =item 502 L
358              
359             =item 503 L
360              
361             =item 504 L
362              
363             =item 505 L
364              
365             =back
366              
367             =head1 COMPOSING WITH HTTP::THROWABLE
368              
369             In general, we expect that you'll use L or a
370             subclass to throw exceptions. You can still use HTTP::Throwable
371             directly, though, if you keep these things in mind:
372              
373             HTTP::Throwable is mostly concerned about providing basic headers and a
374             PSGI representation. It doesn't worry about the body or a
375             stringification. You B provide the methods C and
376             C and C.
377              
378             The C method returns the string (of octets) to be sent as the HTTP
379             entity. That body is passed to the C method, which must
380             return an arrayref of headers to add to the response. These will
381             generally include the Content-Type and Content-Length headers.
382              
383             The C method should return a printable string, even if the
384             body is going to be empty.
385              
386             For convenience, these three methods are implemented by the roles
387             L and L.
388              
389             =head1 SEE ALSO
390              
391             =over 4
392              
393             =item *
394              
395             L
396              
397             =item *
398              
399             L
400              
401             =back
402              
403             =head1 AUTHORS
404              
405             =over 4
406              
407             =item *
408              
409             Stevan Little
410              
411             =item *
412              
413             Ricardo Signes
414              
415             =back
416              
417             =head1 CONTRIBUTORS
418              
419             =for stopwords Brian Cassidy Chris Prather Edward Betts Fitz Elliott Karen Etheridge
420              
421             =over 4
422              
423             =item *
424              
425             Brian Cassidy
426              
427             =item *
428              
429             Chris Prather
430              
431             =item *
432              
433             Edward Betts
434              
435             =item *
436              
437             Fitz Elliott
438              
439             =item *
440              
441             Karen Etheridge
442              
443             =back
444              
445             =head1 COPYRIGHT AND LICENSE
446              
447             This software is copyright (c) 2011 by Infinity Interactive, Inc.
448              
449             This is free software; you can redistribute it and/or modify it under
450             the same terms as the Perl 5 programming language system itself.
451              
452             =cut
453              
454             __END__