This article is in two parts. It started with the wish to talk mostly about hypermedia controls, but I decided it would be better to do a preceding post covering some more foundational notes on building a RESTful service.
Recently there’s been plenty of discussion about service platforms – Steve Yegge’s accidental post on Google Plus springs most prominently to mind. This article is partly motivated by these discussions, but it’s also a product of my own experience designing, implementing, and consuming services. I’ll include resources I’ve found useful when working on RESTful services.
I’m going to assume basic familiarity with REST, so you may find this introduction helpful if you need a place to start.
Using the Richardson Maturity Model as a Guide
The Richardson Maturity Model is a layered approach to REST. Aside from sounding like a psychological evaluation, it’s a helpful way of envisioning the different elements that will comprise your service, and how they are composed.
In essence, the model can be described as follows:
- The first level concerns implementing URIs for each resource (like /pizzas/1).
- The second level details how to interact with resources through HTTP methods (GET, POST, PUT, DELETE…). You can think of this like CRUD operations for resources, though we’ll discuss later how that doesn’t quite suffice.
- Finally, the slightly mysterious “hypermedia controls” level. I’ll cover this in a second article, which is why it is greyed out in the diagram.
I highly recommend you read Martin Fowler’s full article on the Richardson Maturity Model if you haven’t already. You’ll notice I’ve left out quite a bit of detail for simplicity (including the entirety of the lowest level!)
Exploring REST and CRUD Further
It’s worth looking at HTTP verbs (level 2 in our diagram), and how they map to operations on your resources, in more detail. A common approach is to map the following HTTP verbs like so:
1 2 3 4 |
|
If I want to retrieve a pizza representation, I just GET /pizzas/{id}. If I want to create a new pizza, I POST my representation to /pizzas. Change the topping on a pizza? PUT the updated representation to /pizzas/{id}.
Using HTTP verbs in this way is a good approach for many applications. But it can, in some cases, lead to lack of good separation between model and controller. Take an example: composite representations. The representation of a news story may include headlines of related stories, user comments, and author metadata. Combining data in this manner is common for e.g. mobile clients where the trade off between composing representations (and increasing response size) and the increased latency of multiple requests is deemed necessary.
If the service was designed as a CRUD layer over some database models with no additional composition ability, then implementing these representations can lead to unexpected complexity. It pays to think about resources that don’t map directly to business objects and the way in which a controller will handle this. See Subbu Allamaraju’s excellent cookbook recipes (pp. 30-37)
This is something that is worth bearing in mind when choosing a framework on which to build your RESTful service. In a number of frameworks, the tendency is to derive controllers directly from models. How would you express the above representation in such a framework? Would it save time to use something with greater flexibility?
A final point, which leads on from the notion of generating representations directly from models, is versioning. If your representations are strongly coupled to business objects, changing your database schema implies change to your service. Templating representations helps dissociate the representation from the model, forcing potentially client-breaking to be acknowledged by explicitly modifying a template.
There are a couple of different ways to ask a webservice for a specific version of a resource. Some architects prefer the version to be passed as a header, but there is also a camp that supports having the version in the URL. Ian Robinson’s presentation (slide 20) covers this well.
Conclusion
We’ve covered the lower two levels of the Richardson Maturity Model with some expansion on mapping resources to business objects. There are many other subjects to cover – caching, error-handling patterns, content negotiation, but hopefully the above has provided some useful points to consider when designing a RESTful service and choosing a framework.
In my own work, I have found REST in Practice by Jim Webber, Savas Parastatidis and Ian Robinson a good resource.
In the next article I’ll talk about the final tier of the Richardson Maturity Model: hypermedia controls.