Sound advice - blog

Tales from the homeworld

My current feeds

Sun, 2010-Oct-03

REST service discovery

is a discipline within computer science that seeks to maximise business value firstly by encapsulating reusable logic and data within well-defined and easily accessible services, and then secondly by actually reusing these services. A service-oriented architecture distinguishes between logic that will not be reused (application logic) from logic that is reusable (service logic). Service logic is reused from application to application as business needs change to avoid reinvention of the wheel, reduce time to market for new applications, reduce the maintenance costs associated with having redundant implementations of reusable logic, and increase the return on investment of reusable logic by amortising costs over a series of applications.

Service-orientation is set up in opposition to traditional silo mentalities of software development where application development teams do not talk to each other across an organisation and where each new application is built up often completely from scratch based on whatever third-party or language framework tools are available.

A major focus of the architectural style is on building a uniform contract that decouples services from their consumers, decoupling consumers from individual service contracts. What service-oriented folks see as loose coupling "I'm depending on a service's contract, but I have abstracted it to a degree where the service is able to evolve and even change technology foundations without breaking the contract", REST folk see as tight coupling "Your consumer can only talk to a single service?? You have to rewrite your consumer each time you swap one business for another within your supply chain??".

REST would have us depend only on a uniform contract in order to access the capabilities of a service. Consumers at design time should not know the details of any particular service contract. Instead, they should be written against the uniform contract based on a generic conceptualisation of the capabilities a service might offer.

The classic example of this approach can be found in the Web browser. A user types in a browser address, then navigates from page to page regardless of what service is being offered. The browser doesn't have to be rewritten in order to navigate from yahoo to google, or from facebook to the library of congress. Defining a uniform contract means that the technology part of the equation - the web browser - is able to interact correctly with whatever it is directed to interact with. If the browser knew the contract of the services it was dealing with ahead of time it would become tightly coupled to these services and browsing as we know it would end.

But let's take another look at this vision of browsing. Some REST proponents would suggest that we have eliminated the service contract in this model. We have substituted it for a reusable uniform contract shared by all services on the Web. I disagree with this notion entirely, and say that the service contract remains. It is captured in the individual unqiue sets of URLs each service offers that expose its service capabilities. "getGoogleSearchForm(): SearchForm" has simply been substituted for "GET https://google.com/: text/html". The same underlying capability continues to exist and still has a unique form of addressing available to invoke it.

We can take this view further: Say that I deduce from the form that I can submit a query of "GET https://google.com/search?q=test", what would happen if this resource stopped working or changed its semantics? Well, my operation certainly wouldn't work. This is a contract that if broken will have significant impacts on service consumers. This is the service contract.

So we can take a step back, and say that while service contracts still exist in REST we discover these at runtime. Service consumers don't hard-code knowledge of these capabilities at design time, do they?

Well, in some cases they do. Web browsers these days will almost certainly be hard-coded with knowledge of the URL they need to upgrade themselves when they are out of date. When a web browser is installed on my computer it is almost certainly going to have a "home page" and a set of default bookmarks to access. In fact, quite a bit of contract information is built into a web browser at design time. Much of this can be tailored or replaced at runtime, but nevertheless it is there.

It is this observation that is perhaps most powerful in determining how we should publish the contracts of our RESTful services, and how consumers that are more automated than a typical web browser should discover services and their contract. Discovery of services by developers of automated consumers is critical to the goals of service-orientation in achieving actual reuse of service logic. If the developer of a new application is unable to discover existing service logic and learn effectively how to use it then it is doomed to be reinvented and the silo mentalities continue within your organisation.

REST Service Discovery

The figure above shows a basic model for discovering services within a REST context. We start out with the publication of each service's contract. This is essential in order to achieve reuse of service logic. This doesn't necessarily have to be the whole contract, but has to be sufficient for any service consumer that is previously unequipped with service URLs to discover any other URLs it may need to access over its application lifespan. Key elements of the published service contract for each service capability will be:

  1. The uniform contract method that will be used to invoke the service capability (e.g. GET or PUT)
  2. The URI Template to be used in invoking the capability (e.g. https://google.com/search?q={query} or https://soundadvice.id.au/)
  3. The uniform contract media type alternatives that are supported for the capability (e.g. text/html or application/vnd.com.example.invoice+xml). Multiple alternatives may be present, using content negotiation to select the most appropriate form for information exchange in any given interaction
  4. Sufficient human-readable semantic information for the application developer to understand the capability and validate it as applicable to their needs

The next step is performed by the application developer. The developer would scan a registry of services and related capabilities in order to find one or more that will reduce the cost of developing their application.

Steps 3 and 4 can occur in parallel. (3) is reasonably easy to understand. It is figuring out how to use the uniform contract correctly within the service consumer. In a perfect RESTful world this might be the only step between these two that we would take. It involves studying the specifications for uniform contract elements used by this service and determining how to build the logic of the service consumer based on these specifications. If we find a blog service we might determine that we are going to use GET requests to the service's URLs and make sure we are able to process application/atom+xml responses in return. We might choose to understand a subset of link types in order to discover related URLs and do things like fetch the contents of podcasts and vodcasts on behalf of our user.

By depending only on the uniform contract while determining these key details we are able to remain loosely coupled with the service we initially discovered. If another service happens to reuse those same uniform contract details our consumer can use the capabilities of that other service without needing to change its logic at all. It just needs to select different URLs to go and interact with. When our consumer follows those links it knows how to understand it doesn't care what service is actually offering the links. It just navigates from resource to resource using the uniform contract as its guide as to how to interact correctly.

Step (4) kicks in wherever the uniform contract detail is insufficient to base our service consumer upon. Typically this step does not specify how to build the logic of the service consumer, as step (3) did. Instead, it defines what the configuration file for our service consumer will look like. It preconfigures the consumer with a set of resource identifiers, and sufficient semantics to figure out what to do with these configured URLs. Typical web browser examples include "home page" - the page you open when you start. "bookmarks" - the links and titles to put in the bookmark folder for the user to select. In a more automated world these URLs might be attached to semantics such as "source of data for your reports", "resource to check to see whether operation xxx is permitted", or "place to store to when you want to launch your nuclear missiles". The semantics of these URLs embedded within the configuration file are abstractions of the semantics of the service contracts they came from. The more of an abstraction from the service contract, the more loosely coupled this service consumer will be from the service. In REST we are seeking to minimise this coupling wherever it could appear, and maximise dependency on uniform contract elements instead.

When we have completed (3) and (4) we move on to implementing the service consumer. We should be able do this based on the briefs produced in analysing the service contract and its related uniform contract elements. Developers of the service consumer should not have directly reference the service contract itself. They should especially avoid embedding specific URLs or URL templates that have not been through some process of review and abstraction prior to implementation. In a REST-style SOA services are discoverable, but consumers are able to freely navigate and be reconfigured to interact with the capabilities of other services as required.

Benjamin

Fri, 2010-Aug-13

REST-compliant service contract notation

and are traditional rivals for developer mindshare. Despite this I think they have a lot in common, and in my view a fair amount that each opposing camp can teach the other. I have been looking forward to the convergence between these camps and their styles for some time now, and I have been working on a title called SOA with REST with several other authors that explores this intersection. My understanding of the intersection of REST and SOA has evolved and expanded over this time to a point where I comfortably use some of the techniques of service-orientation to build and define REST architecture. So much so, that the line between what is REST practice and what techniques are from service-orientation have somewhat blurred.

Today I wanted to take the gentle reader through a few basic concepts of the uniform contract: How to define and build services that are compliant with the REST uniform interface constraint, but are able to express their unique service capabilities. I have approached this subject from a few different directions in the past, but this time around I particularly wanted to cover what it means to talk about service contracts within the context of the REST uniform interface constraint.

From a SOA perspective, compliance with the uniform interface constraint requires that across our service inventory (or a significant proportion thereof) we are able to define a single technical contract that can be used to access any resource. This constraint increases integration maturity of a service inventory by allowing one resource to be substituted for another by service consumers at runtime as required. It allows service consumers to discover a resource at runtime that they wish to interact with, and to interact with it correctly without changing any of its logic and without introducing any kind of glue logic. At the same time it replaces the conventional single "service endpoint" with often infinite sets of resources that each form a lightweight endpoint for the service.

The uniform interface constraint simplifies the architecture by reusing very general contract elements that services, consumers, and middleware can all understand and participate in effectively. This initially reduces performance, but leads to improvements in scalability and other architectural properties by allowing middleware such as proxies to be involved in scrutinising and supporting network interactions. It can massively reduce coupling within a service inventory and allows for extremely simple dynamic reconfiguration of service compositions.

I see part of the friction between the two camps as coming down to a lack of shared terminology when talking about services, contracts, and interfaces. I would like to see if I can clear this up a little with a few diagrams:

Uniform and Service Contracts

This first diagram shows the key elements of the uniform contract, and the relationship between a uniform contract and a service contract. There are a number of key points to draw from it.

REST advocates will have immediately picked up the obvious extension of a conventional uniform contract with the service contract concept. This is a startling inclusion and one that deserves explanation. Let me begin this explanation with another diagram:

REST-compliant service contract realisation

This diagram shows a simple REST-compliant realisation of an abstract service. The high level capabilities that analysis suggested this service needs were the capability to convert from degrees Fahrenheit to degrees Celsius, and the corresponding capability to convert back again. These capabilities were refined through reference to the uniform contract into a service contract suitable for use in a REST-style SOA. The name of the service is the same as the authority of the service's resources (converter.example.com) to ensure maximum autonomy of this service. Resources in the contract are identified relative to the identifier for the service.

The actual contract definition can be written in many different ways, but I find this one is easy to use to communicate with people from either an object-oriented or a service-oriented background. What this notation does is to provide a clear service boundary for the REST-compliant service, a clear identification of the service capabilities (which remain readable), and a clear relationship to facets of the uniform contract.

The service capabilities in this case have been refined as:

It is clear from a REST perspective that what we are doing is specifying the resource identifiers that the refined service provides to its consumers. It is normal to expect that a REST-compliant service will define its own resource identifiers to use in conjunction with the uniform contract facets. These resource identifiers provide business context for generic and abstract methods such as "GET".

In the example above we are promising to support a GET operation to two distinct families of resource identifiers. One set will return the number of degrees Celsius for a Fahrenheit value, and the other set will do the reverse. Both will return their result as a simple text-formatted number. Each different value that can be input to the service is embodied in a different identifier, so each refined capability is actually defining a family of resources.

Conclusion

Services and consumers are more loosely coupled with each other in a REST-style SOA than in a conventional SOA. While SOA always encourages the use of loosely-coupled contracts to support implementation changes behind the contract, REST encourages us to abstract the consumer away from design-time knowledge of the service contract itself. Service consumers and middleware are coupled to the uniform contract, and are sufficiently abstracted from specific service contract details to be reusable from service to service.

With this objective in mind, I think it is useful to talk explicitly about service contracts as an element of REST. We need to talk about them because they are important in governing, developing, maintaining, and supporting REST-compliant services. We need to talk about them so that we can offer explicit guidance about what constitutes coupling of a consumer to a service contract. We need to talk about them so that we can point to patterns that help build the loosely-coupled architectures that REST demands.

If we are able to explicitly talk about service contracts, we will be in a better position to understand how they shape our service inventories and our architectures.

Benjamin

Fri, 2010-Apr-02

SOA With REST Patterns preview

I have been working on a book for some time now with Raj Balasubramanian, Thomas Erl, and Cesare Pautasso (in alphabetical order). The title is SOA with REST and it is something I am pretty excited about being able to share with the world in the coming months. I'm sure that it will cause a few second takes on both sides of what has traditionally been a political divide between the and camps, and I see this as a good thing. SOA with REST is intended to be a roadmap for bringing REST and SOA experience together into a cohesive conceptual framework and to allow adults to have adult discussions about what REST means to SOA and vice versa. I see the book as describing an architecturally pure yet also practical approach to the REST style and the SOA model.

Some attendees of last year's SOA Symposium will have gone home with a gallery of chapters from the book. For the wider audience we now have parts of our patterns chapter available as candidates in the catalogue at soapatterns.org. The set of patterns is partially based on trying to explain some of the REST constraints in a patterns language, and partly derived from Web experience. The published candidates are:

Uniform contract
A partial explanation of the whys and wherefores of the Uniform Interface constraint.
Entity endpoint
Why do we address resources in REST, rather than whole services as endpoints?
Entity linking
What is the point of hyperlinking in REST? (hint: Combine with uniform contract and entity endpoint to achieve runtime service discovery)
Message-based state deferral
How does REST ensure services are stateless between requests if it doesn't allow us to defer state to session databases or session management services?
Response caching
How does REST overcome the loss of publish/subscribe and other event-based communication patterns due to client/server and stateless constraints?
Endpoint redirection
How does the Web support services in deprecating old resources?
Content negotiation
How does the Web simultaneously support old and new service consumers as its uniform contract changes over time?
Code on demand
How does REST defer processing to service consumers, and allow consumers to be extended and customised as required by services?
Consumer-processed Composition
What does a typical service composition look like on the Web, anyway?
Idempotent capability
How does the web statelessly provide reliable messaging when there are no humans in the loop? (hint: idempotentcy is one half of the solution, and waiting until the last response has come back before you send another request that depends on the previous succeeding is the other half of the solution)

Benjamin

Fri, 2010-Apr-02

Programme for WS-REST 2010

The programme for WS-REST 2010 has been published

I am especially looking forward to the presentation of Federico Fernandez and Jaime Navon's paper, "Towards a Practical Model to Facilitate Reasoning about REST Extensions and Reuse"

I would like to put out a big thankyou to everyone who submitted.

Benjamin

Sun, 2010-Jan-17

WS-REST 2010

Do you have something to say about the advancement of the REST architectural style?

Come and present at the WS-REST 2010 first international workshop on RESTful design.

As a member of the programme committee I would like to echo the call for papers and encourage high quality submissions. Take care! If it's not REST I'll call you on it! This workshop will deal with REST design topics, the use of REST in novel ways, novel patterns for integrating REST with non-REST architectural elements, and the bridging of cultural and technical divides between REST and non-REST crowds. Don't be put off by the cheeky title. I assure you, it is about the advancement of the REST architectural style.

Time is running out, so get your papers in by 2010-02-08.

Benjamin

Sun, 2010-Jan-17

Scaling through the REST "stateless" constraint

Uniform Interface is the poster boy of the REST constraints. It attracts much of the interest, and much of the controversy. Less-often discussed is the equally important and far more controversial Stateless Constraint. Specifically, the constraint is that services in a REST-style architecture are stateless between requests. They don't carry any session state on behalf of clients that aren't currently in the process of making requests.

Services are typically near the core of a network. Network cores often have great storage, bandwidth, and compute resources but also great demands on these resources. Services are responsible for handling requests on behalf of their entire base of consumers, which on any large network will be a significant set. Nearer to the edge of the network are the consumers. Paradoxically, the resources available in the form of cheap desktop hardware and networking equipment typically have more available capacity at this network edge than is present near the network core where big-iron scaling solutions are being employed. This is due to the large number of consumers out there, typically orders of magnitude more than exist a data centre. Spare resources are relatively fast, large, and responsive nearer to the ultimate user of the system. On the down-side, nodes near the edge of a network tend to be less reliable and more prone to unwanted manipulation than those near the network core.

While big-iron scaling solutions near the core are important, any architecture that really scales will be one that seeks to make use of the resources available near the network edge. Roy envisages a architecture, where most consumers are in a "REST" state most of the time. This is a concept intrinsically linked to statelessness as well more obliquely to notions of code on demand, cache, and the Web's principle of least power.

Stateless

The first step towards a REST scalability utopia is to move as much storage space from services to the edge of the network as possible. This is a balancing act. You don't normally want to move security-sensitive storage to the edge of the network, nor store any information that you have promised to keep in the less-reliable edge nodes of the network. There is also some state associated simply with underlying transport protocols such as TCP that cannot be eliminated. However, the less information that is stored by the service the better it will be able to cope with the demands of its consumers. REST sets the bar for statelessness at the request level: No session state needs to be retained by the service between requests in a REST architecture for normal and correct processing to occur. The service can forget any such state and will still understand the consumer's request within the session.

The scalability effect of this constraint is that session state is moved back to the service consumer at the end of each request. Any session state required to process subsequent request is included in those subsequent requests. The session state flows tidally to and from the service rather than being retained within the service. Normal service state (information the service has promised to retain) still resides within the service and can be read, modified, or added to as part of normal request processing. I have written before about the difference between session state and service state, so I won't go over that ground again today.

Applying this constraint has positive and negative effects. On the plus side, the service must only provision storage capacity sufficient deal with its own service state. It no longer has to deal with a unit of session state for each currently-active service consumer. The service can control the rate at which it processes requests and only has to cope with the session storage requirements of those it is currently processing in parallel. It may have a million currently-active consumers, but if it is only processing ten requests at a time then its session storage requirements are bounded to ten concurrent sessions. The other 999990 sessions are either stored within the related service consumer or are currently in transit between the service and related consumer. Sessions are expensive for services to store, but cheap for consumers. Session state is also often invalid if the consumer terminates, so if the session happens to be lost when this occurs there is typically no negative effect.

The negative impacts of statelessness include the extra bandwidth usage for that tidal flow of state, as well as the prohibition of really useful patterns such as publish/subscribe and pessimistic locking. If the service is able to forget a subscription or forget a lock, then these patterns really don't work any more. These patterns are stateful and force a centralisation of state back to services near the network core.

Cache

is often talked about as a scalability feature of REST. However, it exists primarily to counter the negative effects of stateless on the architecture. Stateless introduces additional bandwidth requirements between services and consumers as session state is transferred more frequently, and we may have additional processing overhead on the service to deal with consumers polling for updates when they previously could have made use of a stateful event-based message exchange pattern. Caching seeks to eliminate both problems by eliminating redundant message exchanges from the architecture. This reduces bandwidth usage as well as service compute resources down to the minimum possible set, ensuring that the stateless architecture is a feasible one.

A cache positioned within a service consumer reduces latency for the client as it makes a series of network requests, some of which will be redundant. The cache detects redundant requests and reuses earlier responses to respond quickly in place of the service. A cache positioned at a data centre or network boundary is principally concerned with reducing bandwidth consumption due to redundant requests. A cache positioned within the service itself is primarily concerned with reducing processing overhead due to redundant requests.

The Web's principle of least power and code on demand

Now that we have moved unnecessary storage requirements to the edge of the network and reduced network bandwidth to a minimum, the obvious next step is to try and reduce our service-side compute requirements. The Web offers its standard approach of the . This principle essentially says that if you provide information instead of a program to run that consumers of your service will understand the content and be able to process it in useful and novel ways. The compute implication of this is that you will often be able to serve a static or pre-cached document to your consumers with practically zero compute overhead. The service consumer can accept the document, understand it, and perform whatever processing it requires.

REST adds the concept of code-on-demand. While something of an anti-principle-of-least-power, it serves more or less the same purpose as far as scalability is concerned: It allows the service to push compute power requirements out to the edge of the network. Instead of actually executing the service composition, a BPEL engine could simply return the BPEL and let the consumer execute it. Hell, it could happily drop the BPEL processor itself into a virtual machine space offered by the service consumer and run it from there. So long as there is nothing security-sensitive or consistency-sensitive in the execution you have just saved yourself significant compute resources over the total set of capability invocations on the service. If you are lucky, the files will already be cached when the consumer attempts to invoke your capability and the request won't touch the service at all.

The Web's use of applets, javascript, html, and pretty much everything else it can or does serve up demonstrate how compute resources can be delegated out to browsers and other service consumers in order to keep services doing what they should be doing: Ensuring that the right information and the right processing is going on without necessarily doing the hard work themselves.

Conclusion

Between the offload of storage space offered by the REST stateless constraint and the offload of compute resources offered by code on demand and the principle of least power, REST significantly alters the balance of resource usage between services near the core of the network and service consumers nearer to the edge of the network. Service consumers place no demands on bandwidth, cpu, or storage except when they have requests outstanding. Services are able to control the rate at which they process requests, and the network itself controls the bandwidth that can be consumed by requests and responses. Caching ensures this approach is feasible in most circumstances for most applications. If you are considering investing in additional hardware scaling mechanisms, make sure you also consider whether applying these architectural constraints would also make a difference to the scalability of your services.

Benjamin