[Catalyst] In search of RESTful CRUD holy grail
Moritz Onken
onken at houseofdesign.de
Wed Mar 4 12:45:44 GMT 2009
Am 04.03.2009 um 13:25 schrieb Zbigniew Lukasiak:
> 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.
>
Hi,
here are my thoughts on this:
I don't distinguish between edit_form and create_form. If there is a
primary key or similar avaiable (either in the path or in $c->req-
>param)
I show the edit form, if there is no such value I show the create form.
Furthermore I would not put the form rendering in the same path as the
REST interface.
I would do something like this:
# 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 /form/foo/<pk> -> edit record form
# GET /form/foo -> create record form
So now, what do we do with errors and redisplay of forms.
I would say a form should post / put / delete to the rest api.
Within that controller we can easily see if a browser is requesting
this url or a web service (see ForBrowser's looks_like_browser()).
If it's a browser we can detach to the /form/foo controller.
Otherwise we show the errors in the format of the Accept header.
moritz
More information about the Catalyst
mailing list