FAQ
I have started to write a Catalyst base controller for REST style CRUD
via DBIC. I have noticed that a number of other people have been
working on or are thinking about working on something similar, most
notabley J. Shirley who seems to be creating
Catalyst::Controller::REST::DBIC::Item
(http://dev.catalystframework.org/svnweb/Catalyst/browse/Catalyst-Controller-REST-DBIC-Item/)
and some chaps from a recent thread on this list (entitled
"Dispatching with Chained vs HTTP method").

Ideally I would like to merge J. Shirley's effort into mine (or visa
versa) along with anything that anyone else has. Basically I want to
avoid ending up with a load of modules that all do the same thing.

My effort is heavily based on something mst wrote a while ago, and
since then I've ended up writing something very similar for every
project I've worked on which indicates it's worth OSing. Essentially
it is used like so:

package MyApp::Controller::API::REST::CD;

use base qw/Catalyst::Controller::REST::DBIC/;

...

__PACKAGE__->config
( action => { setup => { PathPart => 'cd', Chained =>
'/api/rest/rest_base' } },
class => 'RestTestDB::CD',
create_requires => ['artist', 'title', 'year' ],
update_allows => ['title', 'year']
);

And this gets you the following endpoints to fire requests at:
/api/rest/cd/create
/api/rest/cd/id/[cdid]/update
/api/rest/cd/id/[cdid]/delete
/api/rest/cd/id/[cdid]/add_to_rel/[relation]
/api/rest/cd/id/[cdid]/remove_from_rel/[relation]

The full source is here:
http://lukesaunders.me.uk/dists/Catalyst-Controller-REST-DBIC-1.000000.tar.gz

If you have a few moments please have a look, especially if you are
working on something similar. Today I even wrote a test suite which
has a test app and is probably the best place to look to see what it
does.

Note that it lacks:
- list and view type methods which dump objects to JSON (or whatever)
- clever validation - it should validate based on the DBIC column
definitions but it doesn't
- any auth - not sure if it should or not, but it's possible

Also it doesn't distinguish between POST, PUT, DELETE and GET HTTP
requests favouring instead entirely separate endpoints, but that's up
for discussion.

So, J. Shirley, do you have any interest in a merge? And others, do
you have ideas and would you like to contribute?

Thanks,
Luke.

Search Discussions

  • Patrick Donelan at May 4, 2008 at 5:29 am

    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]

    Those URLs don't strike me as very RESTful.

    Patrick
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20080504/e5bd8198/attachment.htm
  • Jay Shirley at May 4, 2008 at 6:05 am

    On Sat, May 3, 2008 at 9:29 PM, Patrick Donelan wrote:
    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]
    Those URLs don't strike me as very RESTful.

    Patrick
    That is my first impression. My work is an enhancement from
    Catalyst::Action::REST, which is a great module already out on CPAN
    and used by other people (holoway++).

    I'm all for collaboration, but my work is mostly tied to have exposed
    webservices (in addition to a web-browser compatibility layer) via
    REST. By that I mean that I expect, and require, that I can do a PUT
    /api/rest/cd/[cdid], DELETE /api/rest/cd/[CDID]

    On a side note about REST - REST doesn't mean human readable URLs. It
    means representative URLs. The bit about cd/id/{CDID}/ smells like
    named parameters going into positional parameters. What is the real
    difference between cd?id={CDID}&action=delete, aside from different
    characters? Where as with REST, /cd/{id} is a unique identifier for
    that object and hence a full representation.

    I understand the limitations of /cd/id/{id} vs. /cd/name/{id}, but a
    lookup and redirection service is a better solution that polluting
    your absolute unique representative URL spaces.

    You can catch me on IRC next week, as I'm actively working on this for
    $work and it's getting real dev time (finally). My work is
    functionally complete, but lacking test cases; it is just a refactor
    of existing code in production.

    -J
  • Zbigniew Lukasiak at May 4, 2008 at 9:52 am

    On Sun, May 4, 2008 at 7:05 AM, J. Shirley wrote:
    On Sat, May 3, 2008 at 9:29 PM, Patrick Donelan wrote:

    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]
    Those URLs don't strike me as very RESTful.

    Patrick
    That is my first impression. My work is an enhancement from
    Catalyst::Action::REST, which is a great module already out on CPAN
    and used by other people (holoway++).

    I'm all for collaboration, but my work is mostly tied to have exposed
    webservices (in addition to a web-browser compatibility layer) via
    REST. By that I mean that I expect, and require, that I can do a PUT
    /api/rest/cd/[cdid], DELETE /api/rest/cd/[CDID]

    On a side note about REST - REST doesn't mean human readable URLs. It
    means representative URLs. The bit about cd/id/{CDID}/ smells like
    named parameters going into positional parameters. What is the real
    difference between cd?id={CDID}&action=delete, aside from different
    characters? Where as with REST, /cd/{id} is a unique identifier for
    that object and hence a full representation.
    The problem I see with /cd/{id} is that when you have a primary key
    that is 'create' - this would clash with the 'create' action.
    /cd/id/{id} let's you separate the reserved words from the user data.

    I understand the limitations of /cd/id/{id} vs. /cd/name/{id}, but a
    lookup and redirection service is a better solution that polluting
    your absolute unique representative URL spaces.

    You can catch me on IRC next week, as I'm actively working on this for
    $work and it's getting real dev time (finally). My work is
    functionally complete, but lacking test cases; it is just a refactor
    of existing code in production.

    -J



    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Zbigniew Lukasiak
    http://brudnopis.blogspot.com/
  • Jay Shirley at May 4, 2008 at 2:54 pm

    On Sun, May 4, 2008 at 1:52 AM, Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 7:05 AM, J. Shirley wrote:
    On a side note about REST - REST doesn't mean human readable URLs. It
    means representative URLs. The bit about cd/id/{CDID}/ smells like
    named parameters going into positional parameters. What is the real
    difference between cd?id={CDID}&action=delete, aside from different
    characters? Where as with REST, /cd/{id} is a unique identifier for
    that object and hence a full representation.
    The problem I see with /cd/{id} is that when you have a primary key
    that is 'create' - this would clash with the 'create' action.
    /cd/id/{id} let's you separate the reserved words from the user data.
    A pet peeve of mine is that people seem to have this weird idea that
    primary key == id. An id can just be some human readable mechanism to
    looking up the item, where as the primary key is what is actually used
    by the database to determine the relations.

    They do not have to be the same field but often times they are out of
    convenience. In cases like this, they simply shouldn't be though.
  • Zbigniew Lukasiak at May 4, 2008 at 4:52 pm

    On Sun, May 4, 2008 at 3:54 PM, J. Shirley wrote:
    On Sun, May 4, 2008 at 1:52 AM, Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 7:05 AM, J. Shirley wrote:

    On a side note about REST - REST doesn't mean human readable URLs. It
    means representative URLs. The bit about cd/id/{CDID}/ smells like
    named parameters going into positional parameters. What is the real
    difference between cd?id={CDID}&action=delete, aside from different
    characters? Where as with REST, /cd/{id} is a unique identifier for
    that object and hence a full representation.
    The problem I see with /cd/{id} is that when you have a primary key
    that is 'create' - this would clash with the 'create' action.
    /cd/id/{id} let's you separate the reserved words from the user data.
    A pet peeve of mine is that people seem to have this weird idea that
    primary key == id. An id can just be some human readable mechanism to
    looking up the item, where as the primary key is what is actually used
    by the database to determine the relations.

    They do not have to be the same field but often times they are out of
    convenience. In cases like this, they simply shouldn't be though.
    Sorry but I don't understand your point - so maybe first I'll restate
    mine. If you have primary key in the database that is of type varchar
    (or char or ...) then 'create' is a legitimage value for that primary
    key.

    If you just don't like the string 'id' in the URI - then I have not
    any preference to that - it can be /foo/primary_key/ for me.


    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Zbigniew Lukasiak
    http://brudnopis.blogspot.com/
  • Christopher Laco at May 4, 2008 at 5:02 pm

    Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 3:54 PM, J. Shirley wrote:
    On Sun, May 4, 2008 at 1:52 AM, Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 7:05 AM, J. Shirley wrote:

    On a side note about REST - REST doesn't mean human readable URLs. It
    means representative URLs. The bit about cd/id/{CDID}/ smells like
    named parameters going into positional parameters. What is the real
    difference between cd?id={CDID}&action=delete, aside from different
    characters? Where as with REST, /cd/{id} is a unique identifier for
    that object and hence a full representation.
    The problem I see with /cd/{id} is that when you have a primary key
    that is 'create' - this would clash with the 'create' action.
    /cd/id/{id} let's you separate the reserved words from the user data.
    A pet peeve of mine is that people seem to have this weird idea that
    primary key == id. An id can just be some human readable mechanism to
    looking up the item, where as the primary key is what is actually used
    by the database to determine the relations.

    They do not have to be the same field but often times they are out of
    convenience. In cases like this, they simply shouldn't be though.
    Sorry but I don't understand your point - so maybe first I'll restate
    mine. If you have primary key in the database that is of type varchar
    (or char or ...) then 'create' is a legitimage value for that primary
    key.

    If you just don't like the string 'id' in the URI - then I have not
    any preference to that - it can be /foo/primary_key/ for me.

    My pet peeve is that /foo/primary_key makes computers happy... but not
    people.


    /products/23
    /products/ABC-1234


    The first is the PK for a product record..
    The second is the actual sku for a product... just a unique as the
    pk...but not the PK itself...


    Now what does "id" mean in this case?
    What id your SKU is a numeric just like your PK?

    Two different and equally useful ways to get at the same resource.

    If you're talking about an interface where humans know the skus, and
    computers know the id (restfully and/or remotely).. you need a sane uri:

    /products/id/<id>
    /products/sku/<sku>

    In the end, I always run into a situation where humans (think marketing
    SEO pushers who know not of REST) want something other than a true
    restful uri.

    -=Chris
  • Jay Shirley at May 4, 2008 at 5:09 pm

    On Sun, May 4, 2008 at 9:02 AM, Christopher Laco wrote:
    Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 3:54 PM, J. Shirley wrote:
    On Sun, May 4, 2008 at 1:52 AM, Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 7:05 AM, J. Shirley wrote:
    On a side note about REST - REST doesn't mean human readable
    URLs. It
    means representative URLs. The bit about cd/id/{CDID}/ smells
    like
    named parameters going into positional parameters. What is the
    real
    difference between cd?id={CDID}&action=delete, aside from
    different
    characters? Where as with REST, /cd/{id} is a unique identifier
    for
    that object and hence a full representation.
    The problem I see with /cd/{id} is that when you have a primary key
    that is 'create' - this would clash with the 'create' action.
    /cd/id/{id} let's you separate the reserved words from the user
    data.
    A pet peeve of mine is that people seem to have this weird idea that
    primary key == id. An id can just be some human readable mechanism to
    looking up the item, where as the primary key is what is actually used
    by the database to determine the relations.

    They do not have to be the same field but often times they are out of
    convenience. In cases like this, they simply shouldn't be though.
    Sorry but I don't understand your point - so maybe first I'll restate
    mine. If you have primary key in the database that is of type varchar
    (or char or ...) then 'create' is a legitimage value for that primary
    key.

    If you just don't like the string 'id' in the URI - then I have not
    any preference to that - it can be /foo/primary_key/ for me.

    My pet peeve is that /foo/primary_key makes computers happy... but not
    people.


    /products/23
    /products/ABC-1234


    The first is the PK for a product record..
    The second is the actual sku for a product... just a unique as the pk...but
    not the PK itself...


    Now what does "id" mean in this case?
    What id your SKU is a numeric just like your PK?

    Two different and equally useful ways to get at the same resource.

    If you're talking about an interface where humans know the skus, and
    computers know the id (restfully and/or remotely).. you need a sane uri:

    /products/id/<id>
    /products/sku/<sku>

    In the end, I always run into a situation where humans (think marketing SEO
    pushers who know not of REST) want something other than a true restful uri.

    -=Chris

    To be honest, I'd rather see something like /products/-{id} and
    /products/{sku}. Simple checks like that make things easy, and the
    '-' is inconvenient for a human but then they don't have to type a
    (seemingly redundant) /sku at each time.

    But also, with an index, a sku lookup should be equal to an id lookup,
    so in this particular hypothetical case I would always go with the
    sku. If you use DBIC or any other sufficiently sane ORM, you don't
    need to ever bother directly with the primary key field, and just do
    $obj->relation and be done.
  • Steve Atkins at May 4, 2008 at 5:33 pm

    On May 4, 2008, at 9:02 AM, Christopher Laco wrote:

    My pet peeve is that /foo/primary_key makes computers happy... but
    not people.


    /products/23
    /products/ABC-1234


    The first is the PK for a product record..
    The second is the actual sku for a product... just a unique as the
    pk...but not the PK itself...


    Now what does "id" mean in this case?
    What id your SKU is a numeric just like your PK?

    Two different and equally useful ways to get at the same resource.

    If you're talking about an interface where humans know the skus, and
    computers know the id (restfully and/or remotely).. you need a sane
    uri:

    /products/id/<id>
    /products/sku/<sku>

    In the end, I always run into a situation where humans (think
    marketing SEO pushers who know not of REST) want something other
    than a true restful uri.
    Part of the problem here might be the wish to avoid a natural
    primary key in the database schema, preferring a synthetic
    primary key even when there's a perfectly good natural
    primary key.

    That's something that I expect to see from the ruby on
    rails crowd, not the (presumably more pragmatic) perl folks.

    If your SKU is unique, then it's a perfectly good primary
    key, and having a synthetic numeric primary key isn't
    necessary. (It might be the right choice in some cases,
    and not in others, but "the primary key is an arbitrary
    integer" is not a given).

    Cheers,
    Steve
  • Christopher Laco at May 4, 2008 at 5:42 pm

    Steve Atkins wrote:
    On May 4, 2008, at 9:02 AM, Christopher Laco wrote:



    My pet peeve is that /foo/primary_key makes computers happy... but not
    people.


    /products/23
    /products/ABC-1234


    The first is the PK for a product record..
    The second is the actual sku for a product... just a unique as the
    pk...but not the PK itself...


    Now what does "id" mean in this case?
    What id your SKU is a numeric just like your PK?

    Two different and equally useful ways to get at the same resource.

    If you're talking about an interface where humans know the skus, and
    computers know the id (restfully and/or remotely).. you need a sane uri:

    /products/id/<id>
    /products/sku/<sku>

    In the end, I always run into a situation where humans (think
    marketing SEO pushers who know not of REST) want something other than
    a true restful uri.
    Part of the problem here might be the wish to avoid a natural
    primary key in the database schema, preferring a synthetic
    primary key even when there's a perfectly good natural
    primary key.

    That's something that I expect to see from the ruby on
    rails crowd, not the (presumably more pragmatic) perl folks.

    If your SKU is unique, then it's a perfectly good primary
    key, and having a synthetic numeric primary key isn't
    necessary.
    Not really. SKU is unique yes, but it can change (renamed, reconfigured
    when companies merge, etc) for the same physical product. It's a poor PK
    for the purposes of joining records to it, but a great key for the
    purposes of lookup and selling the item.

    One could argue that UPC is a better key than sku, but that's not very
    friendly.

    -=Chris
  • Matt S Trout at May 5, 2008 at 12:29 pm

    On Sun, May 04, 2008 at 09:33:50AM -0700, Steve Atkins wrote:
    Part of the problem here might be the wish to avoid a natural
    primary key in the database schema, preferring a synthetic
    primary key even when there's a perfectly good natural
    primary key.

    That's something that I expect to see from the ruby on
    rails crowd, not the (presumably more pragmatic) perl folks.
    Actually, sometimes a synthetic primary key even when there's a perfectly
    good natural one is important. For e.g. InnoDB always clusters by the PK,
    so depending on your access patterns it can be a hell of a lot more
    efficient.

    Pragmatism is a many-edged sword :)

    --
    Matt S Trout Need help with your Catalyst or DBIx::Class project?
    Technical Director http://www.shadowcat.co.uk/catalyst/
    Shadowcat Systems Ltd. Want a managed development or deployment platform?
    http://chainsawblues.vox.com/ http://www.shadowcat.co.uk/servers/
  • Jay Shirley at May 4, 2008 at 5:06 pm

    On Sun, May 4, 2008 at 8:52 AM, Zbigniew Lukasiak wrote:
    Sorry but I don't understand your point - so maybe first I'll restate
    mine. If you have primary key in the database that is of type varchar
    (or char or ...) then 'create' is a legitimage value for that primary
    key.

    If you just don't like the string 'id' in the URI - then I have not
    any preference to that - it can be /foo/primary_key/ for me.
    My point is that you do not have to use the primary key as the record
    lookup identifier.

    A user has no control over the record lookup identifier (ID) when you
    do things like /user/{primary_key} (or /user/id/{primary_key}, which
    is just converting named params to positional in a weird way). In a
    lot of cases, the record lookup identifier makes more sense to be
    somewhat bound to the user. As an example, lets say registering for a
    web service where you have to have a unique login:
    POST /user/jshirley
    ---
    login: jshirley
    first_name: Jay
    last_name: Shirley
    ...

    Now, it's a simple check here - does /user/jshirley exist? If so,
    reject the request appropriately. If not, create the user at
    /user/jshirley.

    The primary key that the database uses is completely useless to the
    user. /user/1634254 is silly, /user/jshirley is meaningful.

    If the ID is generated, that gets a bit trickier but I usually handle
    that with a POST to /user with the data and then let the application
    forward me to the final URL of where the resource exists.

    The other reason is that this system breaks when you no longer have
    records tied to a database. As an example, if you use an md5 sum of a
    file as the identifier. /file/1234 doesn't work because it isn't in a
    database under that system (think of a MogileFS cluster or something
    with hash keys rather than primary keys in the conventional sense) -
    instead /file/{md5sum} is used.

    In brief summary, over-utilization of primary keys as record lookup
    identifiers ends up diminishing the human readability and
    accessibility of your web service. I'm not trying to win over any
    converts, because I think there is a time and a place for each (even
    in the same application, it just depends upon what each action is
    really doing). If I'm not building something that is REST/webservice
    driven I tend to do the /user/{id or token} (with a simple regex to
    check, and if someone has a login of all numbers then screw 'em) - but
    it's a very different strategy when I work with webservices -- each
    time I always make sure if the record lookup indicator should be the
    primary key, and what cases should it not and then react accordingly.
  • Zbigniew Lukasiak at May 4, 2008 at 5:36 pm

    On Sun, May 4, 2008 at 6:06 PM, J. Shirley wrote:
    On Sun, May 4, 2008 at 8:52 AM, Zbigniew Lukasiak wrote:
    Sorry but I don't understand your point - so maybe first I'll restate
    mine. If you have primary key in the database that is of type varchar
    (or char or ...) then 'create' is a legitimage value for that primary
    key.

    If you just don't like the string 'id' in the URI - then I have not
    any preference to that - it can be /foo/primary_key/ for me.
    My point is that you do not have to use the primary key as the record
    lookup identifier.

    A user has no control over the record lookup identifier (ID) when you
    do things like /user/{primary_key} (or /user/id/{primary_key}, which
    is just converting named params to positional in a weird way). In a
    lot of cases, the record lookup identifier makes more sense to be
    somewhat bound to the user. As an example, lets say registering for a
    web service where you have to have a unique login:
    POST /user/jshirley
    ---
    login: jshirley
    first_name: Jay
    last_name: Shirley
    ...

    Now, it's a simple check here - does /user/jshirley exist? If so,
    reject the request appropriately. If not, create the user at
    /user/jshirley.

    The primary key that the database uses is completely useless to the
    user. /user/1634254 is silly, /user/jshirley is meaningful.

    If the ID is generated, that gets a bit trickier but I usually handle
    that with a POST to /user with the data and then let the application
    forward me to the final URL of where the resource exists.

    The other reason is that this system breaks when you no longer have
    records tied to a database. As an example, if you use an md5 sum of a
    file as the identifier. /file/1234 doesn't work because it isn't in a
    database under that system (think of a MogileFS cluster or something
    with hash keys rather than primary keys in the conventional sense) -
    instead /file/{md5sum} is used.

    In brief summary, over-utilization of primary keys as record lookup
    identifiers ends up diminishing the human readability and
    accessibility of your web service. I'm not trying to win over any
    converts, because I think there is a time and a place for each (even
    in the same application, it just depends upon what each action is
    really doing). If I'm not building something that is REST/webservice
    driven I tend to do the /user/{id or token} (with a simple regex to
    check, and if someone has a login of all numbers then screw 'em) - but
    it's a very different strategy when I work with webservices -- each
    time I always make sure if the record lookup indicator should be the
    primary key, and what cases should it not and then react accordingly.
    Then we are talking about two diffrent things. My point is that you
    should not have /foo/create and foo/{id or token} - because you mix a
    reserverd work 'create' with data, you can never guarantee that the
    data, be it primary key or token or whatever, does not contain
    'create'.

    I do understand that in full REST design you would not have a
    '/foo/create/' uri - but if you want to add this REST as an add-on to
    a controller you'll still have other methods on the controller that
    could conflict with the token/id.
  • Matt S Trout at May 5, 2008 at 12:31 pm

    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    On Sun, May 4, 2008 at 8:52 AM, Zbigniew Lukasiak wrote:

    Sorry but I don't understand your point - so maybe first I'll restate
    mine. If you have primary key in the database that is of type varchar
    (or char or ...) then 'create' is a legitimage value for that primary
    key.

    If you just don't like the string 'id' in the URI - then I have not
    any preference to that - it can be /foo/primary_key/ for me.
    My point is that you do not have to use the primary key as the record
    lookup identifier.

    A user has no control over the record lookup identifier (ID) when you
    do things like /user/{primary_key} (or /user/id/{primary_key}, which
    is just converting named params to positional in a weird way). In a
    lot of cases, the record lookup identifier makes more sense to be
    somewhat bound to the user. As an example, lets say registering for a
    web service where you have to have a unique login:
    POST /user/jshirley
    ---
    login: jshirley
    first_name: Jay
    last_name: Shirley
    ...

    Now, it's a simple check here - does /user/jshirley exist? If so,
    reject the request appropriately. If not, create the user at
    /user/jshirley.

    The primary key that the database uses is completely useless to the
    user. /user/1634254 is silly, /user/jshirley is meaningful.
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path component
    such as 'id' for the lookup part to disambiguate".

    --
    Matt S Trout Need help with your Catalyst or DBIx::Class project?
    Technical Director http://www.shadowcat.co.uk/catalyst/
    Shadowcat Systems Ltd. Want a managed development or deployment platform?
    http://chainsawblues.vox.com/ http://www.shadowcat.co.uk/servers/
  • Jay Shirley at May 5, 2008 at 3:50 pm

    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    On Sun, May 4, 2008 at 8:52 AM, Zbigniew Lukasiak wrote:

    Sorry but I don't understand your point - so maybe first I'll restate
    mine. If you have primary key in the database that is of type varchar
    (or char or ...) then 'create' is a legitimage value for that primary
    key.

    If you just don't like the string 'id' in the URI - then I have not
    any preference to that - it can be /foo/primary_key/ for me.
    My point is that you do not have to use the primary key as the record
    lookup identifier.

    A user has no control over the record lookup identifier (ID) when you
    do things like /user/{primary_key} (or /user/id/{primary_key}, which
    is just converting named params to positional in a weird way). In a
    lot of cases, the record lookup identifier makes more sense to be
    somewhat bound to the user. As an example, lets say registering for a
    web service where you have to have a unique login:
    POST /user/jshirley
    ---
    login: jshirley
    first_name: Jay
    last_name: Shirley
    ...

    Now, it's a simple check here - does /user/jshirley exist? If so,
    reject the request appropriately. If not, create the user at
    /user/jshirley.

    The primary key that the database uses is completely useless to the
    user. /user/1634254 is silly, /user/jshirley is meaningful.
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path component
    such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be there.

    If we were talking about RPC, that would be a differently titled
    thread and different arguments.
  • Andrew Rodland at May 5, 2008 at 4:18 pm

    On Monday 05 May 2008 09:50:08 am J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path
    component such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be
    there.
    But those nouns you're talking about aren't verbs at all.

    Andrew
  • Jay Shirley at May 5, 2008 at 5:19 pm

    On Mon, May 5, 2008 at 8:18 AM, Andrew Rodland wrote:
    On Monday 05 May 2008 09:50:08 am J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path
    component such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be
    there.
    But those nouns you're talking about aren't verbs at all.

    Andrew
    How is /create, /edit or /delete not a verb?

    My argument is separate to the /create is valid in the /foo/{token}
    bit. I'm saying that /foo/create is silly to have in the first place,
    and the /foo/id/{id} is nothing more than a conversion from named
    parameters to positional, and ugly.

    If you apply actual REST principles, you don't have such nonsense.
    But again, as I said, this is if you are working with REST. If REST
    doesn't fit your application model, don't use it. Just don't name
    things REST when they are really CRUD.
  • Zbigniew Lukasiak at May 5, 2008 at 5:49 pm

    On Mon, May 5, 2008 at 6:19 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 8:18 AM, Andrew Rodland wrote:
    On Monday 05 May 2008 09:50:08 am J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path
    component such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be
    there.
    But those nouns you're talking about aren't verbs at all.

    Andrew
    How is /create, /edit or /delete not a verb?

    My argument is separate to the /create is valid in the /foo/{token}
    bit. I'm saying that /foo/create is silly to have in the first place,
    and the /foo/id/{id} is nothing more than a conversion from named
    parameters to positional, and ugly.

    If you apply actual REST principles, you don't have such nonsense.
    But again, as I said, this is if you are working with REST. If REST
    doesn't fit your application model, don't use it. Just don't name
    things REST when they are really CRUD.
    The point is about having something that will work as REST for
    automated agents and also work for browsers by some emulation or what
    ever - so you'll have some additional actions on the controller as
    well. Additionally if we really want to make this REST Role (assuming
    Moose Catalyst by that time) - then the user of the library can have
    his own actions. In both way you'll have a clash if we go your way.

    Because /foo/id/{id} looks like a parameter - which is the only
    argument agains it and is just a bit of pedantry on your side - you
    would allow for broken logic?
  • Jay Shirley at May 5, 2008 at 6:08 pm

    On Mon, May 5, 2008 at 9:49 AM, Zbigniew Lukasiak wrote:
    On Mon, May 5, 2008 at 6:19 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 8:18 AM, Andrew Rodland wrote:
    On Monday 05 May 2008 09:50:08 am J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path
    component such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be
    there.
    But those nouns you're talking about aren't verbs at all.

    Andrew
    How is /create, /edit or /delete not a verb?

    My argument is separate to the /create is valid in the /foo/{token}
    bit. I'm saying that /foo/create is silly to have in the first place,
    and the /foo/id/{id} is nothing more than a conversion from named
    parameters to positional, and ugly.

    If you apply actual REST principles, you don't have such nonsense.
    But again, as I said, this is if you are working with REST. If REST
    doesn't fit your application model, don't use it. Just don't name
    things REST when they are really CRUD.
    The point is about having something that will work as REST for
    automated agents and also work for browsers by some emulation or what
    ever - so you'll have some additional actions on the controller as
    well. Additionally if we really want to make this REST Role (assuming
    Moose Catalyst by that time) - then the user of the library can have
    his own actions. In both way you'll have a clash if we go your way.

    Because /foo/id/{id} looks like a parameter - which is the only
    argument agains it and is just a bit of pedantry on your side - you
    would allow for broken logic?
    That's just one argument that is most obvious. The other argument is
    that it adds additional entry points into an entity that you have to
    keep in sync.

    If you have /foo/id/{id} and /foo/name/{name} that are two paths to
    the same entity, but {name} is not immutable you have broken
    navigation at some point (bookmarks, etc). So you have two immutable
    entities for the same thing? I fail to see why that works. Which
    leads into my main argument that using the primary key as the record
    lookup identifier (in many cases) is simply bad design.

    This strategy is redundancy of the oddest form to me, and it yields
    more complications down the road as applications become more complex.

    If you remove the redundancy, and each object has a well-defined
    identifier, a POST to /foo will create a new entity which redirects to
    /foo/{identifier}. It's easy to duplicate functionality that a POST
    to /foo/{identifier} works the same as a POST to just /foo, and can
    generate $identifier. I fail to see why a /create action needs to
    exist in the first place on /foo.

    Now, for browser-compatibility methods it isn't a bad thing having
    /foo/{identifier}/(edit|delete). The business with /foo/id/{ident}
    there so that you don't conflict with a "/create" action on /foo is
    just silly, and a sign of inadequate forethought into your resource
    structure. But again, this has very little to do with REST and more
    to do with a sane URI structure (although not having an explicit
    /create action is more on the RESTful side, I never have encountered
    an issue having "POST /foo" handle item creation).

    So, yes, it is pedantic but I don't view it as broken logic. I view
    it as tidy logic that doesn't employ the use of URI hacks to get
    around browser deficiencies.

    -J
  • Luke saunders at May 5, 2008 at 5:51 pm

    On Mon, May 5, 2008 at 5:19 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 8:18 AM, Andrew Rodland wrote:
    On Monday 05 May 2008 09:50:08 am J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path
    component such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be
    there.
    But those nouns you're talking about aren't verbs at all.

    Andrew
    How is /create, /edit or /delete not a verb?
    My argument is separate to the /create is valid in the /foo/{token}
    bit. I'm saying that /foo/create is silly to have in the first place ...
    Okay, let me clear this up. Originally the plan was to have a
    centralised REST-style action which dispatched POST/PUT/GET/DELETE
    requests to the appropriate actions while also providing RPC-style
    verb actions as an alternative for use if the client didn't properly
    support the REST request methods. Having listened to discussion in
    this thread I think it would be better to make the module pure REST
    and then provide the RPC alternative through a subclass, perhaps also
    integrating Catalyst::Request::REST::ForBrowsers into the REST version
    as suggested.
    If you apply actual REST principles, you don't have such nonsense.
    But again, as I said, this is if you are working with REST. If REST
    doesn't fit your application model, don't use it. Just don't name
    things REST when they are really CRUD.
    Why can't CRUD be RESTful?

    In fact my revised plan is to glue together a base REST module and a
    base CRUD module and add the list method discussed somewhere else in
    this thread to provide a complete default RESTful module. Ideally the
    REST base module could be swapped for an RPC style base module to
    easily provide an RPC alternative of the same thing.
  • Jay Shirley at May 5, 2008 at 6:16 pm

    On Mon, May 5, 2008 at 9:51 AM, luke saunders wrote:
    On Mon, May 5, 2008 at 5:19 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 8:18 AM, Andrew Rodland wrote:
    On Monday 05 May 2008 09:50:08 am J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path
    component such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be
    there.
    But those nouns you're talking about aren't verbs at all.

    Andrew
    How is /create, /edit or /delete not a verb?
    My argument is separate to the /create is valid in the /foo/{token}
    bit. I'm saying that /foo/create is silly to have in the first place ...
    Okay, let me clear this up. Originally the plan was to have a
    centralised REST-style action which dispatched POST/PUT/GET/DELETE
    requests to the appropriate actions while also providing RPC-style
    verb actions as an alternative for use if the client didn't properly
    support the REST request methods. Having listened to discussion in
    this thread I think it would be better to make the module pure REST
    and then provide the RPC alternative through a subclass, perhaps also
    integrating Catalyst::Request::REST::ForBrowsers into the REST version
    as suggested.

    If you apply actual REST principles, you don't have such nonsense.
    But again, as I said, this is if you are working with REST. If REST
    doesn't fit your application model, don't use it. Just don't name
    things REST when they are really CRUD.
    Why can't CRUD be RESTful?

    In fact my revised plan is to glue together a base REST module and a
    base CRUD module and add the list method discussed somewhere else in
    this thread to provide a complete default RESTful module. Ideally the
    REST base module could be swapped for an RPC style base module to
    easily provide an RPC alternative of the same thing.
    REST and CRUD are not mutually exclusive, but implementations can be.

    When I see things like /book/create, /book/1/edit I see CRUD (or RPC)
    but not REST. REST also doesn't have to be CRUD. I have a REST
    application that is more CR. It just posts immutable records and
    provides findability on those records.

    The discussions about a better CRUD base class with REST and RPC
    adapters is obviously the better (best?) solution, but I also think
    there will be significant disagreement between appropriate URI
    resource conventions (as my exchange with zby is an example of.) I
    haven't had enough time to actually proffer any code, but since this
    is a central focus of my development as late I'm very opinionated in
    these matters :)

    I just want to be an advocate of standards and not slip into the
    "Internet Explorer Development Methodology". Eventually browsers will
    support this stuff, in the mean time, using strict REST makes
    webservices so much easier.
  • Peter Karman at May 5, 2008 at 7:28 pm

    On 05/05/2008 12:16 PM, J. Shirley wrote:
    The discussions about a better CRUD base class with REST and RPC
    adapters is obviously the better (best?) solution, but I also think
    there will be significant disagreement between appropriate URI
    resource conventions (as my exchange with zby is an example of.)
    As has been mentioned before, there is an existing REST + CRUD implementation already on CPAN:

    http://search.cpan.org/dist/CatalystX-CRUD/lib/CatalystX/CRUD/REST.pm

    It definitely has URI styles in place already, though overriding fetch() to chain to a
    different root (like /id instead of /) seems trivial to me.

    There is also work started on a DBIC adapter, and existing model stores in place already
    for RDBO and filesystem (LDAP is on my TODO list). SVN is here:

    http://dev.catalyst.perl.org/repos/Catalyst/CatalystX-CRUD/

    I hope to push a new release of CX::CRUD soon that will support the 'x-tunneled-method'
    syntax of drolsky's REST::ForBrowsers in addition to the '_http_method' syntax of prior
    CX::CRUD::REST releases.

    Please, consider building on existing code like CX::CRUD and/or suggesting changes to the
    current implementation, rather than starting a new project. There are already too many
    CRUD-style Catalyst modules on CPAN imho.

    --
    Peter Karman . peter@peknet.com . http://peknet.com/
  • Jay Shirley at May 5, 2008 at 7:48 pm

    On Mon, May 5, 2008 at 11:28 AM, Peter Karman wrote:
    On 05/05/2008 12:16 PM, J. Shirley wrote:


    The discussions about a better CRUD base class with REST and RPC
    adapters is obviously the better (best?) solution, but I also think
    there will be significant disagreement between appropriate URI
    resource conventions (as my exchange with zby is an example of.)
    As has been mentioned before, there is an existing REST + CRUD implementation already on CPAN:

    http://search.cpan.org/dist/CatalystX-CRUD/lib/CatalystX/CRUD/REST.pm

    It definitely has URI styles in place already, though overriding fetch() to chain to a
    different root (like /id instead of /) seems trivial to me.

    There is also work started on a DBIC adapter, and existing model stores in place already
    for RDBO and filesystem (LDAP is on my TODO list). SVN is here:

    http://dev.catalyst.perl.org/repos/Catalyst/CatalystX-CRUD/

    I hope to push a new release of CX::CRUD soon that will support the 'x-tunneled-method'
    syntax of drolsky's REST::ForBrowsers in addition to the '_http_method' syntax of prior
    CX::CRUD::REST releases.

    Please, consider building on existing code like CX::CRUD and/or suggesting changes to the
    current implementation, rather than starting a new project. There are already too many
    CRUD-style Catalyst modules on CPAN imho.

    --
    Peter Karman . peter@peknet.com . http://peknet.com/
    karpet++
  • Luke saunders at May 5, 2008 at 8:33 pm
    On Mon, May 5, 2008 at 7:28 PM, Peter Karman wrote:
    On 05/05/2008 12:16 PM, J. Shirley wrote:


    The discussions about a better CRUD base class with REST and RPC
    adapters is obviously the better (best?) solution, but I also think
    there will be significant disagreement between appropriate URI
    resource conventions (as my exchange with zby is an example of.)
    As has been mentioned before, there is an existing REST + CRUD implementation already on CPAN:

    http://search.cpan.org/dist/CatalystX-CRUD/lib/CatalystX/CRUD/REST.pm
    Out of interest, why did you not use Catalyst::Controller::REST here?
    It definitely has URI styles in place already, though overriding fetch() to chain to a
    different root (like /id instead of /) seems trivial to me.

    There is also work started on a DBIC adapter, and existing model stores in place already
    for RDBO and filesystem (LDAP is on my TODO list). SVN is here:

    http://dev.catalyst.perl.org/repos/Catalyst/CatalystX-CRUD/

    I hope to push a new release of CX::CRUD soon that will support the 'x-tunneled-method'
    syntax of drolsky's REST::ForBrowsers in addition to the '_http_method' syntax of prior
    CX::CRUD::REST releases.

    Please, consider building on existing code like CX::CRUD and/or suggesting changes to the
    current implementation, rather than starting a new project. There are already too many
    CRUD-style Catalyst modules on CPAN imho.

    --
    Peter Karman . peter@peknet.com . http://peknet.com/




    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
  • Peter Karman at May 6, 2008 at 4:21 pm

    On 05/05/2008 02:33 PM, luke saunders wrote:
    On Mon, May 5, 2008 at 7:28 PM, Peter Karman wrote:
    On 05/05/2008 12:16 PM, J. Shirley wrote:


    The discussions about a better CRUD base class with REST and RPC
    adapters is obviously the better (best?) solution, but I also think
    there will be significant disagreement between appropriate URI
    resource conventions (as my exchange with zby is an example of.)
    As has been mentioned before, there is an existing REST + CRUD implementation already on CPAN:

    http://search.cpan.org/dist/CatalystX-CRUD/lib/CatalystX/CRUD/REST.pm
    Out of interest, why did you not use Catalyst::Controller::REST here?
    A few reasons.

    One, the CRUD::REST primary design goal is to allow you to simply change your @ISA list in
    order to switch from RPC to REST style URIs. If you are already using a
    CX::CRUD::Controller-based class, you just put CX::CRUD::REST at the front of your @ISA
    list and voila. That goal would have required a bit more method aliasing and other hackery
    in order to support the *_VERB API in C::C::REST.

    Two, the C::C::REST module (and related Action class) have a lot of support for automatic
    serialization. CX::CRUD is completely agnostic about response type. Maybe it shouldn't be.
    But it is.

    Three, C::C::REST does not have "real-world" browser HTTP use in mind, as
    REST::ForBrowsers does. That's not bad; it's just more "pure" imo. CX::CRUD tries to
    support both, and as of yesterday, svn has support for the 'x-tunneled-method' param like
    REST::ForBrowsers does.

    Four, I didn't need the overhead. :)

    Having said all that, I expect that C::C::REST could work well with CX::CRUD::REST, and
    I'd love to see a patch that implements it, bearing in mind the points above.

    --
    Peter Karman . peter@peknet.com . http://peknet.com/
  • Luke saunders at May 5, 2008 at 9:10 pm

    On Mon, May 5, 2008 at 6:16 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 9:51 AM, luke saunders wrote:
    On Mon, May 5, 2008 at 5:19 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 8:18 AM, Andrew Rodland wrote:
    On Monday 05 May 2008 09:50:08 am J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path
    component such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be
    there.
    But those nouns you're talking about aren't verbs at all.

    Andrew
    How is /create, /edit or /delete not a verb?
    My argument is separate to the /create is valid in the /foo/{token}
    bit. I'm saying that /foo/create is silly to have in the first place ...
    Okay, let me clear this up. Originally the plan was to have a
    centralised REST-style action which dispatched POST/PUT/GET/DELETE
    requests to the appropriate actions while also providing RPC-style
    verb actions as an alternative for use if the client didn't properly
    support the REST request methods. Having listened to discussion in
    this thread I think it would be better to make the module pure REST
    and then provide the RPC alternative through a subclass, perhaps also
    integrating Catalyst::Request::REST::ForBrowsers into the REST version
    as suggested.

    If you apply actual REST principles, you don't have such nonsense.
    But again, as I said, this is if you are working with REST. If REST
    doesn't fit your application model, don't use it. Just don't name
    things REST when they are really CRUD.
    Why can't CRUD be RESTful?

    In fact my revised plan is to glue together a base REST module and a
    base CRUD module and add the list method discussed somewhere else in
    this thread to provide a complete default RESTful module. Ideally the
    REST base module could be swapped for an RPC style base module to
    easily provide an RPC alternative of the same thing.
    REST and CRUD are not mutually exclusive, but implementations can be.

    When I see things like /book/create, /book/1/edit I see CRUD (or RPC)
    but not REST. REST also doesn't have to be CRUD. I have a REST
    application that is more CR. It just posts immutable records and
    provides findability on those records.

    The discussions about a better CRUD base class with REST and RPC
    adapters is obviously the better (best?) solution, but I also think
    there will be significant disagreement between appropriate URI
    resource conventions (as my exchange with zby is an example of.) I
    haven't had enough time to actually proffer any code, but since this
    is a central focus of my development as late I'm very opinionated in
    these matters :)
    I think that the /foo/{token} vs /foo/id/{token} is the only point of
    contention. And it would definitely be nice if an agreement could be
    reached on this. Indeed, if I do develop this further it would make
    sense if the REST base class is your own
    Catalyst::Controller::REST::DBIC::Item.

    To me the /foo/{token} URI is only acceptable if it is understood that
    no further custom object level URIs can then be added
    (/foo/{token}/disable for example) and that lookup can only ever be by
    {token} rather than {name} or something else. For REST I can see that
    this is possible but I do feel that putting something between the base
    and the token to clearly identify it as object level is generally the
    safest option.

    Peter made a fair point that if you don't like it you can subclass and
    change, but agreeing on a best practice and making that default is
    obviously desirable.
    I just want to be an advocate of standards and not slip into the
    "Internet Explorer Development Methodology". Eventually browsers will
    support this stuff, in the mean time, using strict REST makes
    webservices so much easier.



    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
  • Jay Shirley at May 5, 2008 at 9:29 pm

    On Mon, May 5, 2008 at 1:10 PM, luke saunders wrote:
    On Mon, May 5, 2008 at 6:16 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 9:51 AM, luke saunders wrote:
    On Mon, May 5, 2008 at 5:19 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 8:18 AM, Andrew Rodland wrote:
    On Monday 05 May 2008 09:50:08 am J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path
    component such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be
    there.
    But those nouns you're talking about aren't verbs at all.

    Andrew
    How is /create, /edit or /delete not a verb?
    My argument is separate to the /create is valid in the /foo/{token}
    bit. I'm saying that /foo/create is silly to have in the first place ...
    Okay, let me clear this up. Originally the plan was to have a
    centralised REST-style action which dispatched POST/PUT/GET/DELETE
    requests to the appropriate actions while also providing RPC-style
    verb actions as an alternative for use if the client didn't properly
    support the REST request methods. Having listened to discussion in
    this thread I think it would be better to make the module pure REST
    and then provide the RPC alternative through a subclass, perhaps also
    integrating Catalyst::Request::REST::ForBrowsers into the REST version
    as suggested.

    If you apply actual REST principles, you don't have such nonsense.
    But again, as I said, this is if you are working with REST. If REST
    doesn't fit your application model, don't use it. Just don't name
    things REST when they are really CRUD.
    Why can't CRUD be RESTful?

    In fact my revised plan is to glue together a base REST module and a
    base CRUD module and add the list method discussed somewhere else in
    this thread to provide a complete default RESTful module. Ideally the
    REST base module could be swapped for an RPC style base module to
    easily provide an RPC alternative of the same thing.
    REST and CRUD are not mutually exclusive, but implementations can be.

    When I see things like /book/create, /book/1/edit I see CRUD (or RPC)
    but not REST. REST also doesn't have to be CRUD. I have a REST
    application that is more CR. It just posts immutable records and
    provides findability on those records.

    The discussions about a better CRUD base class with REST and RPC
    adapters is obviously the better (best?) solution, but I also think
    there will be significant disagreement between appropriate URI
    resource conventions (as my exchange with zby is an example of.) I
    haven't had enough time to actually proffer any code, but since this
    is a central focus of my development as late I'm very opinionated in
    these matters :)
    I think that the /foo/{token} vs /foo/id/{token} is the only point of
    contention. And it would definitely be nice if an agreement could be
    reached on this. Indeed, if I do develop this further it would make
    sense if the REST base class is your own
    Catalyst::Controller::REST::DBIC::Item.
    If people are ok with the verbs being in the URL as a sacrifice to
    broken browsers, agreed :)

    I'm going to be rounding out the tests for my work, and I'm giving a
    talk on it at YAPC::Asia. It's mostly just my thoughts on how things
    go, but the work is from a web-services point of view, with some
    browser views. I'll post my slides up (and there may be video fo the
    talk) afterwards.
    To me the /foo/{token} URI is only acceptable if it is understood that
    no further custom object level URIs can then be added
    (/foo/{token}/disable for example) and that lookup can only ever be by
    {token} rather than {name} or something else. For REST I can see that
    this is possible but I do feel that putting something between the base
    and the token to clearly identify it as object level is generally the
    safest option.
    I like to map my URLs out in a definitive hierarchy. If people want
    an implicit create action, a /foo/-/create looks better to me than
    having /foo/create, because I have the level of /foo to be the plural,
    /foo/{id} to be the singular (in a simple CRUD example).
    /foo/-/create is fine, because you can have a rule that "-" is never
    an acceptable record identifier.

    All of this stuff is mostly just standardizing on a set of ideas,
    which leads into your next point:
    Peter made a fair point that if you don't like it you can subclass and
    change, but agreeing on a best practice and making that default is
    obviously desirable.
    Agreed :)

    My vote is hierarchy like:
    /foo
    /{token} # Can be pk1 if you so desire
    /- # - is never acceptable as an identifier
    /create # if you want an empty action here

    Now, I do vote against having an explicit create action, since "POST
    /foo" (or "POST /foo/{token}") seems to be a more reasonable create
    action.

    -J
  • Peter Karman at May 5, 2008 at 9:49 pm

    On 05/05/2008 03:29 PM, J. Shirley wrote:
    My vote is hierarchy like:
    /foo
    /{token} # Can be pk1 if you so desire
    /- # - is never acceptable as an identifier
    /create # if you want an empty action here

    Now, I do vote against having an explicit create action, since "POST
    /foo" (or "POST /foo/{token}") seems to be a more reasonable create
    action.
    fwiw, CX::CRUD::REST uses:

    http://search.cpan.org/~karman/CatalystX-CRUD-0.25/lib/CatalystX/CRUD/REST.pm#SYNOPSIS

    I use 0 (zero) as my reserved PK value since seq PKs start at 1 and zero evaluates as
    false in Perl.

    my ($self, $c, $oid) = @_;
    if (!$oid) {
    # could be absent or zero, either is fine
    # ...
    }

    Also, I adopted drolsky's suggestion of /create_form instead of /create in order to keep
    the RESTful no-verb style URIs.

    --
    Peter Karman . peter@peknet.com . http://peknet.com/
  • Luke saunders at May 5, 2008 at 10:36 pm

    On Mon, May 5, 2008 at 9:29 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 1:10 PM, luke saunders wrote:
    On Mon, May 5, 2008 at 6:16 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 9:51 AM, luke saunders wrote:
    On Mon, May 5, 2008 at 5:19 PM, J. Shirley wrote:
    On Mon, May 5, 2008 at 8:18 AM, Andrew Rodland wrote:
    On Monday 05 May 2008 09:50:08 am J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path
    component such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be
    there.
    But those nouns you're talking about aren't verbs at all.

    Andrew
    How is /create, /edit or /delete not a verb?
    My argument is separate to the /create is valid in the /foo/{token}
    bit. I'm saying that /foo/create is silly to have in the first place ...
    Okay, let me clear this up. Originally the plan was to have a
    centralised REST-style action which dispatched POST/PUT/GET/DELETE
    requests to the appropriate actions while also providing RPC-style
    verb actions as an alternative for use if the client didn't properly
    support the REST request methods. Having listened to discussion in
    this thread I think it would be better to make the module pure REST
    and then provide the RPC alternative through a subclass, perhaps also
    integrating Catalyst::Request::REST::ForBrowsers into the REST version
    as suggested.

    If you apply actual REST principles, you don't have such nonsense.
    But again, as I said, this is if you are working with REST. If REST
    doesn't fit your application model, don't use it. Just don't name
    things REST when they are really CRUD.
    Why can't CRUD be RESTful?

    In fact my revised plan is to glue together a base REST module and a
    base CRUD module and add the list method discussed somewhere else in
    this thread to provide a complete default RESTful module. Ideally the
    REST base module could be swapped for an RPC style base module to
    easily provide an RPC alternative of the same thing.
    REST and CRUD are not mutually exclusive, but implementations can be.

    When I see things like /book/create, /book/1/edit I see CRUD (or RPC)
    but not REST. REST also doesn't have to be CRUD. I have a REST
    application that is more CR. It just posts immutable records and
    provides findability on those records.

    The discussions about a better CRUD base class with REST and RPC
    adapters is obviously the better (best?) solution, but I also think
    there will be significant disagreement between appropriate URI
    resource conventions (as my exchange with zby is an example of.) I
    haven't had enough time to actually proffer any code, but since this
    is a central focus of my development as late I'm very opinionated in
    these matters :)
    I think that the /foo/{token} vs /foo/id/{token} is the only point of
    contention. And it would definitely be nice if an agreement could be
    reached on this. Indeed, if I do develop this further it would make
    sense if the REST base class is your own
    Catalyst::Controller::REST::DBIC::Item.
    If people are ok with the verbs being in the URL as a sacrifice to
    broken browsers, agreed :)
    I think the consensus is probably the opposite. I already agreed that
    the verbs shouldn't be in the REST module but there should be an RPC
    variant.
    I'm going to be rounding out the tests for my work, and I'm giving a
    talk on it at YAPC::Asia. It's mostly just my thoughts on how things
    go, but the work is from a web-services point of view, with some
    browser views. I'll post my slides up (and there may be video fo the
    talk) afterwards.
    Nice.
    To me the /foo/{token} URI is only acceptable if it is understood that
    no further custom object level URIs can then be added
    (/foo/{token}/disable for example) and that lookup can only ever be by
    {token} rather than {name} or something else. For REST I can see that
    this is possible but I do feel that putting something between the base
    and the token to clearly identify it as object level is generally the
    safest option.
    I like to map my URLs out in a definitive hierarchy. If people want
    an implicit create action, a /foo/-/create looks better to me than
    having /foo/create, because I have the level of /foo to be the plural,
    /foo/{id} to be the singular (in a simple CRUD example).
    /foo/-/create is fine, because you can have a rule that "-" is never
    an acceptable record identifier.
    I think that's a pretty reasonable suggestion. It doesn't solve the
    different object lookup methods point, but I think it's reasonable for
    that to justify a subclass.

    However, I do still have a nagging feeling that having /foo/create and
    /foo/-/{token} is preferable because it's easier to not make an action
    with a PathPart of "-" than it is to not have a record whose identifer
    is "-". But I accept that your method would mean that the "-" is only
    seen if you want non-standard methods.
    All of this stuff is mostly just standardizing on a set of ideas,
    which leads into your next point:

    Peter made a fair point that if you don't like it you can subclass and
    change, but agreeing on a best practice and making that default is
    obviously desirable.
    Agreed :)

    My vote is hierarchy like:
    /foo
    /{token} # Can be pk1 if you so desire
    /- # - is never acceptable as an identifier
    /create # if you want an empty action here
    I think that's fine.
    Now, I do vote against having an explicit create action, since "POST
    /foo" (or "POST /foo/{token}") seems to be a more reasonable create
    action.
    Agreed :-)
  • Ashley Pond V at May 5, 2008 at 10:59 pm

    On May 5, 2008, at 2:36 PM, luke saunders wrote:
    I think that's fine.
    Now, I do vote against having an explicit create action, since "POST
    /foo" (or "POST /foo/{token}") seems to be a more reasonable create
    action.
    Agreed :-)

    This doesn't strictly seem REST but I do a find_or_create on these,
    using
    a non-pk, unlikely name field like "__new__", or even an illegal name
    like
    "" (illegal at App level, not Model) so that I don't get a stack of
    unused
    records. Then redirect a GET to the /foo/{created_or_found_token}

    I'd shy away from any implementation where a user (or an agent) could
    just pound away at a POST-point and fill up the DB with useless,
    abandoned records.

    -Ashley
  • Zbigniew Lukasiak at May 6, 2008 at 8:07 am

    On Mon, May 5, 2008 at 11:36 PM, luke saunders wrote:
    To me the /foo/{token} URI is only acceptable if it is understood that
    no further custom object level URIs can then be added
    (/foo/{token}/disable for example) and that lookup can only ever be by
    {token} rather than {name} or something else. For REST I can see that
    this is possible but I do feel that putting something between the base
    and the token to clearly identify it as object level is generally the
    safest option.
    I like to map my URLs out in a definitive hierarchy. If people want
    an implicit create action, a /foo/-/create looks better to me than
    having /foo/create, because I have the level of /foo to be the plural,
    /foo/{id} to be the singular (in a simple CRUD example).
    /foo/-/create is fine, because you can have a rule that "-" is never
    an acceptable record identifier.
    I think that's a pretty reasonable suggestion. It doesn't solve the
    different object lookup methods point, but I think it's reasonable for
    that to justify a subclass.

    However, I do still have a nagging feeling that having /foo/create and
    /foo/-/{token} is preferable because it's easier to not make an action
    with a PathPart of "-" than it is to not have a record whose identifer
    is "-". But I accept that your method would mean that the "-" is only
    seen if you want non-standard methods.
    How about /foo/instance/{token} ? This way it would be clear that
    'foo' is just the name of the object class and that the object for
    REST operations is in /foo/instance/{token}.
  • Matt S Trout at May 5, 2008 at 6:02 pm

    On Mon, May 05, 2008 at 07:50:08AM -0700, J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    On Sun, May 4, 2008 at 8:52 AM, Zbigniew Lukasiak wrote:

    Sorry but I don't understand your point - so maybe first I'll restate
    mine. If you have primary key in the database that is of type varchar
    (or char or ...) then 'create' is a legitimage value for that primary
    key.

    If you just don't like the string 'id' in the URI - then I have not
    any preference to that - it can be /foo/primary_key/ for me.
    My point is that you do not have to use the primary key as the record
    lookup identifier.

    A user has no control over the record lookup identifier (ID) when you
    do things like /user/{primary_key} (or /user/id/{primary_key}, which
    is just converting named params to positional in a weird way). In a
    lot of cases, the record lookup identifier makes more sense to be
    somewhat bound to the user. As an example, lets say registering for a
    web service where you have to have a unique login:
    POST /user/jshirley
    ---
    login: jshirley
    first_name: Jay
    last_name: Shirley
    ...

    Now, it's a simple check here - does /user/jshirley exist? If so,
    reject the request appropriately. If not, create the user at
    /user/jshirley.

    The primary key that the database uses is completely useless to the
    user. /user/1634254 is silly, /user/jshirley is meaningful.
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path component
    such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be there.
    You'd never have a /user/recent or similar URL? I guess if you assume that
    all views onto the collection are done via query parameters, or just
    move that funcationality to /recent-users or similar then it doesn't matter.

    But that's a different sort of uglification of the URL; it doesn't get rid
    of it.

    And it still doesn't help if you want to allow lookup by more than one
    name so far as I can see.

    --
    Matt S Trout Need help with your Catalyst or DBIx::Class project?
    Technical Director http://www.shadowcat.co.uk/catalyst/
    Shadowcat Systems Ltd. Want a managed development or deployment platform?
    http://chainsawblues.vox.com/ http://www.shadowcat.co.uk/servers/
  • Jay Shirley at May 5, 2008 at 6:12 pm

    On Mon, May 5, 2008 at 10:02 AM, Matt S Trout wrote:
    On Mon, May 05, 2008 at 07:50:08AM -0700, J. Shirley wrote:
    On Mon, May 5, 2008 at 4:31 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:06:30AM -0700, J. Shirley wrote:
    On Sun, May 4, 2008 at 8:52 AM, Zbigniew Lukasiak wrote:

    Sorry but I don't understand your point - so maybe first I'll restate
    mine. If you have primary key in the database that is of type varchar
    (or char or ...) then 'create' is a legitimage value for that primary
    key.

    If you just don't like the string 'id' in the URI - then I have not
    any preference to that - it can be /foo/primary_key/ for me.
    My point is that you do not have to use the primary key as the record
    lookup identifier.

    A user has no control over the record lookup identifier (ID) when you
    do things like /user/{primary_key} (or /user/id/{primary_key}, which
    is just converting named params to positional in a weird way). In a
    lot of cases, the record lookup identifier makes more sense to be
    somewhat bound to the user. As an example, lets say registering for a
    web service where you have to have a unique login:
    POST /user/jshirley
    ---
    login: jshirley
    first_name: Jay
    last_name: Shirley
    ...

    Now, it's a simple check here - does /user/jshirley exist? If so,
    reject the request appropriately. If not, create the user at
    /user/jshirley.

    The primary key that the database uses is completely useless to the
    user. /user/1634254 is silly, /user/jshirley is meaningful.
    I fail to see how whether the PK is the lookup key or not has any
    relevance at all to the original point, which was "your lookup key and
    names of actions might clash so it can be nice to have an extra path component
    such as 'id' for the lookup part to disambiguate".
    Because I'm talking about REST and a verb in the URI doesn't need to be there.
    You'd never have a /user/recent or similar URL? I guess if you assume that
    all views onto the collection are done via query parameters, or just
    move that funcationality to /recent-users or similar then it doesn't matter.

    But that's a different sort of uglification of the URL; it doesn't get rid
    of it.

    And it still doesn't help if you want to allow lookup by more than one
    name so far as I can see.
    Search vs. Browse is separate user actions and deserves separate resource space.

    /user implies a single user.
    /users implies browsing.

    So in this hypothetical case I would probably have a top level
    namespace for /browse that had its own hierarchy (since most people
    are going to browse more than just people)
    /browse/users/recent

    But... I also would do /browse/people/recent

    Now you have a better (read-only) browse namespace on your site and it
    descends into a hierarchy appropriately.
  • Luke saunders at May 4, 2008 at 11:09 am

    On Sun, May 4, 2008 at 6:05 AM, J. Shirley wrote:
    On Sat, May 3, 2008 at 9:29 PM, Patrick Donelan wrote:

    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]
    Those URLs don't strike me as very RESTful.

    Patrick
    That is my first impression. My work is an enhancement from
    Catalyst::Action::REST, which is a great module already out on CPAN
    and used by other people (holoway++).

    I'm all for collaboration, but my work is mostly tied to have exposed
    webservices (in addition to a web-browser compatibility layer) via
    REST. By that I mean that I expect, and require, that I can do a PUT
    /api/rest/cd/[cdid], DELETE /api/rest/cd/[CDID]
    Sure, but I have previously had problems getting a browser to send PUT
    requests from JS so separate endpoints were required. In fact the Dojo
    author even said that PUT was a nightmare, use POST (possibly fixed in
    recent Dojo version / browsers). i see no reason why you can't have
    one base action which forwards to the others based on request type so
    that both URL types are exposed.
    On a side note about REST - REST doesn't mean human readable URLs. It
    means representative URLs. The bit about cd/id/{CDID}/ smells like
    named parameters going into positional parameters. What is the real
    difference between cd?id={CDID}&action=delete, aside from different
    characters? Where as with REST, /cd/{id} is a unique identifier for
    that object and hence a full representation.
    I find having the id in the path to be a clearer distinction between
    object level operations and class level operations. It's the
    difference between object and all objects.
    You can catch me on IRC next week, as I'm actively working on this for
    $work and it's getting real dev time (finally). My work is
    functionally complete, but lacking test cases; it is just a refactor
    of existing code in production.
    So you don't want to automate any actual operations? In which case if
    anything my module could subclass yours.
  • Aristotle Pagaltzis at May 4, 2008 at 8:10 am

    * luke saunders [2008-05-04 02:50]:
    Also it doesn't distinguish between POST, PUT, DELETE and GET
    HTTP requests favouring instead entirely separate endpoints,
    but that's up for discussion.
    Putting the verb in the URI is RPC, not REST. This is not a
    matter of discussion.

    Regards,
    --
    Aristotle Pagaltzis // <http://plasmasturm.org/>
  • Matt S Trout at May 4, 2008 at 3:15 pm

    On Sun, May 04, 2008 at 09:10:56AM +0200, Aristotle Pagaltzis wrote:
    * luke saunders [2008-05-04 02:50]:
    Also it doesn't distinguish between POST, PUT, DELETE and GET
    HTTP requests favouring instead entirely separate endpoints,
    but that's up for discussion.
    Putting the verb in the URI is RPC, not REST. This is not a
    matter of discussion.
    No, but how you provide an alternative to full RESTness for clients that
    don't handle the full range of HTTP verbs -is- a matter for discussion.

    Or at least a matter for determining an architecture that allows you to
    use whatever alternative you like.

    Please don't let your obsessive REST advocacy blind you to pragmatic
    software development issues; it's starting to get boring.

    --
    Matt S Trout Need help with your Catalyst or DBIx::Class project?
    Technical Director http://www.shadowcat.co.uk/catalyst/
    Shadowcat Systems Ltd. Want a managed development or deployment platform?
    http://chainsawblues.vox.com/ http://www.shadowcat.co.uk/servers/
  • Jay Shirley at May 4, 2008 at 3:58 pm

    On Sun, May 4, 2008 at 7:15 AM, Matt S Trout wrote:
    On Sun, May 04, 2008 at 09:10:56AM +0200, Aristotle Pagaltzis wrote:
    * luke saunders [2008-05-04 02:50]:
    Also it doesn't distinguish between POST, PUT, DELETE and GET
    HTTP requests favouring instead entirely separate endpoints,
    but that's up for discussion.
    Putting the verb in the URI is RPC, not REST. This is not a
    matter of discussion.
    No, but how you provide an alternative to full RESTness for clients that
    don't handle the full range of HTTP verbs -is- a matter for discussion.

    Or at least a matter for determining an architecture that allows you to
    use whatever alternative you like.

    Please don't let your obsessive REST advocacy blind you to pragmatic
    software development issues; it's starting to get boring.
    Naming things REST when they aren't confuses the namespace and further
    propagates the confusion about what REST actually is. Call it
    something else and do everybody who actually tries to build RESTful
    apps a favor. Trying to argue in favor of naming something that isn't
    REST in any way REST does a disservice to the world. And kills
    puppies, deprives worthy little girls of ponies, elects
    neoconservatives to office and, quite possibly, lights a bag of
    excrement on your porch then ringing your doorbell and running.

    And, on a more topical note, my method for having actual REST and then
    a dumbed down browser version is similar to jrockway's suggestion
    about dispatch methods. My approach is a set of very thin actions
    that exist outside of the main API space (or, what I've been playing
    around with is a more adaptive interface based on what Dave Rolsky is
    working on: http://search.cpan.org/~drolsky/Catalyst-Request-REST-ForBrowsers-0.01/lib/Catalyst/Request/REST/ForBrowsers.pm).
    They really end up just being a sort of internal API to the base web
    service. This also addresses the id == primary key issue, because in
    your front-end browser-facing scheme, you have /book/id/{primary key},
    which maps to /book/{unique identifier}.
  • Patrick Donelan at May 5, 2008 at 1:20 am

    No, but how you provide an alternative to full RESTness for clients that
    don't handle the full range of HTTP verbs -is- a matter for discussion.
    Which clients are we talking about here? I did a quick google search and
    could only find an off-hand remark along the lines of "in 2006 safari had
    poor support for REST verbs". I'm interested because in my own personal
    experience I haven't run into any problems generating PUT/POST/GET/DELETE
    with IE/FF/Opera browsers. Or are you talking about the inability to specify
    anything other than GET or POST as a form method?

    Patrick
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20080505/899fa397/attachment.htm
  • Luke saunders at May 5, 2008 at 10:46 am

    On Mon, May 5, 2008 at 1:20 AM, Patrick Donelan wrote:
    No, but how you provide an alternative to full RESTness for clients that
    don't handle the full range of HTTP verbs -is- a matter for discussion.
    Which clients are we talking about here? I did a quick google search and
    could only find an off-hand remark along the lines of "in 2006 safari had
    poor support for REST verbs". I'm interested because in my own personal
    experience I haven't run into any problems generating PUT/POST/GET/DELETE
    with IE/FF/Opera browsers. Or are you talking about the inability to specify
    anything other than GET or POST as a form method?
    I'm afraid I can't remember exactly, it was around two years ago and
    we needed to fire PUT requests using XHR in JS using Dojo and it just
    wasn't happening. Dojo has changed dramatically since then and now has
    an xhrPut method so I expect whatever the problem has been addressed.
  • Matt S Trout at May 5, 2008 at 12:34 pm

    On Mon, May 05, 2008 at 10:46:56AM +0100, luke saunders wrote:
    On Mon, May 5, 2008 at 1:20 AM, Patrick Donelan wrote:

    No, but how you provide an alternative to full RESTness for clients that
    don't handle the full range of HTTP verbs -is- a matter for discussion.
    Which clients are we talking about here? I did a quick google search and
    could only find an off-hand remark along the lines of "in 2006 safari had
    poor support for REST verbs". I'm interested because in my own personal
    experience I haven't run into any problems generating PUT/POST/GET/DELETE
    with IE/FF/Opera browsers. Or are you talking about the inability to specify
    anything other than GET or POST as a form method?
    I'm afraid I can't remember exactly, it was around two years ago and
    we needed to fire PUT requests using XHR in JS using Dojo and it just
    wasn't happening. Dojo has changed dramatically since then and now has
    an xhrPut method so I expect whatever the problem has been addressed.
    Doubt it.

    The problem was the browsers gleefully threw out half the headers we were
    trying to send when we used a PUT request. Fuck all dojo can do about that
    so far as I can see.

    Of course I forget which browsers and which headers, but it sure as hell
    fucked our shit up but good.

    --
    Matt S Trout Need help with your Catalyst or DBIx::Class project?
    Technical Director http://www.shadowcat.co.uk/catalyst/
    Shadowcat Systems Ltd. Want a managed development or deployment platform?
    http://chainsawblues.vox.com/ http://www.shadowcat.co.uk/servers/
  • Patrick Donelan at May 6, 2008 at 2:16 am
    The only header I've found you can't always set via xhr.setRequestHeader()
    is WWW-Authenticate because the browser thinks it should be responsible for
    HTTP Authentication. Which is why the last 2 optional arguments to
    xhr.open() are username and password, to effectively let you set these
    headers (it does the base64 encoding for you too which is handy).

    If anyone manages to remember any specific browser limitations or can find
    any references please let me know since it would be important for any
    RESTful design.

    Patrick
    On Mon, May 5, 2008 at 9:34 PM, Matt S Trout wrote:
    On Mon, May 05, 2008 at 10:46:56AM +0100, luke saunders wrote:
    On Mon, May 5, 2008 at 1:20 AM, Patrick Donelan wrote:

    No, but how you provide an alternative to full RESTness for clients
    that
    don't handle the full range of HTTP verbs -is- a matter for
    discussion.
    Which clients are we talking about here? I did a quick google search
    and
    could only find an off-hand remark along the lines of "in 2006 safari
    had
    poor support for REST verbs". I'm interested because in my own
    personal
    experience I haven't run into any problems generating
    PUT/POST/GET/DELETE
    with IE/FF/Opera browsers. Or are you talking about the inability to
    specify
    anything other than GET or POST as a form method?
    I'm afraid I can't remember exactly, it was around two years ago and
    we needed to fire PUT requests using XHR in JS using Dojo and it just
    wasn't happening. Dojo has changed dramatically since then and now has
    an xhrPut method so I expect whatever the problem has been addressed.
    Doubt it.

    The problem was the browsers gleefully threw out half the headers we were
    trying to send when we used a PUT request. Fuck all dojo can do about that
    so far as I can see.

    Of course I forget which browsers and which headers, but it sure as hell
    fucked our shit up but good.

    --
    Matt S Trout Need help with your Catalyst or DBIx::Class
    project?
    Technical Director
    http://www.shadowcat.co.uk/catalyst/
    Shadowcat Systems Ltd. Want a managed development or deployment
    platform?
    http://chainsawblues.vox.com/
    http://www.shadowcat.co.uk/servers/

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive:
    http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20080506/8e2eca84/attachment.htm
  • Aristotle Pagaltzis at May 5, 2008 at 10:29 am

    * Matt S Trout [2008-05-04 16:25]:
    On Sun, May 04, 2008 at 09:10:56AM +0200, Aristotle Pagaltzis wrote:
    * luke saunders [2008-05-04 02:50]:
    Also it doesn't distinguish between POST, PUT, DELETE and
    GET HTTP requests favouring instead entirely separate
    endpoints, but that's up for discussion.
    Putting the verb in the URI is RPC, not REST. This is not a
    matter of discussion.
    No, but how you provide an alternative to full RESTness for
    clients that don't handle the full range of HTTP verbs -is- a
    matter for discussion.

    Or at least a matter for determining an architecture that
    allows you to use whatever alternative you like.

    Please don't let your obsessive REST advocacy blind you to
    pragmatic software development issues; it's starting to get
    boring.
    You are reading things into my post that aren?t there. I made a
    statement of fact about what REST is; there was no advocacy
    either way in it.

    Still, since you mention pragmatism, let me point out that I do
    not consider purely RESTful design an an ivory-tower pursuit; it
    has practical benefits, and if you understand what REST is and
    don?t dismiss the idea of complying with it out of hand, it?s not
    hard to come up with workarounds for limited clients, such as the
    excellent Catalyst::Request::REST::ForBrowsers.

    I have been thinking about changes I?d like to propose to
    Catalyst::Action::REST to make it less verbose in some
    circumstances, and I have some half-baked ideas regarding
    emulation of HTTP Auth using cookies. When I?m done I want to tie
    all this together by way of a controller base class. If anyone is
    thinking along the same lines, I shall be happy to talk in
    private, but before I run my mouth off too much in public I want
    to have code to show.

    None of this, btw, is specific to a CRUD interface, but could be
    a great foundation to build one with.

    Regards,
    --
    Aristotle Pagaltzis // <http://plasmasturm.org/>
  • Zbigniew Lukasiak at May 4, 2008 at 10:20 am

    On Sun, May 4, 2008 at 2:38 AM, luke saunders wrote:
    I have started to write a Catalyst base controller for REST style CRUD
    via DBIC. I have noticed that a number of other people have been
    working on or are thinking about working on something similar, most
    notabley J. Shirley who seems to be creating
    Catalyst::Controller::REST::DBIC::Item
    (http://dev.catalystframework.org/svnweb/Catalyst/browse/Catalyst-Controller-REST-DBIC-Item/)
    and some chaps from a recent thread on this list (entitled
    "Dispatching with Chained vs HTTP method").

    Ideally I would like to merge J. Shirley's effort into mine (or visa
    versa) along with anything that anyone else has. Basically I want to
    avoid ending up with a load of modules that all do the same thing.

    My effort is heavily based on something mst wrote a while ago, and
    since then I've ended up writing something very similar for every
    project I've worked on which indicates it's worth OSing. Essentially
    it is used like so:

    package MyApp::Controller::API::REST::CD;

    use base qw/Catalyst::Controller::REST::DBIC/;

    ...

    __PACKAGE__->config
    ( action => { setup => { PathPart => 'cd', Chained =>
    '/api/rest/rest_base' } },
    class => 'RestTestDB::CD',
    create_requires => ['artist', 'title', 'year' ],
    update_allows => ['title', 'year']
    );

    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]

    The full source is here:
    http://lukesaunders.me.uk/dists/Catalyst-Controller-REST-DBIC-1.000000.tar.gz

    If you have a few moments please have a look, especially if you are
    working on something similar. Today I even wrote a test suite which
    has a test app and is probably the best place to look to see what it
    does.
    I've been planning for a more REST-like update to InstantCRUD for a
    long time. My approach is a bit different because for validation and
    for generating form's HTML I use HTML::Widget. I believe validation
    is important and separate enough to have a separate package (and I
    don't want to reinvent the wheel - so I use what is available at
    CPAN). I also choose to generate the HTML - because I believe there
    is too much logic (classes for errors, options from the database,
    subforms from the database - see below) in it for the simplistic
    Template::Toolkit language - an elegant solution for that could be
    also a TT plugin.

    Now I am working on porting Instant to use Rose::HTML::Form instead of
    HTML::Wiget - it will give it much more solid base.

    One more difference in my approach is that the 'update' action will be
    able to edit not just one row from the DB - but all the interrelated
    records that together make a full object. This means also adding and
    removing the related records - so I'll not have the add_to_rel
    remove_from_rel actions.

    There is also an effort by Peter Carman:
    http://search.cpan.org/~karman/CatalystX-CRUD-0.25/lib/CatalystX/CRUD/REST.pm
    - and I more or less agreed with Peter on some basics - so that
    hopefully our code will be compatible and maybe even will form
    together just one solution.

    Finally I am waiting for the Moose port of Catalyst - so that all the
    CRUD functionality could be just a Role instead of forcing the user to
    'use base'.
    Note that it lacks:
    - list and view type methods which dump objects to JSON (or whatever)
    - clever validation - it should validate based on the DBIC column
    definitions but it doesn't
    - any auth - not sure if it should or not, but it's possible

    Also it doesn't distinguish between POST, PUT, DELETE and GET HTTP
    requests favouring instead entirely separate endpoints, but that's up
    for discussion.

    So, J. Shirley, do you have any interest in a merge? And others, do
    you have ideas and would you like to contribute?

    Thanks,
    Luke.

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Zbigniew Lukasiak
    http://brudnopis.blogspot.com/
  • Luke saunders at May 4, 2008 at 11:23 am

    On Sun, May 4, 2008 at 10:20 AM, Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 2:38 AM, luke saunders wrote:
    I have started to write a Catalyst base controller for REST style CRUD
    via DBIC. I have noticed that a number of other people have been
    working on or are thinking about working on something similar, most
    notabley J. Shirley who seems to be creating
    Catalyst::Controller::REST::DBIC::Item
    (http://dev.catalystframework.org/svnweb/Catalyst/browse/Catalyst-Controller-REST-DBIC-Item/)
    and some chaps from a recent thread on this list (entitled
    "Dispatching with Chained vs HTTP method").

    Ideally I would like to merge J. Shirley's effort into mine (or visa
    versa) along with anything that anyone else has. Basically I want to
    avoid ending up with a load of modules that all do the same thing.

    My effort is heavily based on something mst wrote a while ago, and
    since then I've ended up writing something very similar for every
    project I've worked on which indicates it's worth OSing. Essentially
    it is used like so:

    package MyApp::Controller::API::REST::CD;

    use base qw/Catalyst::Controller::REST::DBIC/;

    ...

    __PACKAGE__->config
    ( action => { setup => { PathPart => 'cd', Chained =>
    '/api/rest/rest_base' } },
    class => 'RestTestDB::CD',
    create_requires => ['artist', 'title', 'year' ],
    update_allows => ['title', 'year']
    );

    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]

    The full source is here:
    http://lukesaunders.me.uk/dists/Catalyst-Controller-REST-DBIC-1.000000.tar.gz

    If you have a few moments please have a look, especially if you are
    working on something similar. Today I even wrote a test suite which
    has a test app and is probably the best place to look to see what it
    does.
    I've been planning for a more REST-like update to InstantCRUD for a
    long time. My approach is a bit different because for validation and
    for generating form's HTML I use HTML::Widget. I believe validation
    is important and separate enough to have a separate package (and I
    don't want to reinvent the wheel - so I use what is available at
    CPAN). I also choose to generate the HTML - because I believe there
    is too much logic (classes for errors, options from the database,
    subforms from the database - see below) in it for the simplistic
    Template::Toolkit language - an elegant solution for that could be
    also a TT plugin.

    Now I am working on porting Instant to use Rose::HTML::Form instead of
    HTML::Wiget - it will give it much more solid base.
    I thinking generating the form is a step too far for this sort of
    thing, normally I just want the API. In some cases I'll be generating
    the form HTML with Jemplate for example.
    One more difference in my approach is that the 'update' action will be
    able to edit not just one row from the DB - but all the interrelated
    records that together make a full object. This means also adding and
    removing the related records - so I'll not have the add_to_rel
    remove_from_rel actions.
    Interesting. How are you representing the related objects in the request?
    There is also an effort by Peter Carman:
    http://search.cpan.org/~karman/CatalystX-CRUD-0.25/lib/CatalystX/CRUD/REST.pm
    - and I more or less agreed with Peter on some basics - so that
    hopefully our code will be compatible and maybe even will form
    together just one solution.

    Finally I am waiting for the Moose port of Catalyst - so that all the
    CRUD functionality could be just a Role instead of forcing the user to
    'use base'.

    Note that it lacks:
    - list and view type methods which dump objects to JSON (or whatever)
    - clever validation - it should validate based on the DBIC column
    definitions but it doesn't
    - any auth - not sure if it should or not, but it's possible

    Also it doesn't distinguish between POST, PUT, DELETE and GET HTTP
    requests favouring instead entirely separate endpoints, but that's up
    for discussion.

    So, J. Shirley, do you have any interest in a merge? And others, do
    you have ideas and would you like to contribute?

    Thanks,
    Luke.
    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Zbigniew Lukasiak
    http://brudnopis.blogspot.com/

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
  • Zbigniew Lukasiak at May 4, 2008 at 11:58 am

    On Sun, May 4, 2008 at 12:23 PM, luke saunders wrote:
    On Sun, May 4, 2008 at 10:20 AM, Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 2:38 AM, luke saunders wrote:
    I have started to write a Catalyst base controller for REST style CRUD
    via DBIC. I have noticed that a number of other people have been
    working on or are thinking about working on something similar, most
    notabley J. Shirley who seems to be creating
    Catalyst::Controller::REST::DBIC::Item
    (http://dev.catalystframework.org/svnweb/Catalyst/browse/Catalyst-Controller-REST-DBIC-Item/)
    and some chaps from a recent thread on this list (entitled
    "Dispatching with Chained vs HTTP method").

    Ideally I would like to merge J. Shirley's effort into mine (or visa
    versa) along with anything that anyone else has. Basically I want to
    avoid ending up with a load of modules that all do the same thing.

    My effort is heavily based on something mst wrote a while ago, and
    since then I've ended up writing something very similar for every
    project I've worked on which indicates it's worth OSing. Essentially
    it is used like so:

    package MyApp::Controller::API::REST::CD;

    use base qw/Catalyst::Controller::REST::DBIC/;

    ...

    __PACKAGE__->config
    ( action => { setup => { PathPart => 'cd', Chained =>
    '/api/rest/rest_base' } },
    class => 'RestTestDB::CD',
    create_requires => ['artist', 'title', 'year' ],
    update_allows => ['title', 'year']
    );

    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]

    The full source is here:
    http://lukesaunders.me.uk/dists/Catalyst-Controller-REST-DBIC-1.000000.tar.gz

    If you have a few moments please have a look, especially if you are
    working on something similar. Today I even wrote a test suite which
    has a test app and is probably the best place to look to see what it
    does.
    I've been planning for a more REST-like update to InstantCRUD for a
    long time. My approach is a bit different because for validation and
    for generating form's HTML I use HTML::Widget. I believe validation
    is important and separate enough to have a separate package (and I
    don't want to reinvent the wheel - so I use what is available at
    CPAN). I also choose to generate the HTML - because I believe there
    is too much logic (classes for errors, options from the database,
    subforms from the database - see below) in it for the simplistic
    Template::Toolkit language - an elegant solution for that could be
    also a TT plugin.

    Now I am working on porting Instant to use Rose::HTML::Form instead of
    HTML::Wiget - it will give it much more solid base.
    I thinking generating the form is a step too far for this sort of
    thing, normally I just want the API. In some cases I'll be generating
    the form HTML with Jemplate for example.
    I think we can still make it compatible, if we agree on some kind of
    internal API.
    One more difference in my approach is that the 'update' action will be
    able to edit not just one row from the DB - but all the interrelated
    records that together make a full object. This means also adding and
    removing the related records - so I'll not have the add_to_rel
    remove_from_rel actions.
    Interesting. How are you representing the related objects in the request?
    It is I think quite common convention to use '.' dot for that:

    param1.some_relation.field_value

    or

    some_param.some_multi_relation.1.field_value
    There is also an effort by Peter Carman:
    http://search.cpan.org/~karman/CatalystX-CRUD-0.25/lib/CatalystX/CRUD/REST.pm
    - and I more or less agreed with Peter on some basics - so that
    hopefully our code will be compatible and maybe even will form
    together just one solution.

    Finally I am waiting for the Moose port of Catalyst - so that all the
    CRUD functionality could be just a Role instead of forcing the user to
    'use base'.

    Note that it lacks:
    - list and view type methods which dump objects to JSON (or whatever)
    - clever validation - it should validate based on the DBIC column
    definitions but it doesn't
    - any auth - not sure if it should or not, but it's possible

    Also it doesn't distinguish between POST, PUT, DELETE and GET HTTP
    requests favouring instead entirely separate endpoints, but that's up
    for discussion.

    So, J. Shirley, do you have any interest in a merge? And others, do
    you have ideas and would you like to contribute?

    Thanks,
    Luke.
    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Zbigniew Lukasiak
    http://brudnopis.blogspot.com/

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Zbigniew Lukasiak
    http://brudnopis.blogspot.com/
  • Luke saunders at May 4, 2008 at 12:28 pm

    On Sun, May 4, 2008 at 11:58 AM, Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 12:23 PM, luke saunders wrote:
    On Sun, May 4, 2008 at 10:20 AM, Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 2:38 AM, luke saunders wrote:
    I have started to write a Catalyst base controller for REST style CRUD
    via DBIC. I have noticed that a number of other people have been
    working on or are thinking about working on something similar, most
    notabley J. Shirley who seems to be creating
    Catalyst::Controller::REST::DBIC::Item
    (http://dev.catalystframework.org/svnweb/Catalyst/browse/Catalyst-Controller-REST-DBIC-Item/)
    and some chaps from a recent thread on this list (entitled
    "Dispatching with Chained vs HTTP method").

    Ideally I would like to merge J. Shirley's effort into mine (or visa
    versa) along with anything that anyone else has. Basically I want to
    avoid ending up with a load of modules that all do the same thing.

    My effort is heavily based on something mst wrote a while ago, and
    since then I've ended up writing something very similar for every
    project I've worked on which indicates it's worth OSing. Essentially
    it is used like so:

    package MyApp::Controller::API::REST::CD;

    use base qw/Catalyst::Controller::REST::DBIC/;

    ...

    __PACKAGE__->config
    ( action => { setup => { PathPart => 'cd', Chained =>
    '/api/rest/rest_base' } },
    class => 'RestTestDB::CD',
    create_requires => ['artist', 'title', 'year' ],
    update_allows => ['title', 'year']
    );

    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]

    The full source is here:
    http://lukesaunders.me.uk/dists/Catalyst-Controller-REST-DBIC-1.000000.tar.gz

    If you have a few moments please have a look, especially if you are
    working on something similar. Today I even wrote a test suite which
    has a test app and is probably the best place to look to see what it
    does.
    I've been planning for a more REST-like update to InstantCRUD for a
    long time. My approach is a bit different because for validation and
    for generating form's HTML I use HTML::Widget. I believe validation
    is important and separate enough to have a separate package (and I
    don't want to reinvent the wheel - so I use what is available at
    CPAN). I also choose to generate the HTML - because I believe there
    is too much logic (classes for errors, options from the database,
    subforms from the database - see below) in it for the simplistic
    Template::Toolkit language - an elegant solution for that could be
    also a TT plugin.

    Now I am working on porting Instant to use Rose::HTML::Form instead of
    HTML::Wiget - it will give it much more solid base.
    I thinking generating the form is a step too far for this sort of
    thing, normally I just want the API. In some cases I'll be generating
    the form HTML with Jemplate for example.
    I think we can still make it compatible, if we agree on some kind of
    internal API.
    As in make this module compatible with your new module? Perhaps as a
    base class without form generation?
    One more difference in my approach is that the 'update' action will be
    able to edit not just one row from the DB - but all the interrelated
    records that together make a full object. This means also adding and
    removing the related records - so I'll not have the add_to_rel
    remove_from_rel actions.
    Interesting. How are you representing the related objects in the request?
    It is I think quite common convention to use '.' dot for that:

    param1.some_relation.field_value

    or

    some_param.some_multi_relation.1.field_value
    Makes sense. I prefer that to the add_to_rel action, especially if
    this is to remain a REST module rather than an RPC module.

    The piece of functionality I always wanted but didn't see a clean
    solution to was specifying complex conditions to the 'list' action,
    for example only CDs which have a track called 'Badgers', which
    requires specifying a join and a related condition. I wonder if it
    makes sense to represent that this way too.
    There is also an effort by Peter Carman:
    http://search.cpan.org/~karman/CatalystX-CRUD-0.25/lib/CatalystX/CRUD/REST.pm
    - and I more or less agreed with Peter on some basics - so that
    hopefully our code will be compatible and maybe even will form
    together just one solution.

    Finally I am waiting for the Moose port of Catalyst - so that all the
    CRUD functionality could be just a Role instead of forcing the user to
    'use base'.

    Note that it lacks:
    - list and view type methods which dump objects to JSON (or whatever)
    - clever validation - it should validate based on the DBIC column
    definitions but it doesn't
    - any auth - not sure if it should or not, but it's possible

    Also it doesn't distinguish between POST, PUT, DELETE and GET HTTP
    requests favouring instead entirely separate endpoints, but that's up
    for discussion.

    So, J. Shirley, do you have any interest in a merge? And others, do
    you have ideas and would you like to contribute?

    Thanks,
    Luke.
    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Zbigniew Lukasiak
    http://brudnopis.blogspot.com/

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Zbigniew Lukasiak
    http://brudnopis.blogspot.com/

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
  • Zbigniew Lukasiak at May 4, 2008 at 2:12 pm

    On Sun, May 4, 2008 at 1:28 PM, luke saunders wrote:

    I think we can still make it compatible, if we agree on some kind of
    internal API.
    As in make this module compatible with your new module? Perhaps as a
    base class without form generation?
    Yes - I am thinking about something where you have a separate methods
    for validating the parameters and updating/creating the object in the
    database - so that I could override them in my sub-class.
    It is I think quite common convention to use '.' dot for that:

    param1.some_relation.field_value

    or

    some_param.some_multi_relation.1.field_value
    Makes sense. I prefer that to the add_to_rel action, especially if
    this is to remain a REST module rather than an RPC module.
    It does not bother me if you leave those actions.
    The piece of functionality I always wanted but didn't see a clean
    solution to was specifying complex conditions to the 'list' action,
    for example only CDs which have a track called 'Badgers', which
    requires specifying a join and a related condition. I wonder if it
    makes sense to represent that this way too.
    Well - this is in my plans as well - as search in InstantCRUD :) I am
    thinking to base it on the technique I described in my Advent article:
    http://catalyst.perl.org/calendar/2007/16
  • Luke saunders at May 4, 2008 at 5:20 pm

    On Sun, May 4, 2008 at 2:12 PM, Zbigniew Lukasiak wrote:
    On Sun, May 4, 2008 at 1:28 PM, luke saunders wrote:

    I think we can still make it compatible, if we agree on some kind of
    internal API.
    As in make this module compatible with your new module? Perhaps as a
    base class without form generation?
    Yes - I am thinking about something where you have a separate methods
    for validating the parameters and updating/creating the object in the
    database - so that I could override them in my sub-class.
    Yeah, sure. I think the module will provide validation for column
    types and FK validation, but you can override that if you wish.
    It is I think quite common convention to use '.' dot for that:

    param1.some_relation.field_value

    or

    some_param.some_multi_relation.1.field_value
    Makes sense. I prefer that to the add_to_rel action, especially if
    this is to remain a REST module rather than an RPC module.
    It does not bother me if you leave those actions.
    I might leave them as private actions but if I leave them as public in
    the REST version I'm going to get shot.
    The piece of functionality I always wanted but didn't see a clean
    solution to was specifying complex conditions to the 'list' action,
    for example only CDs which have a track called 'Badgers', which
    requires specifying a join and a related condition. I wonder if it
    makes sense to represent that this way too.
    Well - this is in my plans as well - as search in InstantCRUD :) I am
    thinking to base it on the technique I described in my Advent article:
    http://catalyst.perl.org/calendar/2007/16
    I read your article and it looks ideal, though as you say some method
    for ordering would be required, probably via some special case query
    param.

    Ideally I'd wait for you to implement something along these lines then
    if you wouldn't mind, pull the general parts upstream.
    --


    Zbigniew Lukasiak
    http://brudnopis.blogspot.com/

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
  • Jonathan Rockway at May 4, 2008 at 2:18 pm

    * On Sat, May 03 2008, luke saunders wrote:
    __PACKAGE__->config
    ( action => { setup => { PathPart => 'cd', Chained =>
    '/api/rest/rest_base' } },
    class => 'RestTestDB::CD',
    create_requires => ['artist', 'title', 'year' ],
    update_allows => ['title', 'year']
    );

    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]
    This is RPC, not REST. Not that there's anything wrong with that.

    It sounds like what you want to write is a Controller that proxies class
    methods to a URI. For example, you write a class like this:

    package Foo;

    sub create { my ($class, $username, $password) = @_; ... }
    sub delete { my $self = shift; $self->delete }
    sub foo { my ($self, $quux, $value_for_42) = @_; ... }

    sub fetch_existing { my ($class, $id) = @_ }

    ...
    1;

    Then you write a controller like this:

    package MyApp::Controller::Foo;
    use base 'The::Thing::You're::Writing';

    __PACKAGE__->config(
    class => 'Foo',
    fetch_existing => 'fetch_existing',
    new_instance => 'create',
    methods => {
    create => ['username', 'password'],
    delete => [],
    foo => ['quux', '42'],
    },
    );
    1;

    Then you have actions like:

    /foo//create/<username>/<password>
    /foo/<id>
    /foo/<id>/foo/<quux>/<value for 42>
    /foo/<id>/delete

    In your configuration, an option would be available to REST-ify certain
    parts of the RPC interface:

    rest => {
    create => 'create',
    get => 'fetch_existing',
    delete => 'delete',
    update => 'update',
    }

    Then you would have the /foo and /foo/<id> REST endpoints do the same
    thing as the RPC calls.

    Anyway, making this specific to DBIx::Class sounds like a waste of time.

    Regards,
    Jonathan Rockway

    --
    print just => another => perl => hacker => if $,=$"
  • Luke saunders at May 4, 2008 at 2:58 pm

    On Sun, May 4, 2008 at 2:18 PM, Jonathan Rockway wrote:
    * On Sat, May 03 2008, luke saunders wrote:
    __PACKAGE__->config
    ( action => { setup => { PathPart => 'cd', Chained =>
    '/api/rest/rest_base' } },
    class => 'RestTestDB::CD',
    create_requires => ['artist', 'title', 'year' ],
    update_allows => ['title', 'year']
    );

    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]
    This is RPC, not REST. Not that there's anything wrong with that.

    It sounds like what you want to write is a Controller that proxies class
    methods to a URI. For example, you write a class like this:

    package Foo;

    sub create { my ($class, $username, $password) = @_; ... }
    sub delete { my $self = shift; $self->delete }
    sub foo { my ($self, $quux, $value_for_42) = @_; ... }

    sub fetch_existing { my ($class, $id) = @_ }

    ...
    1;

    Then you write a controller like this:

    package MyApp::Controller::Foo;
    use base 'The::Thing::You're::Writing';

    __PACKAGE__->config(
    class => 'Foo',
    fetch_existing => 'fetch_existing',
    new_instance => 'create',
    methods => {
    create => ['username', 'password'],
    delete => [],
    foo => ['quux', '42'],
    },
    );
    1;

    Then you have actions like:

    /foo//create/<username>/<password>
    /foo/<id>
    /foo/<id>/foo/<quux>/<value for 42>
    /foo/<id>/delete

    In your configuration, an option would be available to REST-ify certain
    parts of the RPC interface:

    rest => {
    create => 'create',
    get => 'fetch_existing',
    delete => 'delete',
    update => 'update',
    }

    Then you would have the /foo and /foo/<id> REST endpoints do the same
    thing as the RPC calls.
    I think I'd prefer to use query parameters like I already do rather
    than having them in the URI. In fact what I think I should do is leave
    the module as it is but make the verb actions private and write the
    base action to distribute based on request type so it can be called
    REST. Then, because REST isn't always ideal, create a very slim
    subclass which gives the Private methods URIs and call this the RPC
    version.
    Anyway, making this specific to DBIx::Class sounds like a waste of time.
    Yes, ideally the general parts would be put in a non-DBIC specific
    base controller which $whatever can plug into.

    However, a DBIC specific module will allow the bulk of the validation
    to be done automatically based on column definitions, foreign keys
    etc. Also, a powerful list method can be implemented which allows for
    complex search conditions via $rs->search for retrieving a subset of
    objects, related rows and so forth. I think stuff like this has to be
    DBIC specific.
    Regards,
    Jonathan Rockway

    --
    print just => another => perl => hacker => if $,=$"



    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
  • Zbigniew Lukasiak at May 15, 2008 at 9:13 am
    Hi there,

    This is a frequently recurring conversation - so I created a wiki page
    to gather all the points where we reached some consensus:
    http://catwiki.toeat.com/crud. For the start I just dumped my
    opinions. I tried to be not controversial - but it is a wiki - if you
    don't agree then you can edit it and make it more acceptable for you.

    I am especially waiting for people with opinions on the REST and
    browser REST part - I have got much knowledge in that area.

    Cheers,
    Zbigniew
    On Sun, May 4, 2008 at 2:38 AM, luke saunders wrote:
    I have started to write a Catalyst base controller for REST style CRUD
    via DBIC. I have noticed that a number of other people have been
    working on or are thinking about working on something similar, most
    notabley J. Shirley who seems to be creating
    Catalyst::Controller::REST::DBIC::Item
    (http://dev.catalystframework.org/svnweb/Catalyst/browse/Catalyst-Controller-REST-DBIC-Item/)
    and some chaps from a recent thread on this list (entitled
    "Dispatching with Chained vs HTTP method").

    Ideally I would like to merge J. Shirley's effort into mine (or visa
    versa) along with anything that anyone else has. Basically I want to
    avoid ending up with a load of modules that all do the same thing.

    My effort is heavily based on something mst wrote a while ago, and
    since then I've ended up writing something very similar for every
    project I've worked on which indicates it's worth OSing. Essentially
    it is used like so:

    package MyApp::Controller::API::REST::CD;

    use base qw/Catalyst::Controller::REST::DBIC/;

    ...

    __PACKAGE__->config
    ( action => { setup => { PathPart => 'cd', Chained =>
    '/api/rest/rest_base' } },
    class => 'RestTestDB::CD',
    create_requires => ['artist', 'title', 'year' ],
    update_allows => ['title', 'year']
    );

    And this gets you the following endpoints to fire requests at:
    /api/rest/cd/create
    /api/rest/cd/id/[cdid]/update
    /api/rest/cd/id/[cdid]/delete
    /api/rest/cd/id/[cdid]/add_to_rel/[relation]
    /api/rest/cd/id/[cdid]/remove_from_rel/[relation]

    The full source is here:
    http://lukesaunders.me.uk/dists/Catalyst-Controller-REST-DBIC-1.000000.tar.gz

    If you have a few moments please have a look, especially if you are
    working on something similar. Today I even wrote a test suite which
    has a test app and is probably the best place to look to see what it
    does.

    Note that it lacks:
    - list and view type methods which dump objects to JSON (or whatever)
    - clever validation - it should validate based on the DBIC column
    definitions but it doesn't
    - any auth - not sure if it should or not, but it's possible

    Also it doesn't distinguish between POST, PUT, DELETE and GET HTTP
    requests favouring instead entirely separate endpoints, but that's up
    for discussion.

    So, J. Shirley, do you have any interest in a merge? And others, do
    you have ideas and would you like to contribute?

    Thanks,
    Luke.

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Zbigniew Lukasiak
    http://brudnopis.blogspot.com/

Related Discussions

People

Translate

site design / logo © 2021 Grokbase