I'm working on RestWS integration for the Backbone module (#1463024: Build RestWS Flavor), and have run into an issue regarding opposite uses of PUT and POST in Backbone.js's save() method as compared to the RestWS module's behavior, as defined in the README.txt.

While RestWS uses HTTP PUT /<entity type name> for create and HTTP POST /<entity type name>/<entity id>.<format> for update, Backbone uses HTTP POST /<entity type name> for create (though the create URL can be changed...the REST verb is harder modify, though) and HTTP PUT /<entity type name>/<entity id>.<format> for update.

I think there is considerable reason to believe that Backbone's implementation is the "correct" one with regard to the HTTP 1.1 standard and the intended use, though there is some variation in opinion that could warrant a flexible interpretation (perhaps an admin setting to switch?)

For reference, see the W3's definition of POST vs. PUT, where the contrast is drawn that:

The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource.

By this definition the POST URI should not include the entity ID, as it should refer to the entity type handler or other gateway, while the PUT URI can (must?) include the ID.

As this blog post discusses, PUT and POST are not defined in terms of CRUD operations, and there are understandable interpretations in which either could be used for create or update, but only if two successive calls to the PUT create would result in the same object, as PUT is defined in terms of its idempotence. Because subsequent calls to create a new node will result in nodes with different nid's, however, our PUT / is not idempotent.

I should note that while I have some experience with REST development and JSON REST frameworks, I cannot consider myself an expert. Still, I think these documents make a pretty strong case for POST for create and PUT for update in RestWS's case.

I am also very excited about the potential of using RestWS's entity-based approach with Backbone. What is the best way to resolve this issue?

Thanks for everything,

Ethan

CommentFileSizeAuthor
#9 swap_put_post2.patch5.8 KBsepgil
#8 swap_put_post.patch4.43 KBsepgil
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

ethanw’s picture

Title: HTTP PUT/POST Reversed for CRUD CREATE/UPDATE Operations » HTTP PUT / POST Reversed for CRUD CREATE / UPDATE Operations
klausi’s picture

Hm, I'm not sure where we pulled the information for PUT == create and POST == update, but there was a source somewhere.

Anyway, we cannot just switch the behavior in the 1.x branch as this could break lots of clients. What we could do is to allow PUT and POST for create and update. So the semantics would be shifted to the presence of an id. If there is an id then it must be an update, if it is missing it must be a create. This contradicts your quotation from above a bit, but since everything is so fuzzy undefined anyway we could get away with it.

ethanw’s picture

I think allowing both makes sense. Perhaps it could be a variable setting, with the default for new installations being POST for create and PUT for update, but the update hook could set to the opposite for existing installs?

Robin Millette’s picture

I have a feeling that an option defaulting to current behaviour would be preferable to something automagically hard-coded in the long run.

klausi’s picture

Issue tags: +GSoC 2012

So we have several options to solve this:

1) We just change the meaning of PUT and POST and do nothing else, which will break existing sites (they cannot update the module)
2) We create a RESTWS 2.x branch where we correct this. The 1.x branch will be frozen for old sites and will get security updates only.
3) We introduce a variable setting as proposed above that indicates which is PUT and which is POST.
4) We don't really care about POST/PUT, we just assume that a request with an id is an update and a request without is a create operation.

I think I like option 2 best. What do you think?

setvik’s picture

Another option would be a hybrid of #2 and #3.

i.e. execute option #3 in the 1.x branch and include help text for the option on the admin settings screen that indicates the option will be deprecated in 2.x and that the module will standardize on post=create and put=update. Defaulting new installs to post=create/put=update and existing installs to the reverse will prevent existing sites from breaking as Ethan suggested above. Could maybe even have a drupal_set_message in there for admin users of existing installs that links to the settings page and encourages them to start migrating their code in preparation.

It's a bit more work but would allow new users to confidently start using the module and would provide existing users ample opportunity and warning to convert their code.

That said, it may be enough to go with just option #2 and include a clear warning on the d.o module page about post/put.

I'd be happy to help implement option #3 if you guys decide to include it.

klausi’s picture

I see no reason to implement the variable setting if we are starting a new branch anyway. We should get this right in the 2.x branch and do an alpha release immediately afterwards.

BTW: currently RESTWS has no admin settings screen, so we would have to create that for the setting. Meh.

sepgil’s picture

Assigned: Unassigned » sepgil
Status: Active » Needs review
FileSize
4.43 KB

Here is a patch that swaps put and create.

sepgil’s picture

FileSize
5.8 KB

Forgot to adapt the changes to the readme, so here is a new patch.

klausi’s picture

Status: Needs review » Fixed

Thanks, committed to the new 7.x-2.x branch. I have also updated the project page and added a dev snapshot.

Please test this, I'm planning to release the first alpha of 2.x on Monday.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

cmjns’s picture

Sorry to resurrect this, but I'd like to weigh in with an additional consideration, re breaking client code with changes to API semantics. I've been wishing for an API that gets much closer to a real Hypermedia API rather than just a sort-of-RESTful CRUD API. To this end, I think a significant step forward for RestWS would be to make use of rel attributes that link out to a resource description that communicates to clients what the intended semantics are. So,

would indicate to the client that node creation can happen at /node. Since rel is an URI it also can be followed by the client to get information about how to perform the intended state transition. /node/create could be used to tell the client that a POST with such and such data will create a node, including which fields are required, etc. This information can be cached by the client so that they don't have to hit the URL every time.

Doing this allows you to change all manner of characteristics of the API without breaking client code, so long as clients actually are using the API correctly (looking at rel and not making assumptions about semantics and URL structure).

cmjns’s picture

Status: Closed (fixed) » Active

Sorry to resurrect this, but I'd like to weigh in with an additional consideration, re breaking client code with changes to API semantics. I've been wishing for an API that gets much closer to a real Hypermedia API rather than just a sort-of-RESTful CRUD API. To this end, I think a significant step forward for RestWS would be to make use of rel attributes that link out to a resource description that communicates to clients what the intended semantics are. So,

would indicate to the client that node creation can happen at /node. Since rel is an URI it also can be followed by the client to get information about how to perform the intended state transition. /node/create could be used to tell the client that a POST with such and such data will create a node, including which fields are required, etc. This information can be cached by the client so that they don't have to hit the URL every time.

Doing this allows you to change all manner of characteristics of the API without breaking client code, so long as clients actually are using the API correctly (looking at rel and not making assumptions about semantics and URL structure).

Crell’s picture

Status: Active » Closed (fixed)

cmjns: That's a valid feature request, but should be a new request as it's a separate issue.

cmjns’s picture

Yep. I should know better. http://drupal.org/node/1683792

ethanw’s picture

Confirming that this fix addresses the issues in using with Backbone. Backbone module now supports RestWS out of the box: http://drupal.org/node/1463024#comment-6453512

ethanw’s picture

Issue summary: View changes

Corrected format of issue link #