[Catalyst] In search of RESTful CRUD holy grail

Zbigniew Lukasiak zzbbyy at gmail.com
Wed Mar 4 12:25:40 GMT 2009


This might be a futile mission - but I think I learn something with
each recurrence of this discussion.  So let's restart it once again.

CatalystX::CRUD::REST has a well described RESTful URI structure:

    # POST          /foo                -> create new record
    # GET           /foo                -> list all records
    # PUT           /foo/<pk>           -> update record
    # DELETE    /foo/<pk>           -> delete record
    # GET          /foo/<pk>           -> view record
    # GET          /foo/<pk>/edit_form -> edit record form
    # GET          /foo/create_form    -> create record form

I think everyone will agree that this is indeed REST.  For some cases
there might be a slight problem with that URI schema - if you have a
string primary key - and it can have the value of 'create_form' - then
you will not know if the client is requesting a view on the object
with that id or if he wants the page with the form to create a new
object.

This leads to new variation:

    # POST          /foo                -> create new record
    # GET           /foo                -> list all records
    # PUT           /foo/by_id/<pk>           -> update record
    # DELETE    /foo/by_id/<pk>           -> delete record
    # GET          /foo/by_id/<pk>           -> view record
    # GET          /foo/by_id/<pk>/edit_form -> edit record form
    # GET          /foo/create_form    -> create record form

Of course 'by_id' could be 'instance' or whatever (perhaps the library
should let the user to choose that infix part).

Now   '/foo/by_id/<pk>/edit_form' needs to make a PUT request to
/foo/by_id/<pk>.   To get around the problem with requests outside of
the basic 'GET' and 'POST' repertoir we can use
Catalyst::Request::REST::ForBrowsers.   But it also means that for
browser requests in the case of mistakes made in the form the action
answering that PUT request to '/foo/by_id/<pk>' needs to render the
form again with error indicators. But for non browser requests in case
of similar errors it needs to encode those errors in some other way.
This shows that 'edit_form' is only informing us how to *render* (or
serialize) the data. In the case of GET requests it informs us that we
should render the object data inside of a form and in the case of a
PUT request with errors it informs us that we should similarly put the
error data into the form.  This leads to next variation:


    # PUT           /foo/by_id/<pk>                  -> update record
or return the error encoded for non-browsers
    # PUT           /foo/by_id/<pk>/edit_form  -> update record  or
return the error encoded as HTML form
    # DELETE    /foo/by_id/<pk>                  -> delete record
    # GET          /foo/by_id/<pk>                  -> view record
(for non-browsers encoded)
    # GET          /foo/by_id/<pk>/edit_form  -> view record encoded
as an edit form

And similarly:

    # POST          /foo                     -> create new record
    # POST          /foo/create_form -> create record form
    # GET           /foo                      -> list all records
    # GET          /foo/create_form   -> create record form

i.e. - here we treat 'edit_form' and 'create_form' consistently as a
path info parameter informing us about the serialization method.   The
advantage of this arrangement is also that we don't need to put any
address into the 'action' parameter of the form - and let it always
submit to itself.  In another variation we could move that parameter
from path info to real parameters and have uris like:

    # PUT           /foo/by_id/<pk>                                ->
update record  or return the error encoded
    # PUT           /foo/by_id/<pk>?x-view=edit_form   -> update
record  or return the error encoded as HTML form
    # DELETE    /foo/by_id/<pk>                                -> delete record
    # GET          /foo/by_id/<pk>                                 ->
view record (encoded)
    # GET          /foo/by_id/<pk>?x-view=edit_form    -> view record
encoded as an edit form


Finally we need serialisation and dispatching to different methods for
the same address (/foo/by_id/) based on the method.  This is covered
by Catalyst::Controller::REST.   What I have not yet explored is how
to add this new serialisation method (to 'edit_form') to the
configuration of a Catalyst::Controller::REST based controller.


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



More information about the Catalyst mailing list