Brad Jones has his fingers on so many pulses that I imagine him beavering away in his leguminous clinic. So when he said to me last week that my last post would really help people familiar with REST to see what ROC was about it made me think. I realised that the aim was valid but that it wasn’t really well addressed despite Brad’s enthusiasm. So of course I better do something about that!
Fielding’s well referenced thesis approaches the definition of REST through the application of constraint. Let me quickly recap on those because further constraint will serve us well in helping define ROC:
- Client-Server - separating a client who desires a service from a server providing services by some requesting mechanism creates a separation that enables loose coupling and independent evolution of each.
- Stateless - server maintains no conversational state for each client between requests. This leads to increased visibility of what each independent request is doing, better reliability to partial failure and increased scaling of the server.
- Cache - responses to requests must explicitly state if they can be cached or not. Then a client or intermediary can reuse a response rather than re-requesting. This reduces server and network load.
- Uniform Interface - probably the most distinguish constraint of REST is that each service cannot define an arbitrary interface but must conform to a set of rules. These rules are that requests must have a resource identifier, that representations must be used to manipulate the resource, that messages (requests/ responses) must be self descriptive enough to describe how to process the message without additional knowledge1 and finally that state transitions in the client should be followable from hyperlinks within response representations.
- Layered System - it is possible to build a hierarchy of opaque layers to perform functions such as encapsulating sets of services and clients, load balancing or providing firewalls.
- Code-On-Demand - this optional constraint says that additional understanding and processing of responses can be performed by the client by downloading code or scripts from the server.
All of these constraints apply to ROC with the possible exception of the final optional constraint Code-On-Demand. In the context of a browser it makes sense to provide the user with a richer canvas to convey a representation. But within the context of ROC whose intent is to provide an environment for computation returning code to be executed by the client is not particularly useful but is not prohibited.
At this point it is probably worth dwelling on the intent of ROC. ROC was born out of the desire to gain the economics of web systems in computation systems. When we tried to implement software to fulfil the roles of client and server in networked systems we saw a great dissonance when the principles that lead to long term evolution of the web were interfaced to the tight but brittle inner workings of typical enterprise software stacks. We sought a way to take the web’s principles and make them scale invariant such that they could be applied past the network boundary and down into the smaller scale internals of the nodes on the network. Surprisingly the REST constraints don’t prohibit this application despite the overwhelming majority of discussion of REST being in relation to the HTTP protocol. We have defined additional constraints which guide REST to work in an effective way at this smaller scale:
- Messaging-Middleware - a messaging middleware provides a substrate for clients to issue requests to that will resolve to and invoke services. Having a common intermediary between requests enables extrinsic capabilities such as asynchronous threading and caching.
- Addressing-Is-Relative - an address space - or spaces as ROC calls them - provides a home for clients and services. Each space is a set of services providing resolution to resources. Many spaces can exist within a system and services can act as gateways from one to another. This leads to modularity within systems so that sub-parts can be replaced, upgraded or co-exist with older versions as needed.
- Data-Structures-As-Representations - a representation passed within a request or response may be an arbitrary but immutable data structure or object. (Immutability stops back-channel communication.) Using data structures rather than binary data streams leads to great efficiencies that are needed when the granularity of requests is reduced.
- Transreption - the middleware may invoke services called transreptors which can convert from one representational form to another based upon the requested form and the returned form. This enables looser coupling by not tying server and client implementation technologies together.
- Server-Is-A-Symmetric-Client - both clients and services are components - ROC calls them endpoints. Services can act as clients by issuing sub-requests. This can lead to functional decomposition as a top level request fans out to a recursive tree of sub-requests allowing the ROC abstraction to be implemented down to the finest scales of the system.
- Identifiers-As-Function-Invocation - a specific form of identifier whose syntax allows nested identifiers enables the specification of resources which are the computation of software functions with specified argument resources. Though optional, application of this constraint on service-like resources leads to great flexibility and avoidance of the usual URI escaping and ordering issues that can arise.
I’ve deliberately not gone into too much detail about each of these constraints. I want this list to act as a taster of what is available to explore if you download NetKernel.