Like Subbu, I also have been sitting on a blog post about the Richardson Maturity Model. I have different reasons for feeling uncomfortable with this Model, however.

The following came out of a discussion on an internal list at ThoughtWorks, where a number of people were talking about how they aspired to reach the "Holy Grail" of REST Level 3, and still thought they were basically "doing REST" by addressing most of the uniform interface.

But, as indeed pointed out in that article, REST is only at Level 3.

However, fortunately, you can jump right to Level 3 without much effort.

REST Is Easy

I believe that this Maturity Model language and thinking has the negative effect of making it seem that:

  • there are "degrees of REST" below "Level 3", which there aren't
  • achieving a RESTful architecture is like reaching the top of Mt. Everest!

But REST can actually be very easy to achieve in your application!

Here's how easy it is to be RESTful - "Level 3" - in just six lines:

GET /resource/1 HTTP/1.1
Host: restful.com
                                .
HTTP/1.1 200 OK
Cache-Control: max-age=100
Content-Type: application/json
                                .
{ ..,  "next":  "/resource/2",  .. }

Pretty simple, huh? If you're surprised by my use of JSON, hold on a minute, I'll get to that.

Here's how we meet the REST constraints, Hypermedia and all:

  • Client-Server: HTTP gives us that one
  • Layered, Cache: HTTP, and that unexpired response came from a proxy-cache!
  • Identification of Resources: /resource/1 and /resource/2 is that covered
  • Manipulation thru Representations: those JSON octets represent /resource/1
  • Self-descriptive/Headers, etc: yup, we're using HTTP correctly
  • Self-descriptive/Media Types: JSON is pretty well understood
  • Stateless: this is a completely self-contained HTTP exchange
  • Hypermedia guides the client: the next request was "GET /resource/2"..

I grouped Stateless and Hypermedia together at the end there, as they are closely-related constraints, and get to the heart of one of the most important flips you'll need to make in the way you see your distributed systems, if you wish to go from an SOA to an "ROA" or RESTful mindset: which is the flip from thinking Imperatively to thinking Declaratively.

 

The Flip you need to Make in your Thinking

Even though the server forgets this client after this brief exchange, see how it's left a little trail, a little clue, in the content for it to follow? That's /resource/2 of course.

Stateless means that the server doesn't hold state for the client - it doesn't care what the client does in between requests or where the client thinks it is in the achievement of its goals.

  • In other words, the server doesn't lead the client through what to do - Imperatively
  • It simply offers guidance in the form of the content of its responses, and the links contained within them - Declaratively

This flip in thinking gives you one of the greatest benefits of REST: decoupling!

 

Declarative Decoupling

Notice how a server doesn't care if you ever fetch /resource/1 or /resource/2 - it simply broadcasts its state, Declaratively, in the form of resources that any client can GET at any time.

Those clients expect to understand those responses just by parsing a standard or common type, then applying their own interpretation of the payload in their own context, decoupled from the server. A client doesn't even need to see that data the way the server sees it!

And that content doesn't end with that chunk of data - it links up to a potentially global Web of chunks of data. As a client, you can just wander around that Web, getting what you want from it, progressing to your goals, whenever you want.

From Imperative coupling to Declarative de-coupling, in six lines!

 

The JSON and XML Objection

So some of you may have heard that JSON and XML are no good for REST because they are not Hypermedia Types, and REST requires adherence to the Hypermedia Constraint.

However, don't worry, you can have your cool, easy JSON or old-faithful raw XML, and still be RESTful! All that you need to do to adhere to the Hypermedia Constraint is to able to reliably find those links! So this goes back to what I said in my last post: that it's OK to look into the content and find what you expect to find - it doesn't have to be finally declared in the Content-Type!

 

Postel, Schemas and Decoupling

This means you are layering your types, but then should ensure that you have stable layers above the standard JSON or XML Media Type carrier. You could perhaps re-use appropriate schemas, or design schemas with future re-use in mind - while obviously avoiding going down rabbit holes of over-analysis.

Following Postel's Law, the server should be strict and stable in these schemas or data types it uses to generate that JSON or XML, while the client just takes what it needs and is completely cool about all those new elements you just added, and is happy to ignore that payload it didn't understand.

Thus decoupling also applies to Media Types: clients won't break as long as server changes to types and schemas remain backwards-compatible for them.

Decoupling means that you don't share a library between client and server that both generates the JSON or XML and parses it: stick to the principle that it's up to the client how it interprets what it sees, and it should be free to change or to see things differently at any time. For example, don't expect the tags or 'rel's before your links to be the only thing that the client uses when deciding whether or not to jump the link!

 

But That's Just GET!

Indeed - and you'll notice that the Fielding Thesis is around 97% concerned with the GET-side of the Web's architecture. Doesn't even mention POST or DELETE!

Anyway, the same principles apply when shoving data back to servers. Be Declarative, self-descriptive: use a standard Media Type - HTML www-forms, or JSON or XML if you want more structure. Be stable in your schemas or data types. Include links to things any server can know about, not internal ids that only the server should know about.

Note that the server doesn't have to do what you want! You're not Imperatively telling the server what to do, you're Declaring your current state or at most your intentions over the server. Declarative means not just self-descriptive, but also stateless and idempotent - you're not sending Imperative commands back, you're Declaring state - a sample of your client application state, in fact.

That's another aspect of decoupling. This isn't lock-step RPC, it's about intention and often it's about eventual consistency - state that settles out in its own time.

Now here's another thing that can make your life simpler: you don't need to use PUT and DELETE to be RESTful! You can do what 99.99% of HTTP usage today does: just use GET and POST. Indeed, it's more RESTful to just use these, as they are more self-descriptive, in the sense that vastly more machinery out there understands just those two verbs.

So don't get stressed out about just using POST - as long as you're being Declarative and not tunnelling Imperative function calls:

  • Use POST the way the Web does: to return whole data structures in an agreed, stable domain-specific format over a common base Media Type
  • Use POST the way the Web should have done: idempotently! Which means putting enough identifying information in the content so that you can tell if you've seen it already
  • POST to real, GETable resources .. and don't forget to invalidate the cache of that resource as the POST flies by

So: forget the "Holy Grail of Level 3", and join in to the simple, good ole' RESTful Web - today!