GithubHelp home page GithubHelp logo

catalyst-actionrole-matchrequestaccepts's Introduction

NAME

Catalyst::ActionRole::MatchRequestAccepts - Dispatch actions based on HTTP Accept Header

SYNOPSIS

package MyApp::Controller::Foo;

use Moose;
use namespace::autoclean;

BEGIN {
  extends 'Catalyst::Controller::ActionRole';
}

## Add the ActionRole to all the Controller's actions.  You can also 
## selectively add the ActionRole with the :Does action attribute or in
## controller configuration.  See Catalyst::Controller::ActionRole for
## more information.

__PACKAGE__->config(
  action_roles => ['MatchRequestAccepts'],
);

## Match for incoming requests with HTTP Accepts: plain/html
sub for_html : Path('foo') Accept('plain/html') { ... }

## Match for incoming requests with HTTP Accepts: application/json
sub for_json : Path('foo') Accept('application/json') { ... }

DESCRIPTION

Lets you specify a match for the HTTP Accept Header, which is provided by the Catalyst $ctx->request->headers object. You might wish to instead look at Catalyst::Action::REST if you are doing complex applications that match different incoming request types, but if you are very fussy about how your actions match, or if you are doing some simple ajaxy bits you might like to use this instead of a full on package (like Catalyst::Action::REST is.)

Currently the match performed is a pure equalty, no attempt to guess or infer matches based on similarity are done. If you need to match several variations you can specify all the variations with multiple attribute declarations. Right now we don't support expression based matching, such as text/*, although adding such would probably not be very hard (although I don't want to make the logic here slow down our dispatch matching too much).

Please note that if you specify multiple Accept attributes on a single action, those will be matched via an OR condition and not an AND condition. In other words we short circuit match the first action with at least one of the Accept values appearing in the requested HTTP headers. I think this is correct since I imagine the purpose of multiple Accept attributes would be to match several acceptable variations of a given type, not to match any of several unrelated types. However if you have a use case for this please let me know.

If an action consumes this role, but no Accept attributes are found, the action will simple accept all types.

For debugging purposes, if the Catalyst debug flag is enabled, you can override the HTTP Accept header with the http-accept query parameter. This makes it easy to force detect in testing or in your browser. This feature is NOT available when the debug flag is off.

Also, as usual you can specify attributes and information in th configuration of your Catalyst::Controller subclass:

## Set the 'our_action_json' action to consume this ActionRole.  In this
## example GET '/json' would only match if the client request HTTP included
## an Accept: application/json.

__PACKAGE__->config(
  action_roles => ['MatchRequestAccepts'],
  action => {
    our_action_json => { Path => 'json', Accept => 'application/json' },
  });

## GET '/foo' will dispatch to either action 'our_action_json' or action
## 'our_action_html' depending on the incoming HTTP Accept.

__PACKAGE__->config(
  action => {
    our_action_json => {
      Does => 'MatchRequestAccepts',
      Path => 'foo',
      Accept => 'application/json',
    },
    our_action_html => {
      Does => 'MatchRequestAccepts',
      Path => 'foo',
      Accept => 'text/html',
    },
  });

There's a functioning Catalyst example application in the test directory for your review as well.

EXAMPLE WITH CHAINED ACTIONS

The following example uses Catalyst chaining to match one of two different types of Accept headers, and to return the correct HTTP error message if nothing is matched. This is probably my most common use pattern.

package MyApp::Web::Controller::Chained;

use Moose;
use namespace::autoclean;

BEGIN {
  extends 'Catalyst::Controller::ActionRole';
}

__PACKAGE__->config(
  action_roles => ['MatchRequestAccepts'],
);

sub root : Chained('/') PathPrefix CaptureArgs(0) {}

  sub text_html
    : Chained('root') PathPart('') Accept('text/html') Args(0)
  {
    my ($self, $ctx) = @_;
    $ctx->response->body('text_html');
  }

  sub json
    : Chained('root') PathPart('') Accept('application/json') Args(0)
  {
    my ($self, $ctx) = @_;
    $ctx->response->body('json');
  }

  sub not_accepted
    : Chained('root') PathPart('') Args
  {
    my ($self, $ctx) = @_;
    $ctx->response->status(406);
    $ctx->response->body('error_not_accepted');
  }

__PACKAGE__->meta->make_immutable;

In the given example, a GET request to http://www.myapp.com/chained will match for Accept values of HTML and JSON, and will return a status 406 error to all other requests.

AUTHOR

John Napiorkowski email:[email protected]

THANKS

Shout out to Florian Ragwitz [email protected] for providing such a great example in Catalyst::ActionRole::MatchRequestMethod. Source code and tests are pretty much copied from his stuff.

I also cargo culted a chuck of code from Catalyst::TraitFor::Request::REST which let me parse HTTP Accept lines.

SEE ALSO

Catalyst::ActionRole::MatchRequestMethod, Catalyst::Action::REST, Catalyst, Catalyst::Controller::ActionRole, Moose.

COPYRIGHT & LICENSE

Copyright 2011, John Napiorkowski email:[email protected]

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

catalyst-actionrole-matchrequestaccepts's People

Contributors

jjn1056 avatar tsibley avatar

Stargazers

 avatar

Watchers

 avatar  avatar

Forkers

tsibley moltar

catalyst-actionrole-matchrequestaccepts's Issues

Problem accepting multiple Accept attributes

Hi,

First, thanks for the module, it really made working with conneg quite easy. I have one possible issue:

My understanding of the docs was that a Catalyst action should be able to accept multiple Accept attributes ("Please note that if you specify multiple Accept attributes on a single action, those will be matched via an OR condition and not an AND condition"), e.g.:

sub for_html : Path('/art') Accept('plain/html') Accept('text/html') Args(1) {
#...

This didn't seem to work; instead I had to forward to another:

sub for_text_html : Path('/art') Accept('text/html') Args(1) {
    my ( $self, $c, $id_in ) = @_;
    $c->forward('for_plain_html');
}

sub for_plain_html : Path('/art') Accept('plain/html') Args(1) {
#...

Seems to break Method action attribute

sub foo : Chained('/') PathPart('foo') Accept('application/json') Args(0) GET {
    my ( $self, $c ) = @_;

    $c->view( 'JSON' )->ok( { ok => 1 } );
}

Matches on POST request:

❯ curl -v -H "Accept: application/json" -X POST http://0.0.0.0:3000/foo

*   Trying 0.0.0.0...
* TCP_NODELAY set
* Connected to 0.0.0.0 (127.0.0.1) port 3000 (#0)
> POST /foo HTTP/1.1
> Host: 0.0.0.0:3000
> User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:31.0) Gecko/20100101 Firefox/31.0
> Referer:
> Accept: application/json
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Sun, 07 Apr 2019 01:59:29 GMT
< Server: HTTP::Server::PSGI
< Content-Type: application/json
< X-Catalyst: 5.90124
< Content-Length: 8
<
* Closing connection 0
{"ok":1}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.