4

In a RESTful application, how do we differentiate between an "action" and an HTTP verb (GET, POST, PUT, DELETE)?

For example, as I understand it, a GET request to the resource /products should return a list of all products. A POST request to /products should create a new product. How, then, does the user request the original form which is used to create the product? My initial response would have been a GET request to the same URI, but as mentioned above, that should return a list of all products - not a blank form for creating a product.

In most frameworks I've researched, this problem is solved by making the "action" part of the URI. For example, a POST request to /products/create would create a new product, whereas a GET request to /products/create would give the blank form for creating a product. To get a list of all products would be a GET request to either /products or /products/get, /products/read, etc. depending on the framework in question. This approach resolves the ambiguity above, but it conflicts with what I've read about traditional REST design.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
FtDRbwLXw6
  • 27,774
  • 13
  • 70
  • 107
  • `but it conflicts with what I've read about traditional REST design` -- Why? – Robert Harvey Aug 07 '12 at 23:31
  • @RobertHarvey: Because the "action" is redundant with the HTTP verb. If an action is specified in the URI, then you'd only ever need two of the verbs (i.e. `GET` and `POST`). – FtDRbwLXw6 Aug 07 '12 at 23:34
  • 1
    In a pure REST environment, you would be accessing resources, not actions. So, to get the form to create a new product, you would issue a `GET` on the /products/form URI. You would then perhaps use Javascript to turn the form into a JSON request, which you would then `PUT` to /products. As you've already pointed out, it seldom works out that way, probably partly for convenience reasons, and partly because REST isn't commonly fully exploited for most web resources. – Robert Harvey Aug 07 '12 at 23:41
  • 1
    @RobertHarvey: If I'm understanding correctly, you're saying that the blank form for a new product should be treated as its own resource (that would only support the `GET` method), rather than an action for the product resource? – FtDRbwLXw6 Aug 07 '12 at 23:45
  • In ASP.NET MVC, the `POST` verb is supported by a different controller method overload that accepts the form data upon SUBMIT. – Robert Harvey Aug 07 '12 at 23:47
  • @RobertHarvey , the issue is that web browsers really do not play well with other request methods. That's why the common practices is to use `` to let your forms have custom request methods. It's a bit hack'ish, but works just fine. Of course, of you are using ASP.NET MVC, it might not be an available option. – tereško Aug 07 '12 at 23:57
  • @tereško Related: http://stackoverflow.com/q/3900974 – Robert Harvey Aug 08 '12 at 00:03

2 Answers2

2

IMHO, the best option is to make the request method a part of controller's action.

Lets say you are accessing http://who.cares/product/42 or http://who.cares/product/42/specification . This query to webserver would translate as Product controller. The actions name should be created by combining request method and command:

DELETE "http://who.cares/product/42"

    controller: "Product", 
    action:     "deleteProduct()" 


GET "http://who.cares/product/42/details"

    controller: "Product", 
    action:     "getDetails()"


POST "http://who.cares/product/42/review"

    controller: "Product", 
    action:     "postReview()"


GET "http://who.cares/products/ 

    controller: "Products", 
    action:     "getProducts()"


POST "http://who.cares/products/ 

    controller: "Products", 
    action:     "postProducts()"
tereško
  • 58,060
  • 25
  • 98
  • 150
  • How would this option treat requesting a blank form for inputting a new product? What would the URI and action be? – FtDRbwLXw6 Aug 07 '12 at 23:43
  • This is more or less the way it works in ASP.NET MVC. But since the controller method is typically part of the URL, you still see the controller method name in the URL, as in /products/create. GET and POST are only split across form requests and SUBMITs. – Robert Harvey Aug 07 '12 at 23:44
  • @tereško: But that doesn't explain the difference between requesting the new product form and submitting it. I get that submitting it would be a `POST /product`, but what would requesting the form be? It can't be `GET /product`, since that should return a collection of all products. – FtDRbwLXw6 Aug 07 '12 at 23:47
  • @drrcknlsn , `POST "http://who.cares/products/` would turn into `postProducts()` method. The fallback command (if none is set in URI) is the same as the controller's name. To be honest, I am still a bit confused about the difference between `PUT` and `POST` (I think they translate as "*save*" and "*add*"). You should be using different controller for working with list of items: `Products`. And another one for dealing with single item: `Product`. – tereško Aug 07 '12 at 23:53
  • @tereško: What URI do I use to retrieve the blank form for creating a product? `POST /products` will only _create_ the new product. But how do I _get the form in the first place_ so that I can fill it out and submit it? – FtDRbwLXw6 Aug 07 '12 at 23:58
  • 2
    @drrcknlsn , I would go with `GET "/products/new"`. The REST interface is not really aimed at HTML applications. What you are doing this way is creating an API for 3rd party apps. Therefore it is not necessary for the requests, which return HTML forms, to be RESTful. – tereško Aug 08 '12 at 00:16
1

here is example like it Rails does

REST request path    |  action name | Description
---------------------|-------------------|-------------
GET    /profile/new  | new               | Render a form for creating the profile
POST   /profile      | create            | Create a the profile from the received data
GET    /profile      | show              | Render a the profile
GET    /profile/edit | edit              | Render a form for editing the profile
PUT    /profile      | update            | Update the profile based on the received data
DELETE /profile      | destroy           | Destroy the profile

I don't see any conflict , Idea is that urls are human readable and you can introduce new URIs to show different representations of the same resource. (like profile/1/edit and profile/1) /profile/new - address of profile that is empty (like profile/1, profile/2 .. etc in show method) But if you want you can suggest that profile/1/edit is some kind of different - nested resource of profile/1/ resource, but I like to thing that it's just other representation of profile/1/ resource =)

Also is good idea to use plural and singular URI when you working with many resources or with one, example

/profile/1.html - gives you 1 resource
/profiles.html - gives you list of profiles
Fivell
  • 11,829
  • 3
  • 61
  • 99
  • Well, sort of. This method still includes "actions" by way of `new` and `edit`, but leaves the other redundant ones out. I suppose that's better than `DELETE /products/delete/123` and the like. – FtDRbwLXw6 Aug 07 '12 at 23:40
  • @drrcknlsn: In ASP.NET MVC, it would be a POST to `/products/delete/123`. I've never seen anyone actually use the DELETE verb there. – Robert Harvey Aug 07 '12 at 23:45
  • @RobertHarvey: That's even more confusing for me, since I wouldn't think anything other than `DELETE` would be used to delete a resource. Though, I sort of understand the rationale behind using `PUT` if you're going the route of including the action in the URI (makes more sense than `GET /products/delete/123` or any of the others). – FtDRbwLXw6 Aug 07 '12 at 23:51
  • 1
    @drrcknlsn: Part of the problem is that you need a confirmation page for a delete. So a `delete` url is really a GET for a confirmation page. The delete then occurs behind the scenes, in the POST controller method upon submission of the confirmation form. HTML really only supports GET and POST verbs anyway. See http://stephenwalther.com/archive/2009/01/21/asp-net-mvc-tip-46-ndash-donrsquot-use-delete-links-because.aspx for more information. – Robert Harvey Aug 07 '12 at 23:55
  • @RobertHarvey, our conversation is about REST, not about what really HTML supports =) REST is about HTTP, there are ways to simulate PUT, PATCH and other http verbs for html almost in all web frameworks – Fivell Aug 07 '12 at 23:57
  • OK, but Rails is a framework that allows you to develop *HTML applications.* Naturally, if your REST model is simply an API to another application or framework, it may be more "pure" than this. – Robert Harvey Aug 07 '12 at 23:59
  • @RobertHarvey , your link with problem above is only about ASP.NET and how it implemets REST , not about REST actually... – Fivell Aug 08 '12 at 00:06
  • @Fivell: My point with the link is that you would not issue a `DELETE` action on a link, since Google crawling your delete links would wreak havoc on your database. Such links are almost always `GET`s. I apologize for all the other superfluous information; my experience is in ASP.NET. – Robert Harvey Aug 08 '12 at 00:08
  • @RobertHarvey: Thanks for the article link; I read most of it. It seems to suggest that using `DELETE /product/123` is safe, as is `POST /product/delete/123`. The security hole is allowing `GET /product/delete/123`. – FtDRbwLXw6 Aug 08 '12 at 00:12
  • usually delete operation can be done only by authorized users, I don't remember a project where google or other crawler can even see it, also there are another option you can use forms with buttons for delete – Fivell Aug 08 '12 at 00:12
  • @drrcknlsn: Yes, you're right. I'm conflating `GET` with being authorized to perform the delete. The `GET` would be to get the confirmation form. As you can see, most of the impurity is being create by the web application itself; with a properly-designed REST API, and a suitable application that interfaces with it, there really should be no impurity. But since ASP.NET MVC and Rails are, to a certain extent, mixed metaphors, a certain amount of purity is sacrificed for convenience. – Robert Harvey Aug 08 '12 at 00:13