Friday, February 8, 2008

Designing a RESTful API

There's a bit of art that goes into designing any API. We've designed and refined a SOAP API over the last couple of years, and the RPC-like nature of SOAP does seem to make things fairly simple from an API designer's perspective. Everything looks more or less like methods you would see in C#, only exposed through a service.

Designing a RESTful API, on the other hand, is a process I am finding to be a much bigger mental leap.

The REST model is best suited for problems where you're dealing with assets - that is, things that you act upon. But I couldn't find any good examples that were truly RESTful and also handled complex asset scenarios.

What is truly RESTful? Well, to be truly RESTful you use all 4 HTTP verbs (GET, PUT, POST, DELETE). You don't add action verbs as params (?name=smith&action=delete). I could be flip and say it's not RESTful because it's cheating, but it's not about a dogma. The design criteria was to make the API as simple as possible, and having to know about special action= parameters requires additional knowledge on the part of the consumer. For us, the consumer should be able to have no prior knowledge of the API, just of the resources they want to access, and still be able to accomplish useful work.

The complex asset scenario is trickier, I think. Most of the RESTful APIs out there deal with rather flat and simple resource structures. Amazon's S3 resource structure never gets more complex than GET /[bucket-name]/[key-name], and Google's search API is also flat but decorated with lots of filters: GET /search?q=bill+material&output=xml&client=test&site=operations

Don't get me wrong - simple is good! It's just that these aren't great models to learn from for a more complex set of assets. For example, say I have a taxonomy of categories with n numbers of subcategories. Each category can contain n number of items. Items can also contain subitems. Categories and items can each have a set of properties, and furthermore each category and item can be one of a certain set of types, which means they can have different property sets. And the same items can appear in more than 1 category. In some cases I only want to retrieve a subset of all available properties for n items or categories.

Category A (categoryType=F1)
.|- Category AA (categoryType=G4)
....|-Item 27 (itemType=9H)
....|-Item 492 (itemType=4Y)
.|- Item 1 (itemType=9H)
Category B (categoryType=F1)
Category C (categoryType=F1)
.|-Category CC (categoryType=H8)
.|-Category CD (categoryType=H8)
...|-Item 1 (itemType=9H)
.....|-Item 303 (itemType=7T)
.....|-Item 305 (itemType=7T)
.....|-Item 306 (itemType=7T)
.|-Item 27 (itemType=9H)

This is, in a nutshell, the set of resources I need to be able to expose through the API.

For something with this level of complexity, where thinking in terms of sets becomes more natural, I found Microsoft's Astoria project (officially: ADO.NET Data Services) to be very helpful. Especially the concept of filtering resources.

Take the following example: GET /Customers[ALFKI]/Orders[1]/Employees, which filters the assets based on the data in the brackets, in this case returning those employees who created Order ID=1 for customer ID=ALFKI. The beauty of this approach is that it's easy to extend the filters in the brackets. So I could do GET /Customers[ALFKI]/Orders[1,2,9]/Employees or even /Customers[ALFKI,PDX,MSTR]/Orders[1-1000]/Employees.

The RESTful API we're working on isn't done yet - we're just starting to create a mock service that spits out static XML so we can get a feel for how the various consumers will actually use the API. This will let us play with the details of the API and the XML format before we commit to building all the data plumbing underneath it.

Here are some RESTful resources I found helpful:
  • Using ADO.NET Data Services - some great thinking from Microsoft on building a RESTful API for selecting complex data sets
  • Why REST Failed - the title is overstated, but Elliotte Rusty Harold (no relation to me) does a great job explaining the current challenges with PUT and DELETE support in modern browsers. Good for understanding what you're getting into.
  • Why PUT and DELETE? - an interview with Elliotte Rusty Harold that does a nice job of explaining why you want to go to the effort of supporting all 4 HTTP verbs despite the limited browser support. In a word - elegance.

No comments: