Amazon is catching a lot of flak over their implementation of a RESTful API for SimpleDB. Stefan calls it "the shittiest REST API in a long time". Bill says that "Ascribing REST to the SimpleDb API might be down to lack of knowledge or marketecture".
So what is the fuss about? Take a look at the following sample code from the Amazon SimpleDB developer guide:
https://sdb.amazonaws.com/?Action=PutAttributes
&DomainName=MyDomain
&ItemName=Item123
&Attribute.1.Name=Color&Attribute.1.Value=Blue
&Attribute.2.Name=Size&Attribute.2.Value=Med
&Attribute.3.Name=Price&Attribute.3.Value=14.99
&AWSAccessKeyId=
&Version=2007-11-07
&Signature=Dqlp3Sd6ljTUA9Uf6SGtEExwUQE=
&SignatureVersion=1
&Timestamp=2007-06-25T15%3A01%3A28-07%3A00
Can you see what the problem is? It's kind of subtle, so I'll give you a hint - what is up with that "Action=PutAttributes" bit in the URL?
The problem is that in REST you use the HTTP methods GET, PUT, POST, DELETE, HEAD and OPTIONS. In the above example, GET is being used. Now, the interesting thing about the GET method is that according to the HTTP spec (RFC 2616), it is "safe":
GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval
In other words, the GET method is what you use for reading things (e.g. queries or looking up items). GET should not be used to update things. Lots of web infrastructure rely on these semantics to do their job. Breaking the contract hurts the web.
So how would you make it RESTful? First, I'd recommend taking a look at Joe Gregorio's excellent advice from 2004 on designing a REST API. Joe suggests asking four questions:
- What are the URIs?
- What's the format?
- What methods are supported?
- What status codes should be returned?
So lets map out a strawman SimpleDB REST API using these questions as a guideline.
The URI
In this case, we are updating something in MyDomain which is identified by ItemName.
Resource | URI |
MyDomain List | /mydomains/ |
MyDomain | /mydomains/{item-name} |
The Format
These days, JSON is a pretty decent format to use as a generic starting place. XML is still fine & dandy, but is a little harder to work with in browser clients. You might want to take a look at Atom as well. In any case, clients can use Content Negotiation to ask for their preferred representation.
A JSON format for a SimpleDB item could look like this:
{
"DomainName": "MyDomain",
"ItemName": "Item123",
"Timestamp": "2007-06-25T15%3A01%3A28-07%3A00",
"Attributes": {
"Color": "Blue",
"Size": "Med",
"Price": "14.99”
}
}
The list of items would look like this:
[
{"ItemName": "Item123", "href": "https://sdb.amazonaws.com/mydomains/123"},
{"ItemName": "Item321", "href": "https://sdb.amazonaws.com/mydomains/321”},
...
]
Notice that in the list we have indicated the href of each specific item.
The Methods
Mapping the available operations to the MyDomain items/item we get the following:
Resource | URI | Method | Description |
MyDomain List | /mydomains/ | GET | Retrieve the list of MyDomain items |
POST | Create a new MyDomain item | ||
MyDomain | /mydomains/{item-name} | GET | Retrieve a specific MyDomain iem |
PUT | Update a MyDomain item | ||
DELETE | Remove a MyDomain item |
The Status Codes
Joe recommends that you document the status codes that you expect to return for each operation. Some of the more common ones are:
- 200 - OK.
- 201 - Created. When an item is successfully created return a 201 and the response will include a Location: header with the URI of the newly created item resource.
- 204 - No Content. Used for a successful DELETE.
- 301 - Moved Permanently.
- 400 - Bad Request.
- 410 - Gone.
Note that in HTTP there is the idea of status code fallback. The 2xx series means success, 3xx means a redirection and the 4xx series means a client error. If a client doesn't understand 201 for example, it can still safely assume that the operation was a success.
So there you have it. My version of a RESTful API for SimpleDB. SimpleDB seems like a very cool idea to me. Let's hope they sort this mess out soon.
Posted by: Geoffrey Wiseman | 2007.12.16 at 11:16 PM