[Catalyst] RESTful perl implementations...

J. Shirley jshirley at gmail.com
Fri Sep 8 17:56:34 CEST 2006


I'm working on a similar thing, except relying heavier on JSON-RPC for
certain things, and a mix of RESTful constructs for the rest.

Maybe an IRC meeting where we can get together and compare notes to
solidify our efforts?

-J

On 9/7/06, Garrett Goebel <ggoebel at goebel.ws> wrote:
> My apologies. I haven't made the time yet to fix my code to use an
> ActionClass. And it doesn't look like I'll have a chance to work on
> things again until this weekend at the earliest.
>
> In the mean time, you might consider checking out the
> Jifty::Plugin::REST::Dispatcher in the svn repository (http://
> svn.jifty.org/svn/jifty.org) and the slides from the following
> presentation: http://pugs.blogs.com/talks/oscon-rhox.pdf.
>
> cheers,
>
> Garrett
>
>
> On Sep 7, 2006, at 8:22 AM, John Napiorkowski wrote:
>
> > I'm not trying to make something as magical as
> > InstantCRUD, but I'd like to add some RESTful matching
> > and convienence to Catalyst actions.  So I'd like to
> > be able to match on various HTTP method types and
> > preparse XML type bodies by various modules (XML::Atom
> > if it's an atom feed, XML::Simple if it's
> > application/xml, etc.)
> >
> > My goal is to make it easy to build web services
> > similar to the Google Data API.
> >
> > As a side project, but related, I'm working up a
> > controller to handle different error types, so you can
> > just say $c->detach('/errors/method_not_allowed') and
> > have it give a meaningful response.
> >
> > I've attached something I'm working on (which I am
> > sure doesn't work yet :) ) to give you the idea of my
> > direction.  If you think it looks in the same ballpark
> > as your goal we should followup.
> >
> > Seems all the cool REST articles are using Python or
> > Ruby, I'd like to give them a reason to use Perl
> > instead :)
> >
> > --john
> >
> > --- Garrett Goebel <ggoebel at goebel.ws> wrote:
> >
> >> On Sep 6, 2006, at 3:35 PM, John Napiorkowski wrote:
> >>
> >>> Garrett,
> >>>
> >>> Looks like we are working on something similar.  I
> >>> hadn't noticed your postings about two weeks about
> >> (I
> >>> was in the middle of moving from Beijing back to
> >> the
> >>> USA and missed about a week of Catalyst postings)
> >> or I
> >>> might have saved time asking the same questions
> >> you
> >>> asked.
> >>>
> >>> I'm actually doing this as an Action class.  Since
> >> I
> >>> don't find any additional posts I'm not sure your
> >>> status.  Want to collaborate?  I am also very
> >>> interested in REST based services and would enjoy
> >>> having someone to bounce ideas off of.
> >>>
> >>>
> >>
> >> I've just been through something similar. Moving
> >> back to the USA from
> >> Lima, Peru.
> >>
> >> I spent the week following that last post dissecting
> >> InstantCRUD and
> >> rewriting something similar but RESTful for the work
> >> I've previously
> >> mentioned. I had to present something that kinda
> >> sorta worked on the
> >> 28th. Which led to many shortcuts being taken. I'm
> >> still not happy
> >> with where I'm at. But the last week of
> >> transitioning back to the
> >> states and getting the kids into school is settling
> >> down. Reminder to
> >> self... I still need to send a foreign key patch for
> >>
> >> DBIx::Class::Schema::Loader::DBI::SQLite to Brandon.
> >>
> >> I'd be happy to collaborate. I'm fully aware that
> >> I'm unaware of
> >> Catalyst best practices. And like you, I'd love to
> >> bounce ideas and
> >> code around.
> >>
> >> Perhaps you could start by describing your goals and
> >> your approach in
> >> more detail. I still need to convert my hacked
> >> Catalyst::Action into
> >> an class derived from ActionClass. If I get some
> >> time tomorrow, I'll
> >> work that up and post some code.
> >>
> >> cheers,
> >>
> >> Garrett
> >>
> >>
> >>> --- Garrett Goebel <ggoebel at goebel.ws> wrote:
> >>>
> >>>> On Aug 22, 2006, at 3:49 AM, Matt S Trout wrote:
> >>>>>> Garrett Goebel wrote:
> >>>>>>
> >>>>>> I hacked something into the Path and Regex
> >>>> dispatchers to get
> >>>> collective
> >>>>>> matching on method and path working in the
> >>>> prototype.
> >>>>>
> >>>>> You shouldn't need to hack anything into these;
> >>>> just use a custom
> >>>> ActionClass
> >>>>> that overrides $action->match to introspect onto
> >>>> the request
> >>>> method and
> >>>>> anything else you need (this is already how
> >> :Args
> >>>> is handled, see the
> >>>>> Catalyst::Action source for the implementation).
> >>>>
> >>>> Thanks. I'd found the :Args code in
> >> Catalyst::Action
> >>>> last night and
> >>>> managed to shoehorn the request method and path
> >>>> parameter matching
> >>>> checks into it. How to subclass or override it
> >> was
> >>>> going to be my
> >>>> next question. I'll check out using a custom
> >>>> ActionClass.
> >>>>
> >>>> Last night I also sub-classed the Request class
> >> to
> >>>> add:
> >>>> __PACKAGE__->mk_accessors(qw/path_parameters
> >>>> accept_extension/);
> >>>>
> >>>> And I'm currently subclassing the Dispatcher to
> >>>> override
> >>>> prepare_action in order to:
> >>>> o  remove uri path parameters from
> >> $c->request->path
> >>>> and add to
> >>>>     $c->request->path_parameters
> >>>> o  remove "file" extension from last path segment
> >>>> and add to
> >>>>     $c->request->accept_extension
> >>>> o  filter body parameters from using content_type
> >>>> implied by the
> >>>>     accept_extension (json, yaml, etc) and add to
> >>>> $c->request-
> >>>>> parameters.
> >>>>     Perhaps I should consider just using the
> >>>> $c->request->content_type?
> >>>> o  check POST requests for hidden
> >> _method=DELETE|PUT
> >>>> parameter and
> >>>> update
> >>>>     $c->request->method accordingly
> >>>>
> >>>> These are all things I want to do once per
> >> request,
> >>>> not once per
> >>>> action. Certainly there are better places to
> >> perform
> >>>> some of these
> >>>> tasks. And I would like to hear any advice on the
> >>>> best place to
> >>>> override catalyst for each. In the mean time, at
> >>>> least I've got a
> >>>> proof of concept working.
> >>>>
> >>>>
> >>>> My controller now is able to look like:
> >>>>
> >>>> # GET http://foo.com/model
> >>>> # GET http://foo.com/model.json
> >>>> sub index :GET :Path('') Args(0) {
> >>>>      my ($self, $c) = @_;
> >>>>      my @models = grep {
> >>>> UNIVERSAL::can($c->model($_),
> >>>> 'result_source') }
> >>>>                   $c->models;
> >>>>      $self->out($c, \@models);
> >>>>      1;
> >>>> }
> >>>>
> >>>> # GET http://foo.com/model/Person
> >>>> sub show :GET :Path('') :Args(1) {
> >>>>      my ($self, $c, $model) = @_;
> >>>>      my @pkcols =
> >>>>
> >> $c->model($model)->result_source->primary_columns;
> >>>>      my @pk_tuples = map(
> >>>>          { my $tuple = $_; csv_encode(map({
> >>>> $tuple->$_ } @pkcols)) }
> >>>>          $c->model($model)->search(undef,
> >>>>                                    {columns  =>
> >>>> \@pkcols,
> >>>>                                     distinct =>
> >> 1,
> >>>>                                     order_by =>
> >>>> \@pkcols})
> >>>>      );
> >>>>      $self->out($c, \@pk_tuples);
> >>>>      1;
> >>>> }
> >>>>
> >>>> # GET http://foo.com/model/Person;edit
> >>>> sub edit :GET :Path('') :PathParam(edit) :Args(1)
> >>>> {...}
> >>>>
> >>>> # GET http://foo.com/model/Person;add
> >>>> sub add :GET :Path('') :PathParam(add) :Args(1)
> >>>> {...}
> >>>>
> >>>>
> >>>> # GET http://foo.com/model/Person;column_info
> >>>> # GET
> >> http://foo.com/model/Person.yaml;column_info
> >>>> sub show_column_info :GET :Path('')
> >>>> :PathParam(column_info) :Args(1) {
> >>>>      my ($self, $c, $model) = @_;
> >>>>      my $rs  = $c->model($model)->result_source;
> >>>>      my %column_info = map { $_ =>
> >>>> $rs->column_info($_)} $rs->columns;
> >>>>      $self->out($c, \%column_info);
> >>>>      1;
> >>>> }
> >>>>
> >>>> # POST http://foo.com/model/Person;new
> >>>> sub create :POST :Path('') :PathParam(new)
> >> :Args(1)
> >>>> {...}
> >>>>
> >>>> # PUT http://foo.com/model/Person/32
> >>>> sub update :PUT :Path('') :Args(2) {...}
> >>>>
> >>>> # DELETE http://foo.com/model/Person/32
> >>>> sub destroy :DELETE :Path('') :Args(2) {...}
> >>>>
> >>
> >>



More information about the Catalyst mailing list