-#
-# Catalyst::Action::Deserialize::Data::Serializer.pm
-# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
-# Created on: 10/12/2006 03:00:32 PM PDT
-#
-# $Id$
-
package Catalyst::Action::Deserialize::Data::Serializer;
-
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
+use Moose;
+extends 'Catalyst::Action';
+with 'Catalyst::ActionRole::DeserializeFormat';
use Data::Serializer;
+use namespace::clean -except => 'meta';
-sub execute {
- my $self = shift;
- my ( $controller, $c, $serializer ) = @_;
-
- my $sp = $serializer;
- $sp =~ s/::/\//g;
- $sp .= ".pm";
- eval {
- require $sp
- };
- if ($@) {
- $c->log->debug("Could not load $serializer, refusing to serialize: $@")
- if $c->debug;
- return 0;
- }
- my $body = $c->request->body;
- if ($body) {
- my $rbody;
- if ( -f $c->request->body ) {
- open( BODY, "<", $c->request->body );
- while ( my $line = <BODY> ) {
- $rbody .= $line;
- }
- close(BODY);
- }
- my $dso = Data::Serializer->new( serializer => $serializer );
- my $rdata;
- eval {
- $rdata = $dso->raw_deserialize($rbody);
- };
- if ($@) {
- return $@;
- }
- $c->request->data($rdata);
- } else {
- $c->log->debug(
- 'I would have deserialized, but there was nothing in the body!')
- if $c->debug;
- }
- return 1;
+sub deserialize {
+ my ($self, $content, $c, $serializer) = @_;
+ unless (eval "use $serializer; 1") {
+ $c->log->debug("Could not load $serializer, refusing to serialize: $@")
+ if $c->debug;
+ return 0;
+ }
+ my $d = Data::Serializer->new(serializer => $serializer);
+ return $d->raw_deserialize($content);
}
1;
-#
-# Catlyst::Action::Deserialize::JSON.pm
-# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
-# Created on: 10/12/2006 03:00:32 PM PDT
-#
-# $Id$
-
package Catalyst::Action::Deserialize::JSON;
+use Moose;
+extends 'Catalyst::Action';
+with 'Catalyst::ActionRole::DeserializeFormat';
+use JSON qw(decode_json);
+use namespace::clean -except => 'meta';
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
-use JSON qw( decode_json );
-
-sub execute {
- my $self = shift;
- my ( $controller, $c, $test ) = @_;
-
- my $body = $c->request->body;
- my $rbody;
-
- if ($body) {
- while (my $line = <$body>) {
- $rbody .= $line;
- }
- }
-
- if ( $rbody ) {
- my $rdata = eval { decode_json( $rbody ) };
- if ($@) {
- return $@;
- }
- $c->request->data($rdata);
- } else {
- $c->log->debug(
- 'I would have deserialized, but there was nothing in the body!')
- if $c->debug;
- }
- return 1;
-}
+sub deserialize { decode_json $_[1] }
1;
package Catalyst::Action::Deserialize::View;
+use Moose;
+extends 'Catalyst::Action';
+with 'Catalyst::ActionRole::DeserializeFormat';
+use namespace::clean -except => 'meta';
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
-
-sub execute {
- return 1;
-}
+sub deserialize { undef };
1;
-#
-# Catlyst::Action::Deserialize::XML::Simple.pm
-# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
-# Created on: 10/12/2006 03:00:32 PM PDT
-#
-# $Id$
-
package Catalyst::Action::Deserialize::XML::Simple;
+use Moose;
+extends 'Catalyst::Action';
+with 'Catalyst::ActionRole::DeserializeFormat';
+use XML::Simple;
+use namespace::clean -except => 'meta';
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
-
-sub execute {
- my $self = shift;
- my ( $controller, $c, $test ) = @_;
-
- eval {
- require XML::Simple;
- };
- if ($@) {
- $c->log->debug("Could not load XML::Simple, refusing to deserialize: $@")
- if $c->debug;
- return 0;
- }
-
- my $body = $c->request->body;
- if ($body) {
- my $xs = XML::Simple->new('ForceArray' => 0,);
- my $rdata;
- eval {
- $rdata = $xs->XMLin( "$body" );
- };
- if ($@) {
- return $@;
- }
- if (exists($rdata->{'data'})) {
- $c->request->data($rdata->{'data'});
- } else {
- $c->request->data($rdata);
- }
- } else {
- $c->log->debug(
- 'I would have deserialized, but there was nothing in the body!')
- if $c->debug;
- }
- return 1;
+sub deserialize {
+ my ($self, $content) = @_;
+ my $x = XML::Simple->new(ForceArray => 0);
+ my $data = $x->XMLin($content);
+ $data = $data->{data} if exists $data->{data};
+ return $data;
}
1;
-#
-# Catlyst::Action::Deserialize::YAML.pm
-# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
-# Created on: 10/12/2006 03:00:32 PM PDT
-#
-# $Id$
-
package Catalyst::Action::Deserialize::YAML;
-
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
+use Moose;
+extends 'Catalyst::Action';
+with 'Catalyst::ActionRole::DeserializeFormat';
use YAML::Syck;
+use namespace::clean -except => 'meta';
-sub execute {
- my $self = shift;
- my ( $controller, $c, $test ) = @_;
-
- my $body = $c->request->body;
- if ($body) {
- my $rdata;
- eval {
- my $body = $c->request->body;
- $rdata = LoadFile( "$body" );
- };
- if ($@) {
- return $@;
- }
- $c->request->data($rdata);
- } else {
- $c->log->debug(
- 'I would have deserialized, but there was nothing in the body!')
- if $c->debug;
- }
- return 1;
-}
+sub deserialize { Load $_[1] }
1;
# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
# Created on: 10/12/2006 03:00:32 PM PDT
#
-# $Id$
package Catalyst::Action::REST;
-
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
+use Moose;
use Class::Inspector;
-use Catalyst::Request::REST;
+use Moose::Util qw(does_role);
+use Catalyst::RequestRole::REST;
use Catalyst::Controller::REST;
+use namespace::clean -except => 'meta';
+
+extends 'Catalyst::Action';
BEGIN { require 5.008001; }
our $VERSION = '0.76';
$VERSION = eval $VERSION;
-sub new {
- my $class = shift;
- my $config = shift;
- Catalyst::Request::REST->_insert_self_into( $config->{class} );
- return $class->next::method($config, @_);
-}
-
=head1 NAME
Catalyst::Action::REST - Automated REST Method Dispatching
my $self = shift;
my $c = shift;
+ Catalyst::RequestRole::REST->meta->apply($c->request)
+ unless does_role($c->request, 'Catalyst::RequestRole::REST');
+
my $controller = $c->component( $self->class );
my $rest_method = $self->name . "_" . uc( $c->request->method );
-#
-# Catalyst::Action::Serialize::Data::Serializer
-# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
-#
-# $Id$
-
package Catalyst::Action::Serialize::Data::Serializer;
-
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
+use Moose;
+extends 'Catalyst::Action';
+with 'Catalyst::ActionRole::SerializeFormat';
use Data::Serializer;
+use namespace::clean -except => 'meta';
-sub execute {
- my $self = shift;
- my ( $controller, $c, $serializer ) = @_;
-
- my $stash_key = (
- $controller->{'serialize'} ?
- $controller->{'serialize'}->{'stash_key'} :
- $controller->{'stash_key'}
- ) || 'rest';
- my $sp = $serializer;
- $sp =~ s/::/\//g;
- $sp .= ".pm";
- eval {
- require $sp
- };
- if ($@) {
- $c->log->info("Could not load $serializer, refusing to serialize: $@");
- return 0;
- }
- my $dso = Data::Serializer->new( serializer => $serializer );
- my $data;
- eval {
- $data = $dso->raw_serialize($c->stash->{$stash_key});
- };
- if ($@) {
- return $@;
- }
- $c->response->output( $data );
- return 1;
+sub serialize {
+ my ($self, $data, $c, $serializer) = @_;
+ unless (eval "use $serializer; 1") {
+ $c->log->info("Could not load $serializer, refusing to serialize: $@");
+ return 0;
+ }
+ my $d = Data::Serializer->new(serializer => $serializer);
+ return $d->raw_serialize($data);
}
1;
-#
-# Catlyst::Action::Serialize::JSON.pm
-# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
-# Created on: 10/12/2006 03:00:32 PM PDT
-#
-# $Id$
-
package Catalyst::Action::Serialize::JSON;
-
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
+use Moose;
+extends 'Catalyst::Action';
+with 'Catalyst::ActionRole::SerializeFormat';
use JSON qw(encode_json);
+use namespace::clean -except => 'meta';
-sub execute {
- my $self = shift;
- my ( $controller, $c ) = @_;
-
- my $stash_key = (
- $controller->{'serialize'} ?
- $controller->{'serialize'}->{'stash_key'} :
- $controller->{'stash_key'}
- ) || 'rest';
- my $output;
- eval {
- $output = $self->serialize( $c->stash->{$stash_key} );
- };
- if ($@) {
- return $@;
- }
- $c->response->output( $output );
- return 1;
-}
-
-sub serialize {
- my $self = shift;
- encode_json( shift );
-}
+sub serialize { encode_json $_[1] }
1;
package Catalyst::Action::Serialize::View;
-use strict;
-use warnings;
+use Moose;
+extends 'Catalyst::Action';
+with 'Catalyst::ActionRole::SerializeFormat';
+use namespace::clean -except => 'meta';
-use base 'Catalyst::Action';
+sub serialize {
+ my ($self, $data, $c, $view) = @_;
-sub execute {
- my $self = shift;
- my ( $controller, $c, $view ) = @_;
+ unless ($c->view($view)) {
+ $c->log->error("Could not load $view, refusing to serialize");
+ return 0;
+ }
- my $stash_key = (
- $controller->{'serialize'} ?
- $controller->{'serialize'}->{'stash_key'} :
- $controller->{'stash_key'}
- ) || 'rest';
-
- if ( !$c->view($view) ) {
- $c->log->error("Could not load $view, refusing to serialize");
- return 0;
- }
-
- return $c->view($view)->process($c);
+ return $c->view($view)->process($c);
}
1;
-#
-# Catlyst::Action::Serialize::XML::Simple.pm
-# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
-# Created on: 10/12/2006 03:00:32 PM PDT
-#
-# $Id$
-
package Catalyst::Action::Serialize::XML::Simple;
-
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
-
-sub execute {
- my $self = shift;
- my ( $controller, $c ) = @_;
-
- eval {
- require XML::Simple
- };
- if ($@) {
- $c->log->debug("Could not load XML::Serializer, refusing to serialize: $@")
- if $c->debug;
- return 0;
- }
- my $xs = XML::Simple->new(ForceArray => 0,);
-
- my $stash_key = (
- $controller->{'serialize'} ?
- $controller->{'serialize'}->{'stash_key'} :
- $controller->{'stash_key'}
- ) || 'rest';
- my $output;
- eval {
- $output = $xs->XMLout({ data => $c->stash->{$stash_key} });
- };
- if ($@) {
- return $@;
- }
- $c->response->output( $output );
- return 1;
+use Moose;
+extends 'Catalyst::Action';
+with 'Catalyst::ActionRole::SerializeFormat';
+use XML::Simple;
+use namespace::clean -except => 'meta';
+
+sub serialize {
+ my ($self, $data, $c) = @_;
+ my $x = XML::Simple->new(ForceArray => 0);
+ return $x->XMLout({ data => $data });
}
1;
-#
-# Catalyst::Action::Serialize::YAML.pm
-# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
-# Created on: 10/12/2006 03:00:32 PM PDT
-#
-# $Id$
-
package Catalyst::Action::Serialize::YAML;
-
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
+use Moose;
+extends 'Catalyst::Action';
+with 'Catalyst::ActionRole::SerializeFormat';
use YAML::Syck;
+use namespace::clean -except => 'meta';
-sub execute {
- my $self = shift;
- my ( $controller, $c ) = @_;
-
- my $stash_key = (
- $controller->{'serialize'} ?
- $controller->{'serialize'}->{'stash_key'} :
- $controller->{'stash_key'}
- ) || 'rest';
- my $output;
- eval {
- $output = $self->serialize($c->stash->{$stash_key});
- };
- if ($@) {
- return $@;
- }
- $c->response->output( $output );
- return 1;
-}
-
-sub serialize {
- my $self = shift;
- my $data = shift;
- Dump($data);
-}
+sub serialize { Dump $_[1] }
1;
-#
-# Catlyst::Action::Serialize::YAML::HTML.pm
-# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
-# Created on: 10/12/2006 03:00:32 PM PDT
-#
-# $Id$
-
package Catalyst::Action::Serialize::YAML::HTML;
-
-use strict;
-use warnings;
-
-use base 'Catalyst::Action';
-use YAML::Syck;
+use Moose;
+extends 'Catalyst::Action::Serialize::YAML';
use URI::Find;
+use namespace::clean -except => 'meta';
-sub execute {
- my $self = shift;
- my ( $controller, $c ) = @_;
-
- my $stash_key = (
- $controller->{'serialize'} ?
- $controller->{'serialize'}->{'stash_key'} :
- $controller->{'stash_key'}
- ) || 'rest';
- my $app = $c->config->{'name'} || '';
- my $output = "<html>";
- $output .= "<title>" . $app . "</title>";
- $output .= "<body><pre>";
- my $text = Dump($c->stash->{$stash_key});
- # Straight from URI::Find
- my $finder = URI::Find->new(
- sub {
- my($uri, $orig_uri) = @_;
- my $newuri;
- if ($uri =~ /\?/) {
- $newuri = $uri . "&content-type=text/html";
- } else {
- $newuri = $uri . "?content-type=text/html";
- }
- return qq|<a href="$newuri">$orig_uri</a>|;
- });
- $finder->find(\$text);
- $output .= $text;
- $output .= "</pre>";
- $output .= "</body>";
- $output .= "</html>";
- $c->response->output( $output );
- return 1;
-}
+around serialize => sub {
+ my $next = shift;
+ my ($self, $data, $c) = @_;
+ my $yaml = $self->$next($data, $c);
+ my $app = $c->config->{name} || '';
+ my $finder = URI::Find->new(sub {
+ my($uri, $orig_uri) = @_;
+ my $newuri;
+ if ($uri =~ /\?/) {
+ $newuri = $uri . "&content-type=text/html";
+ } else {
+ $newuri = $uri . "?content-type=text/html";
+ }
+ return qq|<a href="$newuri">$orig_uri</a>|;
+ });
+ my $output = "<html>";
+ $output .= "<title>" . $app . "</title>";
+ $output .= "<body><pre>";
+ $finder->find(\$yaml);
+ $output .= $yaml;
+ $output .= "</pre>";
+ $output .= "</body>";
+ $output .= "</html>";
+ return $output;
+};
1;
use warnings;
use base 'Catalyst::Action';
+use Moose::Util qw(does_role);
+use Catalyst::ControllerRole::SerializeConfig;
use Module::Pluggable::Object;
-use Catalyst::Request::REST;
+use Catalyst::RequestRole::REST;
+use Catalyst::ResponseRole::REST;
use Catalyst::Utils ();
-sub new {
- my $class = shift;
- my $config = shift;
- Catalyst::Request::REST->_insert_self_into( $config->{class} );
- return $class->SUPER::new($config, @_);
-}
-
__PACKAGE__->mk_accessors(qw(_serialize_plugins _loaded_plugins));
sub _load_content_plugins {
my $self = shift;
my ( $search_path, $controller, $c ) = @_;
+ Catalyst::RequestRole::REST->meta->apply($c->request)
+ unless does_role($c->request, 'Catalyst::RequestRole::REST');
+
+ Catalyst::ResponseRole::REST->meta->apply($c->response)
+ unless does_role($c->response, 'Catalyst::ResponseRole::REST');
+
unless ( defined( $self->_loaded_plugins ) ) {
$self->_loaded_plugins( {} );
}
my $sarg;
my $map;
- my $config;
+ Catalyst::ControllerRole::SerializeConfig->meta->apply($controller)
+ unless does_role($controller, 'Catalyst::ControllerRole::SerializeConfig');
+
+ my $config = $controller->serialize_config;
- if ( exists $controller->{'serialize'} ) {
- $c->log->info("Using deprecated configuration for Catalyst::Action::REST!");
- $c->log->info("Please see perldoc Catalyst::Action::REST for the update guide");
- $config = $controller->{'serialize'};
- # if they're using the deprecated config, they may be expecting a
- # default mapping too.
- $config->{map} ||= $controller->{map};
- } else {
- $config = $controller;
- }
- $map = $config->{'map'};
+ $map = $config->{map};
# pick preferred content type
my @accepted_types; # priority order, best first
# pick the best match that we have a serializer mapping for
my ($content_type) = grep { $map->{$_} } @accepted_types;
- return $self->_unsupported_media_type($c, $content_type)
- if not $content_type;
+ unless ($content_type) {
+ $c->response->unsupported_media_type;
+ return;
+ }
# carp about old text/x-json
if ($content_type eq 'text/x-json') {
$sclass .= $mc;
#}
if ( !grep( /^$sclass$/, @{ $self->_serialize_plugins } ) ) {
- return $self->_unsupported_media_type($c, $content_type);
+ $c->response->unsupported_media_type($content_type);
+ return;
}
} else {
- return $self->_unsupported_media_type($c, $content_type);
+ $c->response->unsupported_media_type($content_type);
+ return;
}
unless ( exists( $self->_loaded_plugins->{$sclass} ) ) {
my $load_class = $sclass;
if ($@) {
$c->log->error(
"Error loading $sclass for " . $content_type . ": $!" );
- return $self->_unsupported_media_type($c, $content_type);
+ $c->response->unsupported_media_type($content_type);
+ return;
} else {
$self->_loaded_plugins->{$sclass} = 1;
}
return $sclass, $sarg, $content_type;
}
-sub _unsupported_media_type {
- my ( $self, $c, $content_type ) = @_;
- $c->res->content_type('text/plain');
- $c->res->status(415);
- if (defined($content_type) && $content_type ne "") {
- $c->res->body(
- "Content-Type " . $content_type . " is not supported.\r\n" );
- } else {
- $c->res->body(
- "Cannot find a Content-Type supported by your client.\r\n" );
- }
- return undef;
-}
-
-sub _serialize_bad_request {
- my ( $self, $c, $content_type, $error ) = @_;
- $c->res->content_type('text/plain');
- $c->res->status(400);
- $c->res->body(
- "Content-Type " . $content_type . " had a problem with your request.\r\n***ERROR***\r\n$error" );
- return undef;
-}
-
1;
=head1 NAME
--- /dev/null
+package Catalyst::ActionRole::DeserializeFormat;
+use Moose::Role;
+use Moose::Util qw(does_role);
+use Catalyst::RequestRole::Deserialize;
+use namespace::clean -except => 'meta';
+
+requires 'deserialize';
+
+around execute => sub {
+ my $next = shift;
+ my ($self, $controller, $c, $arg) = @_;
+
+ Catalyst::RequestRole::Deserialize->meta->apply($c->request)
+ unless does_role($c->request, 'Catalyst::RequestRole::Deserialize');
+
+ my $content = "";
+ my $body = $c->request->body;
+ if ($body) {
+ local $_;
+ while (<$body>) { $content .= $_ }
+ }
+
+ if ($content) {
+ my $data = eval {
+ $self->deserialize(
+ $content,
+ $c,
+ $arg,
+ )
+ };
+ return $@ if $@;
+ $c->request->_set_data($data);
+ } else {
+ $c->debug && $c->log->debug(
+ 'I would have deserialized, but there was nothing in the body!'
+ );
+ }
+ return 1;
+};
+
+1;
--- /dev/null
+package Catalyst::ActionRole::SerializeFormat;
+use Moose::Role;
+use Catalyst::ControllerRole::SerializeConfig;
+use Moose::Util qw(does_role);
+use namespace::clean -except => 'meta';
+requires 'serialize';
+
+around execute => sub {
+ my $next = shift;
+ my ($self, $controller, $c, $arg) = @_;
+
+ # XXX is ignoring the return value here correct? the original serialize
+ # actions never even called their body.
+ $self->$next($controller, $c, $arg)
+ if blessed $self;
+
+ Catalyst::ControllerRole::SerializeConfig->meta->apply($controller)
+ unless does_role($controller, 'Catalyst::ControllerRole::SerializeConfig');
+
+ my $stash_key = $controller->serialize_config->{stash_key} || 'rest';
+
+ my $output;
+ eval {
+ $output = $self->serialize(
+ $c->stash->{$stash_key},
+ $c,
+ $arg,
+ );
+ };
+ return $@ if $@;
+ # horrible, but the best I can do given the existing magic return value
+ # conventions.
+ return $output if $output eq '0';
+ $c->response->body($output) unless $c->response->body;
+ return 1;
+};
+
+1;
--- /dev/null
+package Catalyst::ControllerRole::SerializeConfig;
+use Moose::Role;
+use namespace::clean -except => 'meta';
+
+my @KEYS = qw(map content_type_stash_key default);
+
+has serialize_config => (
+ is => 'ro',
+ isa => 'HashRef',
+ init_arg => undef,
+ lazy_build => 1,
+);
+
+sub _build_serialize_config {
+ my $self = shift;
+ my $c = $self->_application;
+ my $config;
+ if ( exists $self->{serialize} ) {
+ $c->log->info("Using deprecated configuration for Catalyst::Action::REST!");
+ $c->log->info("Please see perldoc Catalyst::Action::REST for the update guide");
+ $config = $self->{serialize};
+ # if they're using the deprecated config, they may be expecting a
+ # default mapping too.
+ $config->{map} ||= $self->{map};
+ } else {
+ # do not store a reference to itself in the controller
+ $config = {
+ map {; $_ => $self->{$_} } @KEYS
+ };
+ }
+ return $config;
+};
+
+1;
# Created by: Adam Jacob, Marchex, <adam@hjksolutions.com>
# Created on: 10/13/2006 03:54:33 PM PDT
#
-# $Id: $
package Catalyst::Request::REST;
-
-use strict;
-use warnings;
-use Scalar::Util qw/blessed/;
-
-use base qw/Catalyst::Request Class::Accessor::Fast/;
+use Moose;
+extends qw/Catalyst::Request/;
+with qw/Catalyst::RequestRole::REST Catalyst::RequestRole::Deserialize/;
use Catalyst::Utils;
-use HTTP::Headers::Util qw(split_header_words);
sub _insert_self_into {
my ($class, $app_class ) = @_;
--- /dev/null
+package Catalyst::RequestRole::Deserialize;
+use Moose::Role;
+use namespace::clean -except => 'meta';
+
+has data => (
+ is => 'ro',
+ writer => '_set_data',
+);
+
+1;
--- /dev/null
+package Catalyst::RequestRole::REST;
+# ABSTRACT: A REST-y role for Catalyst::Request
+use Moose::Role;
+
+use Catalyst::Utils;
+use HTTP::Headers::Util qw(split_header_words);
+use namespace::clean -except => 'meta';
+
+has accept_only => (
+ is => 'rw',
+ isa => 'Bool',
+# writer => '_set_accept_only', FIXME fails for me if I use this
+ default => 0,
+);
+
+has accepted_content_types => (
+ is => 'ro',
+ isa => 'ArrayRef',
+ init_arg => undef,
+ lazy_build => 1,
+);
+
+has _accepted_content_types_hash => (
+ is => 'ro',
+ isa => 'HashRef',
+ init_arg => undef,
+ lazy_build => 1,
+);
+
+sub _build_accepted_content_types {
+ my $self = shift;
+ 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" &&
+ (my $ct = $self->params->{'content-type'})) {
+ $types{ $ct } = 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; # FIXME fails if _set_accept_only
+
+ 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 [ sort { $types{$b} <=> $types{$a} } keys %types ];
+}
+
+sub preferred_content_type { $_[0]->accepted_content_types->[0] }
+
+sub _build__accepted_content_types_hash {
+ return { map {; $_ => 1 } @{ $_[0]->accepted_content_types } };
+}
+
+sub accepts { $_[0]->_accepted_content_types_hash->{$_[1]} }
+
+1;
+
+__END__
+
+=head1 SYNOPSIS
+
+ if ( $c->request->accepts('application/json') ) {
+ ...
+ }
+
+ my $types = $c->request->accepted_content_types();
+
+=head1 DESCRIPTION
+
+This is a subclass of C<Catalyst::Request> 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.
+
+Note that if you have a custom request class in your application, and it does
+not inherit from C<Catalyst::Request::REST>, your application will fail with an
+error indicating a conflict the first time it tries to use
+C<Catalyst::Request::REST>'s functionality. To fix this error, make sure your
+custom request class inherits from C<Catalyst::Request::REST>.
+
+=method 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 4
+
+=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.
+
+=method preferred_content_type
+
+This returns the first content type found. It is shorthand for:
+
+ $request->accepted_content_types->[0]
+
+=method accepts
+
+Given a content type, this returns true if the type is accepted.
+
+Note that this does not do any wildcard expansion of types.
+
+=cut
--- /dev/null
+package Catalyst::ResponseRole::REST;
+
+use Moose::Role;
+
+sub unsupported_media_type {
+ my ($self, $content_type) = @_;
+
+ $self->content_type('text/plain');
+ $self->status(415);
+
+ if (defined $content_type and length $content_type) {
+ $self->body("Content-Type $content_type is not supported.\r\n");
+ } else {
+ $self->body("Cannot find a Content-Type supported by your client.\r\n");
+ }
+}
+
+sub serialize_bad_request {
+ my ($self, $content_type, $error) = @_;
+ $self->content_type('text/plain');
+ $self->status(400);
+ $self->body(
+ "Content-Type $content_type had a problem with your request\r\n" .
+ "***ERROR***\r\n$error"
+ );
+ return undef;
+}
+
+1;
use strict;
use warnings;
-use Test::More tests => 28;
+use Test::More tests => 26;
use FindBin;
use lib ( "$FindBin::Bin/../lib", "$FindBin::Bin/../t/lib" );
$ENV{CATALYST_DEBUG} = 0;
my $test = 'Test::Catalyst::Action::REST';
use_ok $test;
- is($test->request_class, 'Catalyst::Request::REST',
- 'Request::REST took over for Request');
-
- $test->request_class('Some::Other::Class');
- eval { $test->setup_finished(0); $test->setup };
- like $@, qr/$test has a custom request class Some::Other::Class/;
-
- {
- package My::Request;
- use base 'Catalyst::Request::REST';
- }
- $test->request_class('My::Request');
- eval { $test->setup_finished(0); $test->setup };
- is $@, '', 'no error from Request::REST subclass';
+ is($test->request_class, 'Catalyst::Request',
+ 'Request::REST did not take over for Request');
}
package MockContext;