Wednesday, June 13th, 2007

RESTful Revert

By Avi Flax

One of our goals for this blog is to give a glimpse into how we work, and how we think. In that spirit, here’s a recent discussion that took place in a Trac ticket. The task was to add, to a RESTful web service, a way to revert a resource to a previous version.

Here’s what I first came up with for this operation:

In a nutshell: to revert a policy to a previous version, a client merely has to POST a representation of that version to the policy resource.

Example Case: Policy HPXQ1-66544 is at version 10, and we want to revert it to version 9.

Step 1: First, the client might want to retrieve a representation of the current state of the policy:

Client: GET /policies/HPXQ1-66544
Server:
200 OK
Content-Type: application/xml
<InsurancePolicy id="HPXQ1-66544" version="10">
...
</InsurancePolicy>

Step 2: Now the client wants to check out version 9:

Client: GET /policies/HPXQ1-66544?version=9
Server:
200 OK
Content-Type: application/xml
<InsurancePolicy id="HPXQ1-66544" version="9">
...
</InsurancePolicy>

Step 3: Let’s revert to version 9

Client:
POST /policies/HPXQ1-66544
Content-Type: application/xml
<InsurancePolicy id="HPXQ1-66544" version="9">
...
</InsurancePolicy>
Server:
200 OK
Content-Type: application/xml
<InsurancePolicy id="HPXQ1-66544" version="11">
...
<History>
....
<Event type="revert" timeStamp="now" note="Reverted to version 9"/>
</History>
</InsurancePolicy>

The developer whose app needed to interact with this API, Sima, was down with all this, but she had one question: “Just curious about the reason for a 2 step process?”

It was a good question! And since I’m always up for discussing REST theory, I replied with this missive:

The reason for the “2-step process” rests in REST theory.

But before I get into that, I should make a correction to the API: the method used should be PUT, not POST.

If we look at the official HTTP spec, the definition of POST is:

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.

…example cases are provided, one of which is: “Providing a block of data, such as the result of submitting a form, to a data-handling process”

The definition of PUT:

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server.

Some people, trying to make REST more accessible, have correlated POST to the “Create” and PUT to the “Update” in CRUD. That does work, to a certain degree. But it doesn’t express one of the primary meanings of POST, which is: “please process this data”.

So hopefully you’ll all agree with me that PUT is more fitting to the operation at hand than POST.

…and that’s just my preamble! Now on to the real theory:

REST stands for Representation State Transfer. The idea, in a nutshell, is that systems can function entirely by providing and accepting representations of the current state of resources, using a predefined set of methods, which are uniform for a given protocol.

Right now, our systems do a lot of providing representations, and not a lot of accepting.

But this case is a perfect fit for this side of REST.

Let’s translate:

Request 1 HTTP English
Client: GET /policies/HPXQ1-66544?version=9 Please give me a representation of the current state of the resource “version 9 of the policy HPXQ1-66544″
Server:
200 OK
Content-Type: application/xml
<InsurancePolicy id="HPXQ1-66544" version="9">
...
</InsurancePolicy>
OK, here’s a representation of this resources’ current state, of content-type application/xml, enjoy!
Request 2 HTTP English
Client:
PUT /policies/HPXQ1-66544
Content-Type: application/xml
<InsurancePolicy id="HPXQ1-66544" version="9">
...
</InsurancePolicy>
Please store this representation as the new content of the resource “the policy HPXQ1-66544″
Server:
200 OK
Content-Type: application/xml
<InsurancePolicy id="HPXQ1-66544" version="11">
...
<History>
....
<Event type="revert"  timeStamp="now" note="Reverted to version 9"/>
</History>
</InsurancePolicy>
OK, done. And here’s a representation of this resources’ current state, of content-type application/xml, enjoy!

Hopefully that makes sense.

Now, at this point you may be shaking your head and saying, “fine, OK, but that all seems fairly complicated. I thought REST was supposed to be simple?! Wouldn’t it be even simpler if the server would just support a method to do this, something like revertPolicy(version)?”

That’s understandable. The benefits of using REST aren’t always apparent when you’re working on or with a single web service. But you just learned the deep nuances of POST and PUT. And the great thing is, that knowledge is portable. Because of REST’s uniform interface, you now know how to use almost any RESTful web service. All you need to learn is what its resources are – you already know what methods the service supports, and what they mean. In a non-RESTful, RPC architecture, such as SOAP, every single service has a completely unique API – a set of procedures – and no knowlege is portable from service to service. In the RPC model, every API has a steep learning curve, because you’re starting at zero every time.

I hope this made sense. I’m really into this head-space right now, ’cause I just recently read the new book, RESTful Web Services – and it’s excellent. I highly recommend it.

So, that’s the kinda stuff we talk about here at arc90. If you have anything to add, please feel free!

Leave a Comment