REST In Plain English (68H)
A lot of high-minded theory floats around the REST concept, but what is it practically? (68I)
Architectural Styles (69J)
In the software world we talk about design and we talk about architecture. Sometimes we try to make a formal distinction and sometimes we go by gut feel. The gut feel we should be going with for REST architectures is that web-style interactions between clients and servers are architecture. The behavior of the client and server software internally is design. (69K)
REST is not about design. It is about architecture. REST is a set of rules that an architecture should conform to. Because it doesn't go into enough detail to define an actual architecture we call it an architectural style. The Web is an example of a real architecture that roughly follows the REST rules. To understand these rules we have to have a picture of an unconstrained architecture. (69L)
Jargon File: (69M)
- The REST architecture rules are called "constraints" (69N)
The Unconstrained Architecture (69O)
An architecture is built up of different designed pieces. These designs interact with each other in various ways. You can picture the unconstrained architecture as allowing messages to be sent between the designed pieces willy nilly. Any piece can send a message to any other piece and the rules of what the message means or how the message is handled are completely up to the sender and receiver. (69P)
It isn't surprising that an unconstrained architecture has its problems: (69Q)
- The chances that two arbitrary designed pieces can be put together and work are almost zero. Unless each one has special knowledge of the other's conventions it would not be able to construct a valid message to send or know how to handle any response. If we want these pieces to work together we need to simplify the architecture. (69R)
- The more people implementing designs the simpler and more forgiving the architecture needs to be. When the architecture is large we also need to seriously consider how we deal with changes to the architecture. Replacing all of the designs at once isn't feasible, but ensuring that a hybrid of old and new architecture versions can work together... is it even possible? (69S)
- Unconstrained interactions can also be inefficient. Is there a way we can improve efficiency to reduce the load on busy pieces and to reduce our dependency on low-latency high bandwidth networks? (69T)
Some jargon terms: (69U)
- The designs or pieces of the architecture are called "components", usually a program running on a server or across a cluster. (69V)
- Components are linked together by "connectors", usually computer networks. (69W)
- Components that work together can be said to "interoperate" (69X)
- The ability to deal with architectural changes can be called "evolvability" (69Y)
- The ability to deal with a huge network size like that of the web can be called "scalability". There are different forms of scalability: (69Z)
- A component scaling to interact directly with a large number of others, usually "horizontal scalability" (6A0)
- Introducing layers between components to shield one from the other, usually "vertical scalability" (6A1)
- Dealing with thousands of different people or interest groups controlling the individual components of the architecture, maybe "social scalability" or the "large-scale participation network" (6A2)
- Different people or interest groups are sometimes called different "agencies". A single agency can be viewed as having a single set of interests, but different agencies may have different interests or even outright competing interests. (6AK)
- When we consider evolvability it makes sense to match the "component" concept in architecture to the "configuration item" concept in configuration management. You don't have to worry about evolvability within a configuration item because you will always deploy the item as a unit, but you might have to worry about different configuration items and different versions of the configuration item... especially if they are controlled or deployed by different agencies. (6AL)
Did you know? (6A3)
- SOA doesn't define constraints on the architecture, or at least few people can agree on what those constraints are. SOA's approach like CORBA's approach before it was to enable interactions between components with minimal to no constraints. Does your SOA behave like an unconstrained architecture? Make sure your technical people understand the architectural style they are applying on top of SOA, or you will end up with a network that doesn't add the value you expect to your enterprise. (6A4)
The Uniform Interface (68J)
The "Uniform Interface" is REST's core tenet made up from several constraints. It is central to solving the problems of an unconstrained architecture. (6A5)
The unconstrained architecture allows function calls, method invocations, remote procedure calls, and other messages that are only understood by a specific server or by a small subset of components in the architecture. REST eliminates ad hoc messages and radically shifts the focus of API development towards defining pieces of information that can be retrieved and manipulated. Instead of adding special function calls or interfaces to the architecture, new services add new pieces of information to be manipulated using standard requests. All requests and responses are understood by every component of the architecture and most carry copies of their information as part of the function call. (6A7)
An example: Instead of a "turnOnTheLightbulb?" request to a server object, we have a PUT "true" to the http://example.com/lightbulb/lit object supplied by the server. The http://example.com/lightbulb/lit object also responds to a GET request that returns true or false. POST is an "add information" request that doesn't make sense for the lightbulb, nor does it really make sense to DELETE the lightbulb. So those requests would fail with a response indicating the fact. (6A8)
In this example everything is standard. The request is understood by everyone. We use a plain text content type that everyone understands as meaning an xsd primitive data type to be interpreted by the server. We identify the object using a standard url. Every part of the request conforms to the uniform interface. The only thing special about the request is the actual selection of which object to send the request to. (6A9)
It is now much more likely that we will be able to link the client who sends these requests or the server that handles the request to other components of the architecture. For example, we can easily take this client and link it to other services that have true and false states. It could schedule start and stop times for lightbulbs or control Uninterruptable Power Supply switch status to power down server room equipment at night. The server could be controlled by the scheduling client, or a manual switch controlled directly by a user. REST creates an environment where clients and servers that encode their information the same way work together. (6AA)
Jargon bonanza: (6AB)
- REST objects are called "resources". This denotes their special feature of all implementing the same set of functions as well as the way they give names to specific pieces of information (6AC)
- The information in resources is often called "state", a nod to computability boffins who see all computers as "finite state machines" (6AD)
- The information has to be encoded to include it in a message. These encodings are called "representations" of the resource. These encodings are sometimes also called "content", "media", "entities", or "data" (68N)
- Methods invocations transfer state in representations. Read that sentence backwards and you get the somewhat obscure "REpresentational State Transfer" expansion of the REST moniker (6AE)
- Jargon for identifier: URL (from the web), URI (from the web) (68L)
More on those standard interactions: (6AF)
- A GET to an identifier means "Give me a copy of your information in a particular document format". (6AG)
- A PUT to that identifier means "Replace your information with mine". (6AH)
- POST adds information, and (6AI)
- DELETE eliminates information. (6AJ)
These methods can enable interaction with any kind of information. REST allows other methods to be defined, but they always act on generic information. In an object-oriented system the uniform interface would be like having every object implement the same interface class, and have no other public methods. (68K)
Why Uniformity? (68O)
Consider the java bean concept. A client has an expectation that get_foo() and set_foo() are operating on the same thing. The thing might be a simple member variable, but might just as easily be a more abstract concept. Either way, the fact that we have a uniform way of accessing the information makes it possible to develop applications we otherwise couldn't. We can do property-based editing with a java-bean. If we used arbitrary methods we couldn't. On the web this uniform interface allows web caches, authenticating proxies, search engines, and web browsers. None of these things would be possible without some form of uniform interface to operate against. (68P)
Another thing that the java bean does is to make it easier to understand the interface. We already have a concept of what a get or set to a particular property will do, so it is easier to pick up and use the interface. Having an easy API to work with is even more important on the web. With millions of people and machines involved in the conversation it is important that we all speak something close to the same language. (68Q)
What does Uniformity look like? (68R)
REST typically replaces the "do something" concept with a "make something so" concept. If you think about it, all "do something" can be modeled this way. Instead of "make this kind of state transition", just "make your state this". You have to get into specific examples to see how this works. (68S)
Starting or stopping a function could be the same as setting the state of a running resource to false or true using a PUT request. (68T)
A general approach to process creation would be: (693)
- POST a representation of the process to a factory resource to create it. (694)
- PUT a representation of the process to the process resource to change its operation. (695)
- DELETE the process to destroy it. (696)
- PUT a false to the process's "running" resource to suspend it. etc ... (68U)
Evolving Uniformity (68V)
The uniform interface is meant to evolve over time. That is why it is built from three different parts that serve different purposes: identifiers, methods, and document types. Each part is designed to change independently of the other parts. New methods are not meant to require the addition of new document types. New document types are not meant to require the addition of new methods. New objects are not meant to introduce new methods or content types. In object-oriented terms we have a single baseclass that defines the methods, but most methods have an "insert data here" slot. The information you want to transfer is added to this slot, along with the name of its document type. This saves us from multiplying out the number of standard methods in our interface class by the number of document types. (68W)
The cut-and-paste desktop paradigm follows a similar model. It has a limited set of operations that map closely to the HTTP verbs. For example, GET is similar to COPY. PUT is similar to PASTE OVER, and POST is similar to PASTE AFTER. We get a great deal of benefit from having these standard methods. It means that information can easily be transferred from one application to another, edited, pasted back, and generally handled without letting the technology get in the way. In this simple paradigm we still need to have flexibility with our document types. A program will typically make several forms of the copied information available to the cut-and-paste buffer. For example, it might be plain text, rich text, and word document. The application that receives a PASTE request picks the document format it understands best and uses that as the source of its information. (697)
As new document types are added the basic cut and paste methods remain, and so it is for REST. New document types are added when new kinds of information are invented. However the set of methods doesn't need to change when this occurs. The interface class that all resources implement still just says "insert data here". The methods return errors when the particular document format they are given is not understood. (698)
Business Rules and Overlapping Resources (68X)
Sometimes when we modify a resource, it will only be that resource that changes. However, just as often the change will set other processing in motion. When we POST a new purchase order we expect resources that describe the set of open purchase orders to change. This information is accessible from multiple resources, and could conceivably be modified using one of several resources. We can talk about resources that share information as overlapping. Changes that might not be a simple overlap may include a commission being paid for the purchase order achieving a particular state of completion. Any kind of business logic may be performed by the server so long as it provides a reasonable interpretation of the request to modify a particular resource. Even a GET is likely to have some sort of side-effect. A log file is bound to be updated, at least. (68Y)
Users must never be held accountable for issuing a GET request. Such a request should never buy an airline ticket. Likewise, it should be safe to repeat a PUT or DELETE request if the client can't be sure the first request went through. Two PUTs should buy the airline ticket only once. (68Z)
Statelessness (690)
Statelessness is the idea that any server for a resource should be able to handle any request from a client. It doesn't have to be the same server as the one who earlier requests went to. In REST we would provide authentication information with each request rather than expecting the server to already know who we are. We would expect that the same url would return the same data no matter the state of our cookies. (691)
Statelessness means that we can replace one server with another if it fails or needs to be upgraded. It also means that we can perform load balancing between servers. Both of these things are possible even without statelessness, but are more costly and difficult. (692)