- Hypermedia as the engine of application state
- Self-descriptive messages
- Manipulation of resources through representations
- Identification of resources
Getting a clear handle on the definition of the REST architectural style can be daunting. While there is no shortage of descriptions available, I did not find many of them helpful at first. Also, as I began talking about REST to colleagues, I often had a difficult time producing clear descriptions for the key points. Over time, however, I sharpened my summary into a version that seemed to make sense to most of my listeners. I offer here my rendition of the REST model.
A definition
First, here is a succinct definition of REST from the Conclusions section of Fielding's 2000 dissertation:
REST is a coordinated set of architectural constraints that attempts to minimize latency and network communication while at the same time maximizing the independence and scalability of component implementations. This is achieved by placing constraints on connector semantics where other styles have focused on component semantics. REST enables the caching and reuse of interactions, dynamic substitutability of components, and processing of actions by intermediaries, thereby meeting the needs of an Internet-scale distributed hypermedia system.
As mentioned in the above quote, REST is often described as a set of constraints. Here, again using a quote from Fielding's work, is the set of constraints that defines the REST pattern:
REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state.
And here is each one, in turn:
Identification of resources
Every interesting resource has its own unique URI. This URI can be used
to request an instance of the resource. For example: http://example.org/users/
is a URI that might return a list of users. The URI is the identifier. The
resulting list of users is the resource.
It is important to note that a resource is not a 'storage object' but is, instead, conceptual entity. Resources represent some identified item that can be accessed - nothing more. The identifier (URI) is passed from the client to the server where it is resolved into a resource that is returned from the server to the client. Just how the server uses the identifier to 'construct' the resource is of no real importance to the client.
Manipulation of resources through representations
An identified resource can be returned in various formats such as HTML, XML, SVG, JSON, PNG, etc. These formats are representations of the identified resource. The list of possible formats (Media Types) understood by clients and servers is constrained and each format is well-defined.
REST-ful applications may support more than one representation of the
same resource at the same URI. And REST-ful applications allow clients to indicate
which representation of a resource they wish to receive. This is accomplished via
the Accept
HTTP header that is passed by the client to the server with
each request for a resource.
Resources can be updated (or added) by sending representations from the client to
the server. REST-ful applications may support more than one representation for updates
to the same resource. And REST-ful applications allow clients to indicate their preferred representation when sending data to the server. This is accomplished via the
Content-Type
HTTP header that is passed by the client to the server with
each resource sent to the server.
The de-coupling of the representation of the resource from the URI that identifies that resource is a key aspect of REST.
Self-descriptive messages
Each client request and server response is a message and REST-ful applications expect each message to the self-descriptive. That means each message contains all the information necessary to complete the task. Other ways to describe this type of message is "state-less" or "context-free." Each message passed between client and server can have a body (or 'entity body') and metadata.
REST-ful applications also operate on the notion of a constrained set of message types that are fully understood by both client and server. The document that defines HTTP 1.1 outlines eight message types (HTTP Methods) that can be sent to HTTP servers. Six of them are widely used today. They are: GET, HEAD, OPTIONS, PUT, POST, and DELETE. The first three are read-only messages. The last three are update messages. There are well-defined rules for how clients and servers are expected to behave when using these messages. The names and meanings of the messages metadata elements (HTTP Headers) are also well-defined. REST-ful applications understand and follow these rules very carefully.
Hypermedia as the engine of application state
Sharing representations by sending self-descriptive messages to identified resources changes the state of the application. For example, successfully POSTing a representation of a new "user record" to the server will change the state of the application by growing the list of users by one. Requesting a list of users (via GET) can return the new state of the application. Both POSTs and GETs are accomplished via hypermedia links.
In an HTML browser, GETs are accomplished by clicking on anchor tags that have an attribute ("href") which contains a resource URI. POSTs are handled by pressing the "Submit" button within a form tag that has a URI attribute ("action"). Note that the anchor and form elements were sent by the server to the client as part of the representation of the requested resource. In this way, a REST-ful application enables the server to inform the client of the possible ways to change the state of the application via hypermedia.
Additional considerations
In addition to the four primary interface constraints outlined above there are two other optional constraints important to REST-ful applications. These are 1) support for intermediaries; and 2) code-on-demand.
Support for intermediaries
Sharing resources using self-descriptive messages makes it possible for both client and server can take advantage of intermediaries (proxies). Intermediaries can be used to cache the results of requests, act as firewalls between clients and servers, and other tasks. Since REST messages are self-descriptive and their semantics are well-defined, REST-ful intermediaries can be safely added and removed at any point along the stream between client and server without breaking the communication line or requiring servers or clients to 'upgrade'.
Code-on-demand
REST-ful applications may also be able to take advantage of clients that support "code-on-demand." For example, Web browsers may allow servers to return scripts or links to applets that can be executed at the client. This additional code execution can extend the capabilities of the client without requiring the user to install new client software.
Comments