REST, You’re doing it wrong.

 

My wife recently expressed her frustration with the abundance of blog posts entitled ‘you’re doing it wrong’, or some approximation there-of; and so I could hardly resist writing one of my own! In this post I’d like to take a look at REST, and how it’s being used, or perhaps misused.

Just to be clear, there are a few points in this post at which I’ll point out common misunderstandings or misuses of REST, but in fact, whimsical title aside, this post is intended as a reading of the REST portion of Roy Fieldings dissertation on “Architectural Styles and
the Design of Network-based Software Architectures” more so than it is an accusation of fault.

What is REST?

For those of you that aren’t already aware, REST (Representational State Transfer) as an architectural style which was developed by Roy Fielding, at the same time as he was developing the HTTP 1.1 protocol (RFC 2068). Essentially, what is now called REST was the architectural style used in the development of HTTP 1.1 in 1997, but was first defined in Roys 2000 dissertation “Architectural Styles and the Design of Network-based Software Architectures.” A dissertation which I have read, and yet, I’m sure I still fail to understand most of it. I urge caution to the uninitiated. That’s what this blog post is really about, it’s my attempt to interpret REST for the uninitiated, including myself.

So what is REST?!!

Well, Roy Fielding defines REST as a series of constraints on an applications architecture. I’ll get into these constraints a little later, but first, lets understand why there are constraints to begin with.

Borrowing from Roy’s dissertation but whittling a little; There are two possible approaches when designing a system. Either you begin with a set of known components, and design based on those components, or you design first and later constrain your design to the available components. REST was designed with the later approach, and the mindset behind building a REST application is the same. In effect, and to reiterate, REST is a series of constraints to be applied to your application architecture.

It’s at this point that most descriptions of REST begin describing each of the constraints that REST imposes on your application architecture, but I feel this would be a little unfair. You see, most descriptions of REST focus specifically on the section of Roy’s work which defines REST, and neglect everything leading up to it. This is likely in the interests of brevity, however, I believe we can get off on a fair footing by first, and very briefly, using HTTP 1.1 (here-in simply HTTP) as an example.

HTTP provides a limited set of methods, OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE. Just think, all of the functionality of the web, and every web application ever written, operates over a protocol with only seven methods, and of those, only four are really commonly used in web applications!  How is this possible?

Well, the web is essentially one very large virtual state machine. Every operation performed over the HTTP protocol boils down to the creation, reading, updating and deletion (CRUD) of some piece of data, and each of those methods alters the state of that data. These operations are “State Transitions.” That is to say, the state of the data is altered, and therefore it transitions from one state to another.

The web is a perfect example of how versatile an application can be built on top of just a few state transition operations. The whole “world wide web” is effectively a giant REST application!

It’s also worth noting that the most common application of REST is in the use of HTTP based services, which typically use the JSON text format for encapsulating data. Neither HTTP nor JSON are requirements imposed on a REST application, but it has become something of a defacto standard.

So, lets start tackling those constraints we talked about. I’m going to take these in a different order to that in which they appear within Roy Fieldings dissertation:

Client-Server

One of the constraints imposed on components of a REST application is that they are client-server based. This constraint is relatively straight forwards, since REST is intended for building distributed applications that scale. Dividing the application into components which are accessible via the network makes REST a SoA (Service Oriented Architecture) design style. This allows for a separation of concerns between the components of your application. Each component may be responsible for a single piece of functionality, which offers the ability to put boundaries around the size of each component. This helps to keep your code base to a manageable size.

Layered System

REST also imposes that your application be divided into layers. This is almost implied by the application being client-server based, because ultimately the client and the server are two different layers. Layering is more than this however. Dividing the components of your application into logical groups (layers) allows you to place an additional boundary on functionality. Doing so, helps the application to scale both in terms of code-base, and physically in terms of infrastructure.

Uniform Interface

We’ve already discussed state transition operations. This is the point at which I think most developers begin to get REST services quite wrong. This constraint appears to be one of those which is frequently misunderstood, or, is not even applied.

Consider this piece of JSON text taken from a hypothetical web service:

{
result: {
  ISBN: "978-0-345-39180-3",
  title: "The Hitchhiker's Guide to the Galaxy"
}
status: "ok",
error: ""
}

It would be reasonable to assume that we’re looking at the result of a query into a database of books, and have been given back the title and ISBN number for one of the books in the database. We can also infer from this data that a method call was made, and that the result of that method has the status of “ok”, and therefore there is no associated error message. Presumably the “error” field would be populated if the status were anything other than “ok”.

This is precisely NOT how a RESTful service should respond!

You see, from this piece of JSON it’s possible to infer that some arbitrary method was called to look up the book, and arbitrary methods are not part of a Uniform Interface. We should also not see a status code embedded within the response because, if we invoke the appropriate state transitions on a web service, the HTTP protocol already provides status codes. (See HTTP Response Codes).

A truly RESTful service could simply call the HTTP “GET” method on an endpoint named “books”, or, if a particular book is requested by ISBN for example, “books/isbn/978-0-345-39180-3” and the appropriate response for having called the GET method would look more like this..

[{ ISBN: "978-0-345-39180-3", title: "The Hitchhiker's Guide to the Galaxy" }]

As you can see, there is no need of status codes, or error messages when the HTTP protocol responds with code 200 “Ok”. If there is an error within the service during the “GET” request, it could respond with a HTTP response code 500 “Internal Server Error”, or with one of the many other HTTP response codes. If there are no entries to be returned, it can return a simple empty JSON array.

Why? Well, using the HTTP methods and response codes imposes a Uniform Interface onto your service. It means that any REST client application is able to call this method, without needing prior knowledge of the “status” and “error” fields of the data, nor does it need to understand that the actual result is nested within a meta-object containing those fields. So long as the client application understands how to work with the HTTP protocol (which it should if it’s a client application for web services), it will be able to browse the service just as it would any other web based resource.

This also implies a secondary constraint which is not explicitly stated in Roy Fieldings work, but which is implied. When developing your REST based application, you should be considering the data and resources first, and not the methods you wish to have act on that data.

Try to think of the HTTP methods as being the only opportunities you have to run server-side logic, and make no other methods at all. This will no doubt force you to structure your application in such a way that the data structure must accommodate the application logic.

What if you want to run some logic on the server? Well, let me come to that after going through some of the other constraints…

Stateless means Stateless (almost)

The next constraint of the REST architecture, is that communication between the client and the server must be stateless.

This means that each time the client communicates with the server, there must be sufficient information transferred in order for the server to complete the request. To re-word that, the server must not need to look up some previous communication in order to complete the request.

This does not mean that a REST application is stateless. Far from it in-fact. Each piece of a REST application has state information, it’s simply that no component of a REST application should be concerned with the state of any other component.

Lets consider an example application, to further understand how state works within a REST application. We’ll imagine an application which displays a grid of data to the end-user, which is retrieved from a server. The client part of the application will not transfer all data from the server, but rather, it will transfer the data in ‘pages’, and as the user scrolls through the data in the grid, new pages are transferred as required.

The client component of our example application has plenty of state information contained within it. For example, it remembers which page of data was previously requested, so that as the grid is scrolled, it can request the next, or previous page of data as required.

The server component has state information too. The current version of the data stored on the server can be considered the servers state.

Most importantly however, the server is not responsible for the state of the client.That-is; the server need not remember which page of data was previously requested by the client in order to provide the next page. Each time the client requires a new page of data from the server, it includes within the request, an identifier which specifies which page of data it is requesting.

Changes to the data on the server are performed by State Transitions, which we discussed earlier. Sticking with our example application, suppose the end-user alters some data within the grid. The client component transfers the new data to the server as part of a state transition operation. That-is, the Representation (data) is Transferred in order to alter the server State, get it? This is Representational State Transfer.

You may be thinking, “that makes the client responsible for the server state, doesn’t it?” well, no. In the case of our server in this example, the server state is the state of the stored data. Our client does not store that data, it simply requests that the data transition from one state to another. The isolation of state is therefore maintained in both directions.

Cache

Another constraint of a REST application is that responses to a client which may be cached, should be. This constraint in Fieldings work is seemingly ambiguously defined:

“Cache constraints require that the data within a response to a request be implicitly or explicitly labeled as cacheable or non-cacheable.”

If a constraint suggests that data be labeled as cacheable either implicitly or explicitly, how do we know when the data should be labeled and if the label should be implicit or explicit? Does this not make the constraint optional? Well, no. The constraint is not optional at all, but the choice of implicit or explicit labeling does depend on your own application.

The important thing to remember with regards to caching responses, is that data which is unlikely to change need not always be transferred. An example of this is a static web page. While a static web page may be altered at the server, it is not likely to be altered during a single user session on that web site. It would be safe for the browser to cache a copy of that page for a limited time, and then not request it again from the server during the session. This would remove an entire client-server interaction, and therefore result in less network traffic. This is in-fact in common use, all modern browsers have a cache and obey the HTTP headers to cache data or not to, and it’s particularly useful for reducing network transfer of image data, which is unlikely to ever change during the lifetime of a website.

What the seemingly ambiguous statement is saying, is that your application need not implement headers at all. If data is known to always be cacheable, then it always is cacheable and need not be explicitly labeled as such. It is merely a specification of the application components that they understand the caching mechanism.

Code On Demand.

The code on demand constraint is one which offers the opportunity for your server component to return executable code, which may be run by the client. If you think about this, you’ll see that it offers a great degree of flexibility. It’s precisely this constraint which enables the delivery of web based applications through a web browser.

Unlike the other constraints of a REST application, this one is in fact optional. There is no requirement that your REST application must support code on demand.

This constraint need not be so sophisticated as providing a full scripting language such as javascript either. You could for example deliver the client application as HTML responses from a presentation component. This approach enables you to alter and update your user experience on the server, which greatly simplifies deployment of updates.

You’re doing it wrong!

So what are we doing wrong? Well, the most common mistake I see in the development of REST services and REST API’s is the one that I illustrated under the “Uniform Interface” constraint.

Software engineers coming from a more traditional object oriented architecture viewpoint, seem to be stuck in the mindset of performing all logic operations through methods.

For example, suppose you have an object named “person” representing a real world “carbon unit.” It seems that the common wisdom is that, in order to retrieve the age of that person, there should be a method named “getAge”. This method would look at the date of birth for that person, and subtract it from the current date to return their age.

In a REST application however, there should be no need of a “getAge” method to be called remotely, but instead, the age should be returned as a part of the representation (the data). The calculation of their age being performed on the state transition which reads the person from the server component. (the GET method call)

When designing your REST applications you should be thinking of the data that you need to return from a service, or that will be requested by the client, but you should not be thinking of the methods that you need to make available.

Why? Well, to reiterate once more, because REST requires that you have a uniform interface. This imposes the requirement that there is a limited set of common methods. Ideally, though not a requirement, those methods should be the methods of the transfer protocol (in most cases HTTP).

When designing your REST application, if you are thinking in terms of the methods which you will make remotely available, then you’re doing it wrong.

Conclusion

As I hope is always apparent in my blog posts, I am open to corrections and comments. I don’t claim to be an expert on REST, but hope that my reading of the dissertation, responsible for the current ubiquity of REST API’s, is useful to you.

As always,

Thanks for reading!

Facebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Leave a Reply