Updating changelod, 0.60 release.
[catagits/Catalyst-Action-REST.git] / lib / Catalyst / Request / REST.pm
CommitLineData
256c894f 1#
2# REST.pm
be3c588a 3# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
256c894f 4# Created on: 10/13/2006 03:54:33 PM PDT
5#
6# $Id: $
7
8package Catalyst::Request::REST;
9
10use strict;
11use warnings;
12
13use base 'Catalyst::Request';
9a76221e 14use HTTP::Headers::Util qw(split_header_words);
256c894f 15
256c894f 16
9a76221e 17=head1 NAME
18
19Catalyst::Request::REST - A REST-y subclass of Catalyst::Request
20
21=head1 SYNOPSIS
22
23 if ( $c->request->accepts('text/x-json') ) {
24 ...
25 }
26
27 my $types = $c->request->accepted_content_types();
28
29=head1 DESCRIPTION
30
31This is a subclass of C<Catalyst::Request> that adds a few methods to
32the request object to faciliate writing REST-y code. Currently, these
33methods are all related to the content types accepted by the client.
34
35
36=head1 METHODS
37
38=over 4 data
39
40If the request went through the Deserializer action, this method will
41returned the deserialized data structure.
42
43=cut
44
45__PACKAGE__->mk_accessors(qw(data accept_only));
46
47=item accepted_content_types
48
49Returns an array reference of content types accepted by the
50client.
51
52The list of types is created by looking at the following sources:
53
54=over 8
55
56=item * Content-type header
57
58If this exists, this will always be the first type in the list.
59
60=item * content-type parameter
61
62If the request is a GET request and there is a "content-type"
63parameter in the query string, this will come before any types in the
64Accept header.
65
66=item * Accept header
67
68This will be parsed and the types found will be ordered by the
69relative quality specified for each type.
70
71=back
72
73If a type appears in more than one of these places, it is ordered based on
74where it is first found.
75
76=cut
77
78sub accepted_content_types {
79 my $self = shift;
80
81 return $self->{content_types} if $self->{content_types};
256c894f 82
9a76221e 83 my %types;
84
85 # First, we use the content type in the HTTP Request. It wins all.
86 $types{ $self->content_type } = 3
87 if $self->content_type;
88
89 if ($self->method eq "GET" && $self->param('content-type')) {
9a76221e 90 $types{ $self->param('content-type') } = 2;
91 }
92
93 # Third, we parse the Accept header, and see if the client
94 # takes a format we understand.
95 #
96 # This is taken from chansen's Apache2::UploadProgress.
97 if ( $self->header('Accept') ) {
98 $self->accept_only(1) unless keys %types;
99
100 my $accept_header = $self->header('Accept');
101 my $counter = 0;
102
103 foreach my $pair ( split_header_words($accept_header) ) {
104 my ( $type, $qvalue ) = @{$pair}[ 0, 3 ];
105 next if $types{$type};
106
107 unless ( defined $qvalue ) {
108 $qvalue = 1 - ( ++$counter / 1000 );
109 }
110
111 $types{$type} = sprintf( '%.3f', $qvalue );
112 }
113 }
114
115 return $self->{content_types} =
116 [ sort { $types{$b} <=> $types{$a} } keys %types ];
117}
118
119=item preferred_content_type
120
121This returns the first content type found. It is shorthand for:
122
123 $request->accepted_content_types->[0]
124
125=cut
126
127sub preferred_content_type { $_[0]->accepted_content_types->[0] }
128
129=item accepts($type)
130
131Given a content type, this returns true if the type is accepted.
132
133Note that this does not do any wildcard expansion of types.
134
135=cut
136
137sub accepts {
138 my $self = shift;
139 my $type = shift;
140
141 return grep { $_ eq $type } @{ $self->accepted_content_types };
142}
143
144=head1 AUTHOR
145
146Adam Jacob <adam@stalecoffee.org>, with lots of help from mst and jrockway
147
148=head1 LICENSE
149
150You may distribute this code under the same terms as Perl itself.
151
152=cut
153
1541;