May 6, 2012 2 Comments
Who do you think the actor is in the sentence “Brenda was happy to interview the actor”, a Hollywood celebrity or a member of the local community theater? The REST constraints described in Roy Fielding’s dissertation enjoy celebrity status. I cannot mention constraints without people immediately assuming that I either talk about them, ignore them, or argue against them. Few realize that I talk about additional application constraints or perhaps about strengthening one of Fielding’s constraints. I wish I could use another word, but the well-known REST constraints and application-specific constraints aren’t much different and combine to define a concrete RESTful protocol.
I want to be free to talk about constraints because by definition a protocol is a set of rules, many of them constraints. The Wikipedia definition of a communication protocol, “…a system of digital message formats and rules for exchanging those messages in or between computing systems and in telecommunications” mentions rules, but examples from the Merriam-Webster dictionary illustrate even better that the word protocol is synonymous with a set of rules:
- The soldier’s actions constitute a breach of military protocol [rules or regulations].
- They did not follow the proper diplomatic protocols [rules or etiquette].
- What is the proper protocol [rules or conventions] for declining a job offer?
The Geneva Protocol and the Kyoto Protocol set forth international regulation agreed upon by the participating countries. Similarly, the rules of a communication protocol are agreed upon by participants in the communication, not imposed by an external authority. Standards and specifications like RFC 2616 merely formalize the results of the agreement.
A constraint is a rule. What kind of rule is surprisingly hard to define exactly. Some would say a constraint is a rule about what not to do. This is close, but not close enough. Not close enough because any statement about what to do can be rephrased, however awkwardly, to say not to do the opposite. You can say “the protocol must be stateless” or “the protocol must not force the server to keep track of the client’s state”. Either way, it is the same constraint.
Constraints are like good parenting: instead of telling your kinds what to do, you set safe, age-appropriate limits, but otherwise let your kinds live their life and make their own decisions. Protocol constraints are used the same way to ensure safe, reliable, performant communication without restricting what the communication should be about. Constraints are also used to remove unessential variations which would complicate protocol implementation without any clear benefits. For example you can make you protocol simpler if you support JSON only. This is a valid constraint as long as XML support is not essential.
Constraints should never restrict an essential freedom. This is so important that we have an expression for such mistake: to over-constrain. I find it quite unfortunate that the noun constraint derives from the verb to constrain, which has meanings like “restrict by force” or “to secure by or as if by bonds”. These meanings suggest firmness and strength. Some of us subconsciously think of constraints as exceptionally strong and important rules. If somebody ever reminded you in a stern voice of a REST constraint, you know what I mean. To discuss constraints rationally we have to let go of our emotions. We don’t have to enforce constraints more vigorously than other protocol rules.
Let me give you some examples of relatively strict constraints. To show you that my use of constraints is consistent with Fielding’s and that some of his REST constraints are implicit in mine, I’ll gradually relax mine until they become equivalent with two of his.
Imagine a simple HTTP interface for a key-value data store. Clients send GET, PUT, and DELETE requests using URIs as keys and message bodies as values. The following constraint expresses a one-to-one mapping between URIs and message bodies: “As a response to a GET request the server must either return the status code 404 Not Found, or 200 OK and a message body which is a copy of the message body received in the last successful PUT request to the same URI”. Just to show I can, I expressed this as a rule about what the server must do. The remaining constraints are indeed easier to express in terms of what the server must not do, such as:
- The server must not return the 404 status code if there was a previous successful PUT request to the same URI
- The server must not return other HTTP status codes, for example 302
- The server must not allow the byte sequence representing the value assigned to the URI to change by any other means except as a response to an explicit PUT request
- The server must not return a message body for any URI for which no value was yet set
… and a few more. These constraints give my protocol some nice, useful properties. I can fully test my server via the protocol, for example.
“This is not REST”, you may object, “where is the hypermedia?” Good point. The hypermedia constraint does not say you must use hypermedia everywhere. That would be a bit too strict and would render most of the media types from the IANA registry unfit for REST. The constraint says to use hypermedia to indicate what the valid client state transitions are and to help clients discover URIs. In my protocol all client state transitions are valid and the client does not need to discover URIs because it controls the URI space. Hence there is no hypermedia. You may say that the hypermedia constraint is not applicable. I prefer to say that it is satisfied.
To extend the applicability of my protocol beyond key-value data stores I need to relax some of my constraints. To turn my data store into a simple web server I need to eliminate constraint 4 and allow URIs pre-loaded with static content. Unfortunately the loss of constraint 4 also means that my clients no longer know what URIs exist and what they mean. Now I do indeed need to satisfy the hypermedia constraint. There are still many different ways to do it, for example I can provide a site map. Clients can still rely on their knowledge that values associated with URIs never change, use caches that never expire, for example.
Now imagine that my URIs identify Wikipedia articles. I don’t expect articles to change much over time, but I want to allow minor edits or formatting changes by eliminating constraint 3. Without constraint 3, however, message bodies for two successive GET requests may no longer be identical and I lose my ability to programmatically verify URIs still point to valid pages. Indeed, Wikipedia needs volunteers to make sure pages were not vandalized.
I hope I’ve emphasized enough that if I relax my constraints my protocol’s applicability increases but I lose some useful protocol properties. Just how far can I go with relaxing my constraints? Let’s see how far the editors of Wikipedia go. They accept in the page identified by the URI http://en.wikipedia.org/wiki/Tutankhamun any information about the Egyptian pharaoh that meets the quality standards of an encyclopedia. They would definitely not accept information about someone’s pet just because it happens to be named Tutankhamun and they would be equally perplexed to find information about Joe DiMaggio at this URI. Sounds like common sense? I’ve told you that I’m demystifying the REST constraints.
Let me generalize a bit. We expect both URIs and message bodies to mean something. When they are used together in HTTP, we expect their meanings to be related and this relationship between their meanings to remain the same. This is the same as to say that we don’t want to receive (or send) two HTTP message bodies with entirely different meanings from the same URI. This relaxed constraint was implicit in the first version of my protocol, which asked for strict one-to-one mapping between URI and message body. The relaxed version permits many-to-many relationship between the two as long as the relationship between the meaning remains one-to-one.
How useful is this relaxed constraint? The full answer doesn’t fit into this post, but let’s see if we can build a SOAP-like RPC protocol without having HTTP message bodies with different meanings sent to or returned from the same URI. If our service has a single URI, the message bodies mean “invoke method A”, “invoke method B”, and so on. Even if each method has its own URI, the message body sent means “invoke the method” while the message body returned means “this is the result”. Can we say they mean the same thing? I’m not saying the constraint was explicitly formulated just to prevent us from doing RPC over HTTP, only that it has this result as well.
Roy Fielding states the same constraint when he says that message bodies should be representations of resources identified by URIs even though the explanation some people give goes like this (I’m kidding you not): “Two of the REST constraints are the identification of resources and the manipulation of resources by representations. An identifier identifies a resource. A resource is anything that can be identified. A representation can be anything you can send over the network. Got it?” This is not what Fielding says although he says all these things. Each sentence is a quote from his dissertation, but taken out of context, combined into a meaningless blurb, and passed on as REST design wisdom. I won’t attempt to untangle this mess. The dissertation is available online, read at least section 5.2.
Fielding’s REST constraints are neither laws of nature nor religion. Following them does not guarantee success and violating them does not bring inevitable doom. They play the same role as “Stay on trails” signs in our national parks. If you stray from the beaten path there is a slight chance you will discover something wonderful nobody saw before, but you also risk falling into a ravine, starting an avalanche, or being killed by a grizzly bear.
This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 Canada License.