Sound advice - blog

Tales from the homeworld

My current feeds

Mon, 2008-Oct-06

REST Model-View-Controller (cont.)

My last article introduced the application of model-view-controller to REST client and server design. I thought I would expand on that material a little further, and provide some diagrams as food for thought.

The REST Triangle

The first thing I would like to do is re-introduce the REST triangle, roughly in line with the terminology I have been preferring of late.

REST Triangle

When I first introduced the triangle we were all talking about nouns and verbs, and the obviousness of preferring to have more nouns than verbs. Honestly, I think it caused as much confusion as it did clarity. The obviousness is hard to draw from a set of natural languages that have a lot of both nouns and verbs, and the analogy doesn't really help people come to grips with the impact on their architecture.

Instead I have been tending to talk about Resources and Patterns, URLs and Protocols. Resources are network-exposed objects, and tend not to be that easy to grasp until you relate them directly to the concept of URLs. People get URLs. They understand what they look like and roughly what they are for. If you can stick to that end of the story you shouldn't get too much blow-back.

I prefer Patterns to "verbs". I think the verb or method concept is too low level, and doesn't really give an architectural feel for why limiting them is useful. Patterns on the other hand give in my view about the right feel for the real architectural motivation. People understand that you want to catalogue and reuse patterns. Every message exchange is part of some sort of pattern when you operate over an unreliable network. There are always message retries or redirection, or an imperative not to retry, etc. Communication at this level is hard for the uninitiated, and keeping to a fixed set of well-understood set of patterns only makes sense.

Part of the Uniform Interface constraint is that patterns are baked into protocols. You don't talk about a GET pattern, then make up a new method every time you apply it. You make the method name match the pattern. This bypasses much of the service discovery jiggerypokery that you would otherwise have to do. If you already know what pattern you want to apply, and the server supports that pattern, then you know which method to call. After that it is just a matter of making sure you have the right URL in hand to complete the request.

It almost goes without saying, but I'll say it anyway: Any pattern in REST architecture must of course conform to REST principles. That does not mean that the set of patterns is fixed by any means, but we have gotten away with surprisingly few patterns so far.

Squeezed away in the corner there you might call Content Types, but that doesn't really mean much to many people. I tend to call them document types these days. That has a reasonable mapping for most people to what we really mean when we talk about document types: An Excel document isn't much use to Word. A Word document isn't much used to Powerpoint. They are different document types.

The separation of Document Types and the patterns that transfer documents around the network is evolvability gold. You can introduce new kinds of information into the architecture as new document types without breaking your existing infrastructure for moving documents around. However, we also want to catalogue and reuse Document Types. We want to reuse our parsers and generators. We want to reuse our human understanding of what a particular document actually means. Your patterns will likely even let you negotiate between client and server to ensure that everyone can relate the conversation to a document type they were designed to understand.

Coding the Triangle

By no means is there only one way to implement a service or a client. One of the big selling points of REST and SOA generally is that they can operate in a heterogeneous environment where different technology and approaches are used on either side of the client/server divide. With that in mind, let's look at what I would consider a basic "body plan" for a REST client and server. I'll focus on an application of the GET pattern for purposes of example, but the same plan fits any pattern you would care to mention.

REST MVC Body Plan

Model-view-controller as a pattern means many things to many people in many different contexts. Its exact meaning has been somewhat eroded over time and replaced with specific variants for special situations. The overall goal of the pattern, however, has not changed: Isolate appearance from implementation. Separate application logic from the constraints of how that logic is presented to users and to other applications.

Down the middle of my plan I have placed the corners of my REST Triangle. I have the set of Document Types in the architecture. I have the set of Patterns and Protocols. I have the set of Resources or URLs in the architecture. These are abstract entities included to give the diagram a bit of context. Each resource participates in a defined subset of the architecture's overall set of Patterns and protocols, and provides the public face to application logic behind the scenes between client and server.

Down the bottom right and left corners of the diagram I have the client and server model components. These components rightly do not depend on anything and do not play any public role in the message exchange. They are shielded from view by their respective Controllers.

The client controller includes code to pilot a pattern's state machine from its initial to its terminal state, despite possible adverse network conditions along the way. Lost response? Retry the request. Redirection? OK, follow if it looks reasonable. Fail the pattern if it looks dodgy. Positive response from the server? You beauty. Process the response.

The role of the server controller is quite different. It will include objects in its scaffolding to handle requests to any of its Resources. That might mean one object per resource. More likely it will mean an object tree with parameters along the path that collect a number of different resources together. These parameters will be passed into the appropriate function on a scaffolding object.

Let's say our request was a GET to https://example.com/light-bulb/1234. Chances are the request would arrive at a function internally identified as something like Resources.light_bulb.get(id). The controller component will then consult its model as part of fulfilling the request:

Resources.light_bulb.get(accept, id):
	bulb = Model.get_bulb(id);
	return Transform.to_acceptable(accept, bulb.status);

As well as consulting the model, this server consults its set of transforms. It wants to return information about the light bulb in a form that the client understands. Therefore, it uses the accept header from its request and passes it through to the Server Transforms component. Multiple controller functions may return the same Document Type and make use of the same transformations to prepare the returned document.

Once returned, the client will also apply its own transform to the document. Its objective is to map the document into data structures that be easily applied to its own model.

Conclusion

Client and Server Controllers deal with the set of Resources and the application of Patterns and Protocols. The Models of each will be queried and updated as part of the transaction, and the Server Model contributes to the set of Resources by containing objects that can be looked up through the Server Controller. Transformations at both end relate documents to model-ready data, and model data to documents.

Fri, 2008-Oct-03

Model-View-Controller with REST

One of the big questions I think the REST software community are facing at the moment relates to what REST support we should expect from vendors, and what good REST support looks like. I have been taking a lead from web frameworks such as Ruby on Rails, and Gears.

Model-View-Controller means many things to many people. Most of those people will agree that it is a good idea, even if they aren't quite sure what it means for them in their environment.

A classical GUI application would employ application logic in a model, and its view would be a set of widgets on the screen. A controller object either intercedes when events come in from one or the other, or links the two together at display call-up time.

The prevailing wisdom in the world of server-side Web frameworks is more something along the lines of:

This works well in the common environs of web servers today. Anything that is strictly application logic that you might want to port to another framework one day appears in the model. Any routing of requests, filtering, or other request handling operations appear in the controller. Views allow complex web pages to be built in a template form that the controller can populate with model data.

Success on the Server side: The Controller

I have to say that I am a fan of request routing of the form found in Rails. It is appealing to me to map a GET of https://example.com/objects/{id} easily and efficiently to the getObject(id) function within the controller. It gives a reasonable degree of flexibility in relating URLs to internal controller objects, and places the list of URLs exposed by the application and their methods in an single easily-accessible and readable place. The rails implementation might include a little bit too much magic under the covers, but the central idea to my mind is clearly valuable.

Success on the Server side: The View

The views component is also useful in talking about how we move from RESTful web sites to RESTful services. The biggest change I would make here is to look at it as a two way set of transformations. It is just as important to easily process the document from a PUT request as it is to be able to produce a document in response to a GET request. Machine-to-machine communications common to services also tend to be more structured than HTML. The concept of a template per se is of diminishing use as we move headlong into structured XML payloads, so it is probably more important to include a generic data mapping tool something along the lines of an Altova Mapforce.

Success on the Server side: The Model

The model is perhaps the most interesting component of the MVC pattern. In many ways the model could be the whole of a classical SOA service. Previously you would have had (say) an EJB Session Bean as the front-end of your service. You would expose methods on this bean that operate as a thin controller object over the entities in your model.

It seems like writing a well-designed REST service involves writing an additional layer on top of the classical SOA service. You add a controller and its set of data mappings to what you might otherwise have exposed directly to the network. In doing so you gain the benefits of a uniform interface. The implementation is still Object-Oriented, even if the interface is uniform. Just like the implementation of an object's method is still rooted in the structured programming world while the interface to the object is clearly O-O. It is the vendor products that ease the development of this additional layer of abstraction that will be most useful for REST service development.

Success on the Client Side

The client-side interfaces that provide the most leverage will be the ones that cleanly separate data mapping from communication patterns, and most cleanly expose the patterns themselves to users. Built into these patterns will be any retry mechanisms, redirection, content negotiation, etc. The client won't have to deal with individual HTTP response codes. These will be baked in.

Consider a standard GET pattern. The client application code will simply say: I want data from that URL over there, and I'm using this data mapping to interpret the results. The data mapping will inform the pattern which document types it supports as input, and the pattern will do the rest. It will either reach a success or fail terminal state, and inform the application code client of that fact.

Benjamin