Konstantin Gredeskoul
2007-Nov-07 00:47 UTC
RESTful Design - beyond CRUD: shopping cart implementation
Hello fellow Railers :) I am trying to grasp REST-ful design, and after reading about REST in several (including http://www.b-simple.de/documents, watching the corresponding PeepCode and reading the blog entry http://weblog.jamisbuck.org/2007/2/5/nesting-resources) I am still left with questions as to how REST works in real life applications, beyond simple CRUD actions, and where additional value parameters are often required to complete meaningful operations. Let''s look at a basic example of a shopping cart implementation. Most carts are implemented as a model Cart, that has_many :cart_items If I were to use a straightforward REST based resource provided by Rails, I would probably end up with URLs as follows: - /carts/3/cart_items/new - /carts/3/cart_items/6 - etc... This is not very useful to me, because there''s no reason cart items need to be exposed this way in the URL at all. I consider it implementation detail and would rather have a more "facade" oriented API that makes sense to a client and hides the relationship between Cart and CartItem. What I really want, if I were to build a REST-ful API for both users and machines to consume my shopping cart management API, I would probably do something like this: Desired Action Verb URL Return ----------------------------------------------------------------------------------------------------------- get current cart: GET /carts OK; empty or ID of the current cart (eg, 3) create new cart: POST /carts/new OK; XML: id of the new cart; HTML: redirect view this cart: GET /carts/3 OK; XML: contents of the cart; HTML: cart page add product 3, qty 4 UPDATE /carts/3;add/3/4 OK set qty to 1 UPDATE /carts/3/3/1 OK empty cart UPDATE /carts/3;empty OK ----------------------------------------------------------------------------------------------------------- What I am struggling with, is how can I use Restful resource, and yet embed parameters in the URL as in "/carts/3;add/3/4" where 3 is the product ID I want to add, and 4 is the quantity. Or should I simply pass those as standard query parameters - "/carts/3;add?product_id=3&qty=4". This seems rather ugly and breaks resful addressability. So to summarize my questions are: - Am I correct in trying to build a REST-ful API as a "facade", that "simply makes sense", rather than that to follow standard CRUD pattern? - Is there a way to use the URLs like above, and yet take advantage of map.resource and the URL building helpers? - What is the right way to pass parameters to the RESTful controller, such as product_id and quantity? Any feedback is much appreciated. Konstantin --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Michael Guterl
2007-Nov-07 00:58 UTC
Re: RESTful Design - beyond CRUD: shopping cart implementation
On Nov 6, 2007 7:47 PM, Konstantin Gredeskoul <kigster-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hello fellow Railers :) > > I am trying to grasp REST-ful design, and after reading about REST in > several (including http://www.b-simple.de/documents, watching the > corresponding PeepCode and reading the blog entry > http://weblog.jamisbuck.org/2007/2/5/nesting-resources) I am still left > with questions as to how REST works in real life applications, beyond simple > CRUD actions, and where additional value parameters are often required to > complete meaningful operations. > > Let''s look at a basic example of a shopping cart implementation. > > Most carts are implemented as a model Cart, that has_many :cart_items > > If I were to use a straightforward REST based resource provided by Rails, > I would probably end up with URLs as follows: > > - /carts/3/cart_items/new > - /carts/3/cart_items/6 > - etc... > > This is not very useful to me, because there''s no reason cart items need > to be exposed this way in the URL at all. I consider it implementation > detail and would rather have a more "facade" oriented API that makes sense > to a client and hides the relationship between Cart and CartItem. > > What I really want, if I were to build a REST-ful API for both users and > machines to consume my shopping cart management API, I would probably do > something like this: > > Desired Action Verb URL Return > > ----------------------------------------------------------------------------------------------------------- > get current cart: GET /carts OK; empty or ID of the > current cart (eg, 3) > create new cart: POST /carts/new OK; XML: id of the new > cart; HTML: redirect > view this cart: GET /carts/3 OK; XML: contents of the > cart; HTML: cart page > add product 3, qty 4 UPDATE /carts/3;add/3/4 OK > set qty to 1 UPDATE /carts/3/3/1 OK > empty cart UPDATE /carts/3;empty OK > > ----------------------------------------------------------------------------------------------------------- >From what I can tell this breaks the whole philosophy behind REST that you have standard HTTP methods to work with. The idea behind REST is to eliminate these inconsistencies in web services, basically a uniform interface...> > What I am struggling with, is how can I use Restful resource, and yet > embed parameters in the URL as in "/carts/3;add/3/4" where 3 is the product > ID I want to add, and 4 is the quantity. Or should I simply pass those as > standard query parameters - "/carts/3;add?product_id=3&qty=4". This seems > rather ugly and breaks resful addressability. > > So to summarize my questions are: > > - Am I correct in trying to build a REST-ful API as a "facade", that > "simply makes sense", rather than that to follow standard CRUD pattern? > > No, I don''t believe you are correct in trying this. Not if you''re tryingto be RESTful.> > - > - Is there a way to use the URLs like above, and yet take advantage > of map.resource and the URL building helpers? > - What is the right way to pass parameters to the RESTful > controller, such as product_id and quantity? > > Any feedback is much appreciated. >If you''re really interested in getting a grasp on REST I recommend the RESTful Web Services book. There are lots of examples (an entire chapter on rails). It really connected the whole concept of ROA and REST for me. Most of the information that I have found elsewhere was largely academic in nature. HTH, Michael Guterl --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Diego Scataglini
2007-Nov-07 03:50 UTC
Re: RESTful Design - beyond CRUD: shopping cart implementation
> > Let''s look at a basic example of a shopping cart implementation. > > Most carts are implemented as a model Cart, that has_many :cart_items > > If I were to use a straightforward REST based resource provided by Rails, I > would probably end up with URLs as follows: > > /carts/3/cart_items/new > /carts/3/cart_items/6Perfectly fine. btw, /new is only so that you can get the form to create the resource. It''s not requested by REST.> etc... > This is not very useful to me, because there''s no reason cart items need to > be exposed this way in the URL at all. I consider it implementation detail > and would rather have a more "facade" oriented API that makes sense to a > client and hides the relationship between Cart and CartItem. > > What I really want, if I were to build a REST-ful API for both users and > machines to consume my shopping cart management API, I would probably do > something like this: > > Desired Action Verb URL Return > > ----------------------------------------------------------------------------------------------------------- > get current cart: GET /carts OK; empty or ID of the > current cart (eg, 3) > create new cart: POST /carts/new OK; XML: id of the new cart; > HTML: redirect > view this cart: GET /carts/3 OK; XML: contents of the > cart; HTML: cart page > add product 3, qty 4 UPDATE /carts/3;add/3/4 OK > set qty to 1 UPDATE /carts/3/3/1 OK > empty cart UPDATE /carts/3;empty OK > > -----------------------------------------------------------------------------------------------------------revised get /cart post /cart get /cart/3 put /cart/3/add as body &product_id=3&qt=4 put /cart/3 send the whole cart with updated value or put /cart/3/product/3 or /cart/3/3 and send quantity value as part of the body (I prefer the first one, it''s more discoverable and descriptive) delete /cart/3 I wouldn''t probably use that /carts/3;add/3/4 or anything like that. Going outside of crud verbs is okay but In most cases there is a better alternative way.> What I am struggling with, is how can I use Restful resource, and yet embed > parameters in the URL as in "/carts/3;add/3/4" where 3 is the product ID I > want to add, and 4 is the quantity. Or should I simply pass those as > standard query parameters - "/carts/3;add?product_id=3&qty=4". This seems > rather ugly and breaks resful addressability.No it doesn''t. /carts/3;add?product_id=3&qty=4 is perfectly fine as RESTfull resource. Why would it break addressability? Can''t you bookmark it? Wouldn''t that url always give you the expected result? Isn''t it differentiable from /carts/3;add?product_id=3&qty=5? Can''t you link it, bookmark it, print it, read it, type it? If type it in my browser wouldn''t I get the same result (give that there are no sessions involved) as if You typed it? Then it''s addressable. Don''t confuse pretty url with REST. They are not even distant cousins. You could have /cart/3.add.4.times.product.3 although since it''s an update that you''re seeking the url would like like this PUT /cart/3/add or PUT /cart/3.add or whatever URI you want to give it, and the parameters would be as body of the requests.> So to summarize my questions are: > > Am I correct in trying to build a REST-ful API as a "facade", that "simply > makes sense", rather than that to follow standard CRUD pattern?No, I don''t think so. CRUD is not obligatory but preferred and most thing can be expressed as CRUD.> Is there a way to use the URLs like above, and yet take advantage of > map.resource and the URL building helpers?With a combination of map.resources and map.connect:.. sure. And it doesn''t break rest.> What is the right way to pass parameters to the RESTful controller, such as > product_id and quantity?Any feedback is much appreciated.Key value pair is perfectly fine &name=diego&job=programmer When you''re posting you can just encode the parameters. BTW, whenever you''re posting you can pretty much use any data structure that you want. Key value pairs, json, xml, yaml whatever you want. REST is about resources as URI''s and leveraging the HTTP verbs and protocol. The idea is that you can use the same URI /cart/3 with GET, POST, PUT and DELETE and get 4 different and expected/consistent results. Diego I too would suggest read more about REST. Don''t confuse how Rails does REST with what REST is. Sam Ruby''s book so far is the best resource so far. It''ll clear out the confusion.> > Konstantin > > > > >-- Diego Scataglini --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---