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.