In Part 1, we talked about the hypermedia mosh pit that erupted when Roy Fielding leveled some blunt criticism at non-RESTful interfaces advertised under the banner of REST, and went on to list some principles of hypertext-driven API design.
I suggested that we might have a more productive discussion by framing these principles as separate aspects of hypermedia design:
- Resource Encapsulation - Loose coupling between between the client and server, enforced by hiding details of resources and identifiers.
- Processing Model - Using semantically typed hyperlinks to drive application state.
- Data Model - Formalizing message syntax and semantics as a data contract.
In this installment, we’ll focus on resource encapsulation, and explain the motivation for hiding details of URIs and resource types.
First, I should point out one constraint that cuts across all three aspects: The system must address all three of these concerns -- encapsulation, processing model and data model -- using a minimum of out-of-band information, concentrated wherever possible in the media type and link relation specifications.
This has specific meaning and implications in each of these three areas, and we’ll discuss those implications in context.
Loose Coupling and Separation of Concerns
As an architectural style, REST places an extremely high value on loose coupling between systems. This makes sense when you consider that “REST is software design on the scale of decades.”
REST describes the architecture of the World Wide Web, the largest-scale, longest-running distributed system in existence. In spite of huge advances in web standards, today’s browsers can still work with websites developed in the mid-‘90’s. And in many cases, today’s websites are at least partially functional on browsers that are ten or fifteen years old.
Low coupling is the key to this. As clients, browsers don’t need to know anything about the specific servers they access. They only know how to follow the rules of HTTP communication, and how to handle the content exchanged between client and server. They know how to handle the content because each message is explicitly labeled as conforming to a standard media type.
Resource Encapsulation: Good Fences Make Good Neighbors
Roy Fielding makes at least three separate points related to resource encapsulation:
- REST APIs should be independent of any communication protocol or URI scheme; protocols are specified in URIs, and URIs should be opaque identifiers, as far as the client is concerned.
- REST APIs should not require clients to compute or encode URIs. Clients should not know or care how URIs are formed internally, or how they may be related in a logical hierarchy. Again, URIs must be opaque identifiers.
- REST APIs should not expect clients to know how to interact with a given resource by means of a pre-defined “resource type” associated with that resource, or some other out-of-band information specific to that resource. In REST, resources do not have types. Representations have types; specifically, media types. Clients should use standard patterns of content negotiation to obtain a compatible representation, and should handle that representation as specified in its media type, without any resource-specific logic.
There is one exception to points 1 and 2: The REST API must have a URI that serves as the entry point. Practically speaking, you can’t abstract away the details of this entry point URI. But you can drive subsequent API interactions through semantically typed hyperlinks, starting with hyperlinks in the entry point representation. We’ll discuss this further as part of the processing model.
It’s Not Just about URI
Compromised resource encapsulation is the most common and most glaring violation of REST among internet APIs. If you look at the documentation of any given API, you’re likely to see a catalog of resources, where each resource specifies a URI or a static URI template, details about the methods supported, and the content of requests and responses.
In strictly RESTful APIs, nearly all of this detail is defined in media types and link relations. Media types define request and response payloads. URIs (other than the entry point) are late-bound; the client doesn’t depend on a specific URI structure. Instead, the client locates the resources it needs by finding hyperlinks with a specific link relation, starting from the entry point. Each of these links contains a URI or dynamically bound URI template that the client traverses.
Atom is one well-known API protocol that adheres to this rule. But there are very few other APIs that are so strict about resource encapsulation. (If you know of some others, please post a comment!)
The Hyperspace Between Us
In one notable post, David Hansson gives some counter-arguments, explaining why many API developers find it impractical to hide the details of URIs altogether. He does recommend using fully-formed URIs in hyperlinks, rather than requiring the client to construct a URI from out-of-band knowledge (i.e. a URI or a static URI template, pre-defined in API documentation). But he points out that this recommended practice provides only limited benefits, and doesn’t make it practical for API providers to change URI schemes on a whim.
In Taming the RESTed NARWHL (slides here), Rob Zazueta argues for consistent, intuitive, directly accessible endpoint URIs. Rob cites a number of specific reasons for this, one in particular that doesn't become obvious until the API is in production: human-readable URIs make it easier for client and service developers to comprehend log output and diagnose problems.
In the same talk, Rob recommends using media types for application semantics, versioning and content negotiation. NARWHL occupies a middle ground in resource encapsulation, embracing API design conventions that provide rich machine-readability and helpful transparency to developers, wherever possible.
In this series of posts, I’m not taking positions on these debates. This is about understanding what it means for an API to be hypermedia-driven, strictly in accordance with REST principles. As we continue this conversation, we’ll see how this plays out in other important aspects of API design.
Next up: the processing model, which defines how clients can interact with representations using hypermedia controls.