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!

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!

The issue with your example is that as a client, unless I am strongly coupled to your server, I dont know that the particular field "next" contains a URL, as there is no standardised naming for fields in generic JSON, and no way of marking a field as a URL not a string.

Now we could all agree that the IETF standard link relations mean the same in JSON, that could work.

Decoupling as I see it derives from the way the server generates stable schemas above the JSON level as declared self-descriptively in Content-Type. Including, say, always using link relation names in the tags, putting URLs in to strings; always having consistent and stable tagnames and structure and domain-level meanings.

Then the clients read it, self-descriptively, and get what they want from it, not necessarily even what the server expected them to, and certainly not stopping at the Media Type. There's no necessary, parallel, synchronised upgrading of client with server, which is what I see as "coupling". The kind you get in WS-*.

At the JSON level: you get the JSON object and are forced to map that into hashes, lists, strings, etc. So now how do you know what to do with all that stuff? You don't stop there, you go up a level. Perhaps into your link rels indicating URLs, or maybe you can spot that there are strings that conform to URL syntax. You are reading the data self-descriptively. Helped by knowing that the same rules of interpretation will always apply.

But at some point, you hit the reason you fetched the object at all. Which means interpreting that data. Levels upon levels.

Getting value from a JSON object above its Media Type is not coupling, it's unavoidable!

Now we could all agree that the IETF standard link relations mean the same in JSON, that could work.

Presumably you noticed that I deliberately used one of those!

Like you say, "all you have to do is agree". And several sources can agree to use the link-rel convention, or to follow certain stable JSON schemas and standards.

It's not a simple case of "If it's in the Media Type You're Decoupled, If it's Above the Media Type You're Hopelessly Coupled and not RESTful." Self-descriptive agreement and interpretation can happen in various ways, but always, the server has to be Postel-compliant and issue stable, published formats, perhaps with multiple layers, some shared by other servers.

May 9, 2011 12:32

From
Jakob

About media type see my comment on the previous article.

About your "idempotent POST": sure, you can implement it idempotent. But the HTTP Spec say POST makes no guarantees about it. And so know all intermediates, server and clients. That´s why your browser is warning you, if you POST again...

And by the way, using POST for a "deleting" functionality: isn´t that just tunneling? :-)

I'm not sure what point you're making about the idempotent POST... :-/

Say you hit a "delete this item" button on a Web page and it - I can guarantee it - gets sent back using POST. Firstly, that will be idempotent without Tim or Roy losing any sleep...

Secondly, the reason no-one thinks that's tunnelling is because, on the Web, GET and POST are used for the each-way state transfer of domain-level data. They transfer state, in or out, then get out of the way to let the domain conversation between the user and the application continue.

Hence, related to this, and a point I could have added to my article: the status codes you get back from POST should only tell you if that state transfer was OK or not, or needs adjusting in certain ways. You should not use status codes to return domain-specific information about success or failure - on the Web that all happens in the HTML content - the domain-level state.

I suggest we start to respect the way the Web works - including the way it neatly separates concerns! :-)

So yes you could do Hypermedia using JSON or plain XML - however by doing this you are in effect creating an implicit media type on top of them. Now this may sound appealing, and perhaps its a trade-off you can afford - value is not determined by the adherence to any particular model of thinking.

However on the wider web you don't know who is going to use your service or what their capabilities are. And in an enterprise of any size you may not know in the long term who is going to use your service or how they intend to use it. The way our services get used changes over time, often in ways we don't expect.

But even in the case that you do 'control' both sides the other problem you find doing it implicitly is what happens should you want to change the semantics of that implicit media type - how do different clients ask for the different implicit representations? By changing the URI? Query params? Custom headers? Worse still you could end up wrapping your representation in an envelope that provides version information which clients have to interrogate first before deciding how to handle it.

It's that point about being able to reliably find links and other elements where it breaks down. It's only reliable because you understand the implicit nature.

You want to lower the integration barrier by moving away from an explicit media type? That's not the way to do it, if a client doesn't have the capabilities to understand what its getting, don't give it to them. I think there is a fundamental difference between a client ignoring an element it does not understand, and being given something advertised as one thing and getting another.
Like ordering a CocaCola and getting CocaCola & Rum - just ignore the rum part if its not of interest....

Gracefully degrade based upon what the client is able to accept.

If the client can handle html, give them html, if they can handle json (and it makes sense to your service) give them a json representation. If they can handle your protocol (media-type), bingo they get the full feature set, hypermedia with bells on.

Use content negotiation to make the life as reliable for ANY client as possible. Without it you are leaving the client to assume that its interpretation is the correct one.

What number do you get if you increment 4? ( required; to prove you are a worthy correspondent )

By submitting a comment, you agree to its being published under the same copyright conditions as the site itself. Copyright in comments belongs to the submitter. The owner of the site disclaims any responsibility for the content of comments. Comments may be deleted at any time for any reason.