RESTful Design - beyond CRUD: shopping cart implementation

Hello fellow Railers :slight_smile:

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

Hello fellow Railers :slight_smile:

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 trying to 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

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

Perfectly 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.