CatalystX-RequestModel

 view release on metacpan or  search on metacpan

lib/Catalyst/ActionRole/RequestModel.pm  view on Meta::CPAN


    package Example::Controller::Account;

    use Moose;
    use MooseX::MethodAttributes;

    extends 'Catalyst::Controller';

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

      sub update :POST Chained('root') PathPart('') Args(0) Does(RequestModel) BodyModel(AccountRequest) {
        my ($self, $c, $request_model) = @_;
        ## Do something with the $request_model
      }

      sub list :GET Chained('root') PathPart('') Args(0) Does(RequestModel) QueryModel(PagingModel) {
        my ($self, $c, $paging_model) = @_;
      }

    __PACKAGE__->meta->make_immutable;

=head1 DESCRIPTION

Moves creating the request model into the action class execute phase.  The following two actions are essentially
the same in effect:

    sub update :POST Chained('root') PathPart('') Args(0) Does(RequestModel) BodyModel(AccountRequest) {
      my ($self, $c, $request_model) = @_;
      ## Do something with the $request_model
    }

    sub update :POST Chained('root') PathPart('') Args(0) {
      my ($self, $c) = @_;
      my $request_model = $c->model('AccountRequest');
      ## Do something with the $request_model
    }

The main reason for moving this into the action attributes line is the thought that it allows us
to declare the request model as meta data on the action and in the future we will be able to
introspect that meta data at application setup time to do things like generate an Open API specification.
Also, if you have several request models for the endpoint you can declare all of them on the
attributes line and we will match the incoming request to the best request model, or throw an exception

lib/Catalyst/ActionRole/RequestModel.pm  view on Meta::CPAN


    package Example::Controller::Account;

    use Moose;
    use MooseX::MethodAttributes;

    extends 'Catalyst::Controller';

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

      sub update :POST Chained('root') PathPart('') Args(0) Does(RequestModel) BodyModel() {
        my ($self, $c, $request_model) = @_;
        ## Do something with the $request_model
      }

      sub list :GET Chained('root') PathPart('') Args(0) Does(RequestModel) QueryModel() {
        my ($self, $c, $paging_model) = @_;
      }

For the body model associated with the C<update> action, we will look for a model named
C<Example::Model::Account:UpdateBody> and for the query model associated with the C<list> action

lib/Catalyst/ActionRole/RequestModel.pm  view on Meta::CPAN


    use Moose;
    use MooseX::MethodAttributes;

    extends 'Catalyst::Controller';

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

      ## You can use either ~ or ~:: to indicate 'under the current namespace'.

      sub update :POST Chained('root') PathPart('') Args(0) Does(RequestModel) BodyModel(~::RequestBody) {
        my ($self, $c, $request_model) = @_;
        ## Do something with the $request_model
      }

      sub list :GET Chained('root') PathPart('') Args(0) Does(RequestModel) QueryModel(~RequestQuery) {
        my ($self, $c, $paging_model) = @_;
      }

    __PACKAGE__->meta->make_immutable;

lib/Catalyst/ActionRole/RequestModel.pm  view on Meta::CPAN


=head2 BodyModel

Should be the name of a L<Catalyst::Model> subclass that does <CatalystX::RequestModel::DoesRequestModel>.  You may 
supply more than one value to handle different request content types (the code will match the incoming
content type to an available request model and throw an L<CatalystX::RequestModel::Utils::InvalidContentType>
exception if none of the available models match.

Example of an action with more than one request model, which will be matched based on request content type.

    sub update :POST Chained('root') PathPart('') Args(0) Does(RequestModel) BodyModel(AccountRequestForm) RequestModel(AccountRequestJSON) {
      my ($self, $c, $request_model) = @_;
      ## Do something with the $request_model
    }

Also, if more than one model matches, you'll get an instance of each matching model.

You can also leave the C<BodyModel> value empty; if you do so it use a default model based on the action private name.
For example if the private name is C</posts/user_comments> we will look for a model package name C<MyApp::Model::Posts::UserCommentsBody>.
Please see L</ATTRITBUTE VALUE DEFAULTS> for more on configurating and controlling how this works.

lib/CatalystX/RequestModel.pm  view on Meta::CPAN


    package Example::Controller::Register;

    use Moose;
    use MooseX::MethodAttributes;

    extends 'Catalyst::Controller';

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

    sub update :POST Chained('root') PathPart('') Args(0) Does(RequestModel) BodyModel(RegistrationRequest) {
      my ($self, $c, $request_model) = @_;
      ## Do something with the $request_model (instance of 'Example::Model::RegistrationRequest').
    }

    sub list :GET Chained('root') PathPart('') Args(0) Does(RequestModel) QueryModel(PagingModel) {
      my ($self, $c, $paging_model) = @_;
    }


    __PACKAGE__->meta->make_immutable;

lib/CatalystX/RequestModel.pm  view on Meta::CPAN

with nesting.  JSON is actually easier since we don't need a parsing convention to turn the
flat list you get with HTML Form post into a deep structure, nor deal with some of form posting's
idiocracies.

=head2 Endpoints with more than one request model

If an endpoint can handle more than one type of incoming content type you can define that
via the subroutine attribute and the code will pick the right one or throw an exception if none match
(See L</EXCEPTIONS> for more).

    sub update :POST Chained('root') PathPart('') Args(0) 
      Does(RequestModel) 
      RequestModel(RegistrationRequestForm) 
      RequestModel(RegistrationRequesJSON)
    {
      my ($self, $c, $request_model) = @_;
      ## Do something with the $request_model
    }

Also see L<Catalyst::ActionRole::RequestModel>.



( run in 0.500 second using v1.01-cache-2.11-cpan-4d4bc49f3ae )