Most articles on REST seem to focus only on APIs. This view misses several key benefits of a RESTful system. The true potential of REST is to build systems as scalable, distributed, resilient, and composable as the Web. Yes, APIs play a role in this but by themselves are not enough. In this two-part post, I will discuss how you can leverage all REST architecture constraints in your systems:
Rest is not about APIs, Part 1: Description of REST and the API-centric view
Rest is not about APIs, Part 2: The true power of REST, and examples of its application
Brief Description of REST
REST (short for REpresentational State Transfer) is an architectural style that describes how a distributed hypermedia system works. The internet (or “the web”) is the best known example of a distributed hypermedia system. The term REST was introduced by Roy Fielding. His doctoral dissertation [1] remains the go-to source on REST from which I have summarized below.
REST is described using 6 architectural constraints, 4 interface constraints, and 3 architectural components.
Architectural Constraints
- Client-server: separation of client & server roles i.e. the representation of resources from their stored state.
- Stateless: the server should not store or cache client state across requests. Each client request should be transition the stored data from one valid state to another. This allows any available server instance to be used to fulfill any request.
- Cache: the server should indicate if data can be cached and reused across requests.
- Uniform Interface: all server data can be manipulated using the same interface. This constraint further expands into four interface constraints:
- identification of resources: all resources have one or more names (e.g. HTTP URIs) managed by the naming authority (typically the server).
- manipulation of resources through representations: The representation of a resource is separated from its identify and can change over time.
- self-descriptive messages: the messages should contain metadata that describes how to read the message (e.g. HTTP MIME types and other headers).
- hypermedia as the engine of application state (HATEOS): Representations should also contain data to drive application state. This allows clients to be loosely coupled to servers, and require no prior (hard-coded) knowledge of how to interact with a particular resource.
- Layered System: each layer deals with the one below it, and has no direct visibility to other layers.
- Code on Demand (Optional): the server can extend the client functionality by sending back scripts or code.
Architectural Elements
- Data Elements: data elements allow information to be moved from where it is stored to where it will be used. Data Elements are described by Resources, Resource Identifiers and Representations.
- Resources: are things that can be uniquely named (e.g. a HTML page or image on the Web, or an Object instance in an application.) A request for a resource can return a representation or a set of resource identifiers, or a combination of the two.
- Resource Identifiers: are the names given to resources (e.g. a HTTP URL.)
- Representations: a representation is what gets transferred between REST components.
- Connectors: connectors encapsulate the activities of accessing resources and transferring representations.
- Client: a Client initiates requests for information.
- Server: a Server listens for, and responds to, requests
- Cache: a Cache can be attached to clients or servers and is used to speed up interactions.
- Resolver: a Resolver helps find resources to establish inter-component communication (e.g. DNS bind)
- Tunnel: a Tunnel allows interactions across network boundaries like firewalls.
- Components: components are the different roles in a system. Components use one or more Connectors for interactions with other components.
- Origin server: uses a server connector to manage a collection of resources.
- Gateway: a gateway component is a reverse proxy. It performs common functions across servers, such as authentication.
- Proxy: a proxy is an intermediary component selected by the client, to perform common functions.
- User agent: uses client connectors to initiate requests, and receive resource representations from servers.
The API-centric view of REST
The API centric view on REST focuses only on the uniform interface constraint. For the most when APIs are discussed the assumption is that these are external facing APIs (northbound from the perspective of the application). A RESTful external API is a nice addition for software products, and can fulfill a business need. However, it does not address product maintainability and other architectural challenges like elasticity, resilience, and composability.
The Richardson Maturity Model (RMM) [2] is a popular way of measuring how RESTful an API is. The RMM is useful to qualify whether the API has REST characteristics, but does not imply a RESTful system. ip domain info In a blog post describing the RMM [3], Martin Fowler notes:
“I should stress that the RMM, while a good way to think about what the elements of REST, is not a definition of levels of REST itself. Roy Fielding has made is clear that level 3 RMM is a pre-condition of REST. Like many terms in software, REST gets lots of definitions, but since Roy Fielding coined the term, his definition should carry more weight than most.”
-- Martin Fowler, Richardson Maturity Model
(See [4] for Roy Fielding’s post that Martin is referring to.)
Most RESTful API implementations layered on top of existing systems, have a difficult time with the HATEOS interface constraint. They end up adopting “pragmatic REST” [5]. Getting the HATEOS constraint right requires both the server and client to be designed for this type of interaction, like a web browser and a web server.
If you are trying to add an RESTful API to an existing application, this will be hard to do. However, if you can design for HATEOS the potential payoff is huge as you will have a loosely coupled system, where server-side changes do not easily break the client. [6]
Summary
In this part, we discussed what REST is and why the API centric view is not sufficient. In the next part we will cover how to use all of REST to build a systems as flexible as the web.
References
[1] Representational State Transfer (REST), Roy Fielding, <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm</a>
[2] Richardson Maturity Model, Leonard Richardson Presentation 2008, <a href="http://www.crummy.com/writing/speaking/2008-QCon/act3.html">http://www.crummy.com/writing/speaking/2008-QCon/act3.html</a>
[3] Richardson Maturity Model, Martin Fowler, <a href="http://martinfowler.com/articles/richardsonMaturityModel.html">http://martinfowler.com/articles/richardsonMaturityModel.html</a>
[4] REST APIs must be hypertext-driven, Roy Fielding, <a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven</a>
[5] API Design: Harnessing HATEOAS, Part 2, <a href="https://blog.apigee.com/detail/api_design_harnessing_hateoas_part_2">https://blog.apigee.com/detail/api_design_harnessing_hateoas_part_2</a>
[6] Haters gonna HATEOAS, <a href="http://timelessrepo.com/haters-gonna-hateoas">http://timelessrepo.com/haters-gonna-hateoas</a>