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 0.028;
2             our $AUTHORITY = 'cpan:STEVAN';
3              
4 6     6   74797 use Types::Standard qw(Int Str ArrayRef);
  6         318819  
  6         56  
5              
6 6     6   6601 use Moo::Role;
  6         17783  
  6         73  
7              
8             use overload
9 6         39 '&{}' => 'to_app',
10             '""' => 'as_string',
11 6     6   2508 fallback => 1;
  6         18  
12              
13 6     6   3196 use Plack::Util ();
  6         55089  
  6         2571  
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 138 my ($self, $body) = @_;
41              
42 58         114 my @headers;
43              
44 58         86 @headers = @{ $self->body_headers($body) };
  58         205  
45              
46 58 100       267 if ( my $additional_headers = $self->additional_headers ) {
47 6         19 push @headers => @$additional_headers;
48             }
49              
50 58         152 return \@headers;
51             }
52              
53             sub status_line {
54 195     195 1 57673 my $self = shift;
55 195         804 my $out = $self->status_code . " " . $self->reason;
56 195 50       650 $out .= " " . $self->message if $self->message;
57              
58 195         923 return $out;
59             }
60              
61             requires 'body';
62             requires 'body_headers';
63             requires 'as_string';
64              
65             sub as_psgi {
66 58     58 1 124 my $self = shift;
67 58         215 my $body = $self->body;
68 58         895 my $headers = $self->build_headers( $body );
69 58 100       331 [ $self->status_code, $headers, [ defined $body ? $body : () ] ];
70             }
71              
72             sub to_app {
73 4     4 1 27826 my $self = shift;
74 4     4   9 sub { my $env; $self->as_psgi( $env ) }
  4         16  
75 4         26 }
76              
77             sub is_redirect {
78 54     54 0 108537 my $status = (shift)->status_code;
79 54   66     427 return $status >= 300 && $status < 400;
80             }
81              
82             sub is_client_error {
83 54     54 0 181 my $status = (shift)->status_code;
84 54   100     358 return $status >= 400 && $status < 500;
85             }
86              
87             sub is_server_error {
88 54     54 0 184 my $status = (shift)->status_code;
89 54   66     297 return $status >= 500 && $status < 600;
90             }
91              
92 6     6   56 no Moo::Role; 1;
  6         30  
  6         55  
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.028
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 PERL VERSION
203              
204             This library should run on perls released even a long time ago. It should work
205             on any version of perl released in the last five years.
206              
207             Although it may work on older versions of perl, no guarantee is made that the
208             minimum required version will not be increased. The version may be increased
209             for any reason, and there is no promise that patches will be accepted to lower
210             the minimum required perl.
211              
212             =head1 ATTRIBUTES
213              
214             =head2 status_code
215              
216             This is the status code integer as specified in the HTTP spec.
217              
218             =head2 reason
219              
220             This is the reason phrase as specified in the HTTP spec.
221              
222             =head2 message
223              
224             This is an additional message string that can be supplied, which I
225             be used when stringifying or building an HTTP response.
226              
227             =head2 additional_headers
228              
229             This is an arrayref of pairs that will be added to the headers of the
230             exception when converted to a HTTP message.
231              
232             =head1 METHODS
233              
234             =head2 status_line
235              
236             This returns a string that would be used as a status line in a response,
237             like C<404 Not Found>.
238              
239             =head2 as_string
240              
241             This returns a string representation of the exception. This method
242             B be implemented by any class consuming this role.
243              
244             =head2 as_psgi
245              
246             This returns a representation of the exception object as PSGI
247             response.
248              
249             In theory, it accepts a PSGI environment as its only argument, but
250             currently the environment is ignored.
251              
252             =head2 to_app
253              
254             This is the standard Plack convention for Ls.
255             It will return a CODE ref which expects the C<$env> parameter
256             and returns the results of C.
257              
258             =head2 &{}
259              
260             We overload C<&{}> to call C, again in keeping with the
261             L convention.
262              
263             =head1 WELL-KNOWN TYPES
264              
265             Below is a list of the well-known types recognized by the factory and
266             shipped with this distribution. The obvious 4xx and 5xx errors are
267             included but we also include the 3xx redirection status codes. This is
268             because, while not really an error, the 3xx status codes do represent an
269             exceptional control flow.
270              
271             The implementation for each of these is in a role with a name in the
272             form C. For example, "Gone"
273             is C. When throwing the exception
274             with the factory, just pass "Gone"
275              
276             =head2 Redirection 3xx
277              
278             This class of status code indicates that further action needs to
279             be taken by the user agent in order to fulfill the request. The
280             action required MAY be carried out by the user agent without
281             interaction with the user if and only if the method used in the
282             second request is GET or HEAD.
283              
284             =over 4
285              
286             =item 300 L
287              
288             =item 301 L
289              
290             =item 302 L
291              
292             =item 303 L
293              
294             =item 304 L
295              
296             =item 305 L
297              
298             =item 307 L
299              
300             =back
301              
302             =head2 Client Error 4xx
303              
304             The 4xx class of status code is intended for cases in which
305             the client seems to have erred. Except when responding to a
306             HEAD request, the server SHOULD include an entity containing an
307             explanation of the error situation, and whether it is a temporary
308             or permanent condition. These status codes are applicable to any
309             request method. User agents SHOULD display any included entity
310             to the user.
311              
312             =over 4
313              
314             =item 400 L
315              
316             =item 401 L
317              
318             =item 403 L
319              
320             =item 404 L
321              
322             =item 405 L
323              
324             =item 406 L
325              
326             =item 407 L
327              
328             =item 408 L
329              
330             =item 409 L
331              
332             =item 410 L
333              
334             =item 411 L
335              
336             =item 412 L
337              
338             =item 413 L
339              
340             =item 414 L
341              
342             =item 415 L
343              
344             =item 416 L
345              
346             =item 417 L
347              
348             =back
349              
350             =head2 Server Error 5xx
351              
352             Response status codes beginning with the digit "5" indicate
353             cases in which the server is aware that it has erred or is
354             incapable of performing the request. Except when responding to
355             a HEAD request, the server SHOULD include an entity containing
356             an explanation of the error situation, and whether it is a
357             temporary or permanent condition. User agents SHOULD display
358             any included entity to the user. These response codes are applicable
359             to any request method.
360              
361             =over 4
362              
363             =item 500 L
364              
365             =item 501 L
366              
367             =item 502 L
368              
369             =item 503 L
370              
371             =item 504 L
372              
373             =item 505 L
374              
375             =back
376              
377             =head1 COMPOSING WITH HTTP::THROWABLE
378              
379             In general, we expect that you'll use L or a
380             subclass to throw exceptions. You can still use HTTP::Throwable
381             directly, though, if you keep these things in mind:
382              
383             HTTP::Throwable is mostly concerned about providing basic headers and a
384             PSGI representation. It doesn't worry about the body or a
385             stringification. You B provide the methods C and
386             C and C.
387              
388             The C method returns the string (of octets) to be sent as the HTTP
389             entity. That body is passed to the C method, which must
390             return an arrayref of headers to add to the response. These will
391             generally include the Content-Type and Content-Length headers.
392              
393             The C method should return a printable string, even if the
394             body is going to be empty.
395              
396             For convenience, these three methods are implemented by the roles
397             L and L.
398              
399             =head1 SEE ALSO
400              
401             =over 4
402              
403             =item *
404              
405             L
406              
407             =item *
408              
409             L
410              
411             =back
412              
413             =head1 AUTHORS
414              
415             =over 4
416              
417             =item *
418              
419             Stevan Little
420              
421             =item *
422              
423             Ricardo Signes
424              
425             =back
426              
427             =head1 CONTRIBUTORS
428              
429             =for stopwords Andrew Fresh Brian Cassidy Chris Prather Edward Betts Fitz Elliott Karen Etheridge Ricardo Signes
430              
431             =over 4
432              
433             =item *
434              
435             Andrew Fresh
436              
437             =item *
438              
439             Brian Cassidy
440              
441             =item *
442              
443             Chris Prather
444              
445             =item *
446              
447             Edward Betts
448              
449             =item *
450              
451             Fitz Elliott
452              
453             =item *
454              
455             Karen Etheridge
456              
457             =item *
458              
459             Ricardo Signes
460              
461             =back
462              
463             =head1 COPYRIGHT AND LICENSE
464              
465             This software is copyright (c) 2011 by Infinity Interactive, Inc.
466              
467             This is free software; you can redistribute it and/or modify it under
468             the same terms as the Perl 5 programming language system itself.
469              
470             =cut
471              
472             __END__