X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FRequest%2FREST.pm;h=447680e08592f85831b8b5f6bf0474e99a4dec0f;hb=fec6d454787f6a7c23d1b6a7151a009a3ba0907b;hp=9b81c622adaeea294ca976d7dfcb6943ef3a912e;hpb=256c894fcf95e1a0716676afb8f5732854734672;p=catagits%2FCatalyst-Action-REST.git diff --git a/lib/Catalyst/Request/REST.pm b/lib/Catalyst/Request/REST.pm index 9b81c62..447680e 100644 --- a/lib/Catalyst/Request/REST.pm +++ b/lib/Catalyst/Request/REST.pm @@ -1,6 +1,6 @@ # # REST.pm -# Created by: Adam Jacob, Marchex, +# Created by: Adam Jacob, Marchex, # Created on: 10/13/2006 03:54:33 PM PDT # # $Id: $ @@ -10,9 +10,151 @@ package Catalyst::Request::REST; use strict; use warnings; -use base 'Catalyst::Request'; +use base qw/Catalyst::Request Class::Accessor::Fast/; +use HTTP::Headers::Util qw(split_header_words); -__PACKAGE__->mk_accessors(qw(data)); -1; +=head1 NAME + +Catalyst::Request::REST - A REST-y subclass of Catalyst::Request + +=head1 SYNOPSIS + + if ( $c->request->accepts('application/json') ) { + ... + } + + my $types = $c->request->accepted_content_types(); + +=head1 DESCRIPTION + +This is a subclass of C that adds a few methods to +the request object to faciliate writing REST-y code. Currently, these +methods are all related to the content types accepted by the client. + + +=head1 METHODS + +If the request went through the Deserializer action, this method will +returned the deserialized data structure. + +=cut + +__PACKAGE__->mk_accessors(qw(data accept_only)); + +=over 4 + +=item accepted_content_types + +Returns an array reference of content types accepted by the +client. + +The list of types is created by looking at the following sources: + +=over 8 + +=item * Content-type header + +If this exists, this will always be the first type in the list. + +=item * content-type parameter + +If the request is a GET request and there is a "content-type" +parameter in the query string, this will come before any types in the +Accept header. + +=item * Accept header + +This will be parsed and the types found will be ordered by the +relative quality specified for each type. + +=back + +If a type appears in more than one of these places, it is ordered based on +where it is first found. + +=cut + +sub accepted_content_types { + my $self = shift; + + return $self->{content_types} if $self->{content_types}; + + my %types; + # First, we use the content type in the HTTP Request. It wins all. + $types{ $self->content_type } = 3 + if $self->content_type; + + if ($self->method eq "GET" && $self->param('content-type')) { + $types{ $self->param('content-type') } = 2; + } + + # Third, we parse the Accept header, and see if the client + # takes a format we understand. + # + # This is taken from chansen's Apache2::UploadProgress. + if ( $self->header('Accept') ) { + $self->accept_only(1) unless keys %types; + + my $accept_header = $self->header('Accept'); + my $counter = 0; + + foreach my $pair ( split_header_words($accept_header) ) { + my ( $type, $qvalue ) = @{$pair}[ 0, 3 ]; + next if $types{$type}; + + unless ( defined $qvalue ) { + $qvalue = 1 - ( ++$counter / 1000 ); + } + + $types{$type} = sprintf( '%.3f', $qvalue ); + } + } + + return $self->{content_types} = + [ sort { $types{$b} <=> $types{$a} } keys %types ]; +} + +=item preferred_content_type + +This returns the first content type found. It is shorthand for: + + $request->accepted_content_types->[0] + +=cut + +sub preferred_content_type { $_[0]->accepted_content_types->[0] } + +=item accepts($type) + +Given a content type, this returns true if the type is accepted. + +Note that this does not do any wildcard expansion of types. + +=cut + +sub accepts { + my $self = shift; + my $type = shift; + + return grep { $_ eq $type } @{ $self->accepted_content_types }; +} + +=back + +=head1 AUTHOR + +Adam Jacob , with lots of help from mst and jrockway + +=head1 MAINTAINER + +J. Shirley + +=head1 LICENSE + +You may distribute this code under the same terms as Perl itself. + +=cut + +1;