In my previous article (please read it first), I tried to describe how I understand the REST architectural style irrespectively of any communication protocol. Here, I’ll try to map this concept into the HTTP 1.1 protocol (though it applies to HTTP/2 as well) to show that bare HTTP is not suitable to fully host RESTful communication. To illustrate my way of thinking, I’ll use an extended music player example form the previous article. I will associate every song with number of playlist names it can be referenced by to bulk up representations.
2 Mapping Core of REST
Looking for the generalization I have defined the core of REST as a set of concepts consisting of: transfer, state, representations, safety and idempotence.
Transferring state using representations maps easily into HTTP. As HTTP demands a request-response communication model, verbs, describing commands, have been introduced to tell the requests demanding data from requests providing data apart. These verbs are
POST). This already introduces some kind of RPC into the picture but does not break REST yet. HTTP can carry any data so applications are free to construct their representations. Figure 1 shows a music player example using HTTP with a textual representation.
Figure 1. Music player state transfer using HTTP.
According to HTTP standard,
GET is supposed to be safe operation and
PUT is supposed to be idempotent. Stating that, the core of REST can be mapped into HTTP.
Mapping State Patching
In order to use state patching technique which is an inevitable optimization in real applications where the state is most often huge, there needs to be a possibility to uniquely identify state chunks. HTTP uses URIs for that purpose calling addressable state chunks "resources". Figure 2 shows an example of reading and writing a state chunk.
Figure 2. Reading/writing state chunk (resource) using URI.
The problem occurs while transferring multiple chunks in a transactional manner.
In order to read multiple state chunks (resources) transitionally, all of them need to be requested by the client in one self-contained message and then sent by the server in another self-contained message. This is possible only if we can construct a URL encompassing all of the requested resources (for example, addressing group of resources), as HTTP itself does not support multiple URIs within a single
GET request (see Figure 3). Similar situation applies to response message, as there is no way to send multiple resources along with their URIs back to client within a single HTTP response message. It is possible to use a
POST request with some artificial URI not related to any resource and a payload carrying a list of requested URIs. It is also possible to forge response with representation containing a list of all requested resources along with their URIs, but such solution constitutes a new "inner protocol" that merely uses HTTP as a transport mechanism breaking layer isolation along the way.
Figure 3. Reading/writing multiple resources is not supported by bare HTTP.
The same as with transactional read, a transactional write of multiple unrelated chunks of state is not supported by bare HTTP.
POST requests support neither multiple URIs and representations within single HTTP request message, nor multiple status codes within single HTTP response message. It is true that
POST supports multipart payload but all of those parts are addressed to a single URI, so it is only a partial, not satisfying solution (it is possible to correlate each part of a multipart message with a UIR by extending HTTP with non-standard headers though).
Patching Variable State
In the precious article, I described how RESTful patching of variable state can be achieved by introduction of metadata denoting "timelines" of state chunks. This can be only partially mapped to HTTP. The NEW and MODIFIED adjectives can be (semantically incorrectly) mapped into the
PUT verb, which behaves differently whether a target resource exists or not. The
MISSING adjective can be mapped into a
DELETE verb. The server should react to
DELETE in an idempotent. The problem is that patching a variable state of multiple unrelated resources where some of them are
MODIFIED, and some missing is not supported by HTTP as only one verb is allowed within a single message (see Figure 4).
Figure 4. Patching variable state is not supported by HTTP.
HTTP is a good protocol that serves its purpose well. It gave birth to REST and was influenced by it, but it is not 100% RESTful (it is actually an RPC that RESTful behavior can be built upon). People have tried to work around these deficiencies by designing clever URIs and representations, breaking layer isolation along the way (see this book for some recipes), but in the end the bare 100% standard HTTP cannot provide true RESTful communication except cases when "the whole" state gets transferred every time.
Appendix: How a True RESTful Protocol Should Look Like
A truly RESTful protocol covering all exemplified use cases may use any transport it sees suitable but shall define massages as follows:
- Message type: enumeration (
ACKNOWLEDGEMENT) – to discern message type (not every message type needs to be used)
- List of unique chunk identifiers: there can be a special identifier for "entire state" like "
NULL; URI is a good candidate but not the only one
- List of state chunks:
- For every chunk:
- Chunk identifier;
- Chunk "timeliness" tag: enumeration (
- Chunk representation: any data format;
Figure 5 shows an example message exchange of a proposed protocol.
Figure 5. RESTful protocol example.