tags:

views:

57

answers:

1

Sorry for the strange title. Here is my situation.

I have a table of products with the name and display order of each product. The client can change the display order of the products. The table is generated using jQuery.tmpl and the data is pulled using GET under WCF. The products pulled from the db are by CategoryID.

When the user changes the display order of a product in the grid the product needs to be updated using POST. Once the data has been updated the server needs to send back an updated json object to update the table.

QUESTION: How do I structure my POST uri for this scenario? Here is what I have now.

 [OperationContract]
        [WebInvoke(
            Method = "POST",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate = "product/form/{categoryId}")]
        [return: MessageParameter(Name = "products")]
        List<Product> UpdateProduct(string categoryId);

I believe my uri for updating the resource is correct as I am updating a single product by a category id. However, I want to return a new set of products based on the changes made by the POST and not have to make a separate GET call.

Not sure if this is 'right'. Those restafarians have me spooked!

Thanks.

UPDATE I started thinking a bit more about my code above and realized there is more going on here. The reality of my situation is that I am trying to update a specific product by ProductID and THEN return a list of products by CategoryID. Essentially a POST and a GET. So would my URI look like this?

[WebInvoke(
Method = "POST",
UriTemplate = "product/form/{productId}/products/{categoryId}")]
[return: MessageParameter(Name = "products")]
List<Product> UpdateProduct(string productId, string categoryId);

With my method like this?

public static List<Product> UpdateProduct(string productId, string categoryId)
{
ProductManager.UpdateProduct(int.Parse(productId));
return ProductManager.GetProducts(int.Parse(categoryId));
}

UPDATE2

This question has been addressed here with a link Daniel provided. Although handling everything in one POST call appears to make sense, I don't think it conforms to the spirit of REST and using Uri's as resources. Using a POST and then a GET call appears to be the answer. Thanks to Daniel. His comments are good.

+1  A: 

A POST or PUT request to update the display order should not return back anything, except for the status code that indicates the status of the request. You should issue a separate GET request to receive the new list of top 15/25/50/etc products:

If a new resource is created, the origin server MUST inform the user agent via the 201 (Created) response. If an existing resource is modified, either the 200 (OK) or 204 (No Content) response codes SHOULD be sent to indicate successful completion of the request. If the resource could not be created or modified with the Request-URI, an appropriate error response SHOULD be given that reflects the nature of the problem.

From: Section 9.6 of the HTTP 1.1 Specification

You may also be interested in checking out the HTTP Spec (Sections 9.5 and 9.6) and the following Stack Overflow post:


That said, I can think of two ways to update the display order of the products:

  1. Send a move-up or move-down request for a particular product_id. This request can be invoked whenever an up/down button is clicked.

  2. Send the complete order_rank list for a whole category.

I believe the latter is more practical, but you may want to expose both operations. For the first approach the POST verb seems appropriate, but for the second one I would use a PUT.

For the first approach, I would imagine URIs like the following:

POST /products/{productId}/move-up
POST /products/{productId}/move-down

The above suggests that we're creating a "move-up" or a "move-down" command. The verb POST means "create" and the noun (the action) is "move-up" or "move-down" command, which acts on a particular product_id.

For the second approach, I would see a URI like the following:

PUT /categories/{categoryId}/order-rank

To which we can pass a JSON/XML/etc representation for each product_id with the order_rank number. The verb PUT means "update" and the noun is the "order-rank" for a particular category_id.

Daniel Vassallo
Hi Daniel. In my case the display order is a column in my products table. This is necessary for my application. If I understand you correctly you are suggesting 2 calls to perform this operation?
@user423311: No, just one call as you were suggesting. Basically, I only pointed out different URI structures.
Daniel Vassallo
Ok. So the general premise I posted would be ok in that I am PUT/POST(ing) to an update uri but also returning a set of data that from that update uri. FYI I chose POST because of what I read @ http://www.roberthahn.ca/articles/2007/04/06/url-design/ and @ http://jcalcote.wordpress.com/2008/10/16/put-or-post-the-rest-of-the-story/
@user423311: Sorry, I missed that part of the question... No, you should be doing two requests. A POST/PUT to update the order-ranking should not return back the new list of products. A POST that creates a new item can return a "resource id" that points to the newly created item, but a separate GET is required to retrieve that. The same applies to your case. When you change the order of the products, you should issue another GET request to get back the top 10/25/50/etc products.
Daniel Vassallo
I updated my post and saw your link. I will check it out.