tags:

views:

321

answers:

5

Suppose I want to create a REST interface to find the average of a list of numbers. Assume that the numbers are submitted one at a time. How would you do this?

  1. POST a number to http://site.com/api/average
  2. If this is the first number a hash will be returned
  3. POST a number to http://site.com/api/average/hash ....
  4. GET http://site.com/api/average/hash to find the average
  5. DELETE http://site.com/api/average/hash since we dont need it any more

Is this the right way to do it? Any suggestions?

+7  A: 

It makes more sense to think of the list of numbers as the resource. Suppose each list's resource URL is /list/{id} where {id} is a placeholder for the list's ID. Then:

  1. POST /list creates a new list, the server generates a list ID (or 'hash') and specifies the /list/{id} URL in the response's Location header.
  2. POST /list/{id} adds a number to the list
  3. GET /list/{id}/average returns the average
  4. DELETE /list/{id} deletes the list.

An alternative to GET /list/{id}/average would be for GET /list/{id} to return the list as structured data, e.g. XML, that includes the average as a generated property.

Peter Hilton
seems like a good answer, but when or how should the service determine when to delete the {id} if the client forgets?
kenny
Personally, I'd just set-up a timer task to delete 'old' lists once a day. Unless the lists are very huge or frequent, you might be able to store a year's worth.
Peter Hilton
A: 

But without the hash how does the server distinguish between lists?

Each list has an ID, although that could be generated by the server - I'll edit my answer to include that.
Peter Hilton
A: 

To maximize REST philosophies I would do the following

Do a PUT this to indicate a new structure that would generate a hash, that is not based on the number passed. Just a "random" hash. Then each subsequent post would include the id-hash with returned result hash of the numbers sent. Then when a get is presented on that you can cache the results.

1. PUT    /api/average/{number} //return id-hash
2. POST   /api/average/{id-hash}/{number} // return average-hash
3. GET    /api/average/{average-hash}
4. DELETE /api/average/{id-hash}

Then you can cache the get of the average hash, even when you may get to the result in a different way, or different servers get that same average.

null
A: 

What you are talking about is doing a stateless transformation of a request representation (list of numbers) into a response representation (single number).

Lets categorize your resource:

  • Stateless -- The request is stateless, but so is the resource. It should be able to take your request, process it, and return a response without maintaining any internal state. Further discussion below.
  • Unlikely to be cacheable -- I am making an assumption here that your lists of numbers are never/seldom identical.
  • Idempotent -- Requests have no side effects. This is because the resource is stateless.

Now lets examine the different HTTP methods:

  • GET - Gets the state of a resource. Since your resource has no state, it is not appropriate for your situation. (idempotent, cacheable)
  • DELETE - Removes a resource or clears its state. Also not appropriate for your situation. (not idempotent, not cacheable)
  • PUT - Used to set the state of a resource (or create it if it does not exist). (idempotent, not cacheable)
  • POST - Used to process requests which may or may not modify the state of a resource. May create other resources. (no guarantee of idempotence -- depends on whether the resource is stateful or stateless, not cacheable)

As you see in the other answers, POST is most popularly used as a synonym for 'create'. While this is ok, POST is not limited to just 'create' in REST. Mark Baker does a good job of explaining this here: http://www.markbaker.ca/2001/09/draft-baker-http-resource-state-model-01.txt (Section 3.1.4).

While POST does not have a perfect semantic mapping to your problem, it is the best of all the HTTP methods for what you are trying to do. It also leads to a simple, stateless, and scalable solution, which is the point of REST.

In summary, the answer to your question is:

  • Method: POST
  • Request: A representation of a list of numbers
  • Response: A representation of a single number (average of the list)

While this may look like a SOAP-style web service invocation, it is not. Don't let your visceral reaction to SOAP cloud your use of the POST method and place unnecessary constraints on it.

KISS (Keep it simple, stupid).

A: 

You cannot just return a hash or an ID, you have to return URIs or a URI template plus the field values. The only URI that can be part of your API is the entry point, otherwise your API is not REST.

Wahnfrieden