Dave Cross: Still Munging Data With Perl: Online event - Mar 17 Learn more

requires 'match', 'match_captures', 'list_extra_info';
has allowed_content_types => (
is=>'ro',
required=>1,
lazy=>1,
isa=>'ArrayRef',
builder=>'_build_allowed_content_types');
has normalized => (
is=>'ro',
required=>1,
lazy=>1,
isa=>'HashRef',
builder=>'_build_normalized');
sub _build_normalized {
return +{
JSON => 'application/json',
JS => 'application/javascript',
PERL => 'application/perl',
HTML => 'text/html',
XML => 'text/XML',
Plain => 'text/plain',
UrlEncoded => 'application/x-www-form-urlencoded',
Multipart => 'multipart/form-data',
HTMLForm => ['application/x-www-form-urlencoded','multipart/form-data'],
};
}
sub _build_allowed_content_types {
my $self = shift;
my @proto = map {split ',', $_ } @{$self->attributes->{Consumes}};
my @converted = map {
if(my $normalized = $self->normalized->{$_}) {
ref $normalized ? @$normalized : ($normalized);
} else {
$_;
}
} @proto;
return \@converted;
}
around ['match','match_captures'] => sub {
my ($orig, $self, $ctx, @args) = @_;
if(my $content_type = $ctx->req->content_type) {
return 0 unless $self->can_consume($content_type);
}
return $self->$orig($ctx, @args);
};
sub can_consume {
my ($self, $request_content_type) = @_;
my @matches = grep { lc($_) eq lc($request_content_type) }
@{$self->allowed_content_types};
return @matches ? 1:0;
}
around 'list_extra_info' => sub {
my ($orig, $self, @args) = @_;
return {
%{ $self->$orig(@args) },
CONSUMES => $self->allowed_content_types,
};
};
1;
=head1 NAME
Catalyst::ActionRole::ConsumesContent - Match on HTTP Request Content-Type
=head1 SYNOPSIS
package MyApp::Web::Controller::MyController;
use base 'Catalyst::Controller';
sub start : POST Chained('/') CaptureArg(0) { ... }
sub is_json : Chained('start') Consumes('application/json') { ... }
sub is_urlencoded : Chained('start') Consumes('application/x-www-form-urlencoded') { ... }
sub is_multipart : Chained('start') Consumes('multipart/form-data') { ... }
## Alternatively, for common types...
sub is_json : Chained('start') Consume(JSON) { ... }
sub is_urlencoded : Chained('start') Consumes(UrlEncoded) { ... }
sub is_multipart : Chained('start') Consumes(Multipart) { ... }
## Or allow more than one type
sub is_more_than_one
: Chained('start')
: Consumes('application/x-www-form-urlencoded')
: Consumes('multipart/form-data')
{
## ...
}
1;
=head1 DESCRIPTION
This is an action role that lets your L<Catalyst::Action> match on the content
type of the incoming request.
Generally when there's a PUT or POST request, there's a request content body
with a matching MIME content type. Commonly this will be one of the types
used with classic HTML forms ('application/x-www-form-urlencoded' for example)
but there's nothing stopping you specifying any valid content type.
For matching purposes, we match strings but the casing is insensitive.
=head1 REQUIRES
This role requires the following methods in the consuming class.
=head2 match
=head2 match_captures
Returns 1 if the action matches the existing request and zero if not.
=head1 METHODS
This role defines the following methods
=head2 match
=head2 match_captures
Around method modifier that return 1 if the request content type matches one of the
allowed content types (see L</http_methods>) and zero otherwise.
=head2 allowed_content_types
An array of strings that are the allowed content types for matching this action.
=head2 can_consume
Boolean. Does the current request match content type with what this actionrole
can consume?
=head2 list_extra_info
Add the accepted content type to the debug screen.
=head1 AUTHORS
Catalyst Contributors, see Catalyst.pm
=head1 COPYRIGHT
This library is free software. You can redistribute it and/or modify it under
the same terms as Perl itself.
=cut