[Catalyst] RESTful perl implementations...

John Napiorkowski jjn1056 at yahoo.com
Sun Sep 10 08:21:25 CEST 2006


As I promised earlier, attached is a sample
ActionClass that seems to work okay to match on HTTP
request methods, but will clearly need a lot more. 
I'd not even a proper CPAN module and has no tests. 
But it shows the direction I was thinking of taking. 
I also included a controller that demos it, but you'll
need to massage it a bit to work under your
application.

I would appreciate your thoughts and criticisms. 

Thanks!

John

--- John Napiorkowski <jjn1056 at yahoo.com> wrote:

> I'd like something like that for creating my atom
> services, or at least to get me started on them. 
> Ideally this could be something that could also
> generate code I could save and then tweak as well as
> a
> 'plug and go' deal.
> 
> I think thing project has a couple of pieces I can
> see.  Let me put them down and see what you all
> think
> 
> - A way to match actions based on http methods or
> http
> headers.  I mention headers because the google API
> supports using POST as PUT if there is a certain
> header (which one I forgot).  That way we can make
> it
> easy to dispatch REST style without needing to right
> if($c->method eq "POST")... type code everywhere. 
> Thise would have the benefit of playing really nice
> with the new chaining dispatcher.
> 
> - W'd like to automatically inflate/deflate the http
> body to make it easy to access. I think
> XML::Atom::Server has some good ideas for this and
> I've been using bits of that package in my app.  So
> if
> you Atom entry had an iCal as the content body it
> should autmatically create an iCal object, and so
> forth.
> 
> - Another piece would be to have an easy way to use
> a
> CRUD tool to setup the Atom services.  So something
> given a table it would auto publish feeds and
> entries
> for this.
> 
> - Then we'd like to have an easy way to use the
> services in another catalyst application server. 
> There's the XML::Feed model that was recently
> published to serve as a guide for this I think.
> 
> I think a lot of this is already out there in bits
> and
> pieces, particularly the XML::Atom group of modules.
> 
> A have an actionclass for the above almost working
> in
> some form.  I'll try to wrap up a workable version
> of
> it for you to try out tonight.
> 
> --john
> 
> --- Zbigniew Lukasiak <zzbbyy at gmail.com> wrote:
> 
> > Hi all,
> > 
> > Do you think it would fit into InstantCRUD?  I can
> > imagine that if you make
> > it easily pluggable I could include it into the
> > generator.
> > 
> > --
> > Zbyszek
> > 
> > On 9/9/06, John Napiorkowski <jjn1056 at yahoo.com>
> > wrote:
> > >
> > > I'd like something that would be similar to the
> > Google
> > > API (Based on Atom) and would also support JSON
> > for
> > > the feed data.  I also think RPC of some sort is
> > > useful for particular method oriented tasks,
> > certain
> > > things just don't fit well into the REST
> paradigm
> > (in
> > > my opinion, but don't want to start a flame war
> :)
> > )
> > >
> > > I'd be into meeting up on IRC sometime.  I'm in
> > the
> > > East Coast USA timezone (GMT-5).  What about the
> > rest
> > > of you?  I can meet up during this coming
> weekend.
> > >
> > > --john
> > >
> > > --- "J. Shirley" <jshirley at gmail.com> wrote:
> > >
> > > > 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)
> > {...}
> > > > > >>>>
> > > > > >>
> > > > > >>
> > > >
> > > >
> _______________________________________________
> > > > List: Catalyst at lists.rawmode.org
> > > > Listinfo:
> > > >
> > http://lists.rawmode.org/mailman/listinfo/catalyst
> > > > Searchable archive:
> > > >
> > >
> >
>
http://www.mail-archive.com/catalyst@lists.rawmode.org/
> > > > Dev site: http://dev.catalyst.perl.org/
> > > >
> > >
> > >
> > >
> __________________________________________________
> > > Do You Yahoo!?
> > > Tired of spam?  Yahoo! Mail has the best spam
> > protection around
> > > http://mail.yahoo.com
> > >
> > > _______________________________________________
> > > List: Catalyst at lists.rawmode.org
> > > Listinfo:
> > http://lists.rawmode.org/mailman/listinfo/catalyst
> > > Searchable archive:
> > >
> >
>
http://www.mail-archive.com/catalyst@lists.rawmode.org/
> > > Dev site: http://dev.catalyst.perl.org/
> > >
> > 
> > 
> > 
> > -- 
> > Zbigniew Lukasiak
> > http://brudnopis.blogspot.com/
> > > _______________________________________________
> > List: Catalyst at lists.rawmode.org
> > Listinfo:
> > http://lists.rawmode.org/mailman/listinfo/catalyst
> > Searchable archive:
> >
>
http://www.mail-archive.com/catalyst@lists.rawmode.org/
> > Dev site: http://dev.catalyst.perl.org/
> > 
> 
> 
> __________________________________________________
> Do You Yahoo!?
> Tired of spam?  Yahoo! Mail has the best spam
> protection around 
> http://mail.yahoo.com 
> 
> _______________________________________________
> List: Catalyst at lists.rawmode.org
> Listinfo:
> http://lists.rawmode.org/mailman/listinfo/catalyst
> Searchable archive:
>
http://www.mail-archive.com/catalyst@lists.rawmode.org/
> Dev site: http://dev.catalyst.perl.org/
> 


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 



More information about the Catalyst mailing list