REST vs. SOAP (Oh No, Not Again)
Well, yes, once again.
To illustrate why I believe a RESTful application design is different not only in implementation details, I’ve created these two diagrams:
Service-oriented Design
In this model, there will be very few services, each of them exposing a number of operations. Every service is different (has its own interface); the service itself does represent any entity (something which has a logical identity). Instead, some information to identify entities is passed as parameters or, if your prefer, information within the documents.
Resource-oriented (REST) Design
In a RESTful architecture, the key resources are identified; these can be entities, collections, or anything else the designer seems worthy of having its own URI. The standard methods — in this case, the HTTP verbs — are mapped to resource-specific semantics. All resources implement the same (uniform) interface. Not shown in the simplistic diagram is the dimension of content-types, which allows for different representations of resources (e.g. in both XML, HTML, and plain text), as well as the possibility of links to resources in resource representations. Use your imagination — e.g. the GET on /customer/4711 would return a document that contains a link to a specific /order/xyz.
Yeah, I like it. One thing I’d consider is not mentioning http at all. I’d talk about CRUD instead maybe or whatever David@Rails had in his presentation (World of Resources) recently. This would allow people to see the design differences without having their minds corrupted by their (wrong?) understanding of what HTTP is.
i.e. Let’s keep it as pure as possible.
Best,
Dan.
Your second diagram illustrates the brilliance of REST. Ask any REST proponent to define the basic resources for a system comprising “orders” and “customers”, and I’m willing to bet they’d come up with something -very- similar to what you’ve described.
Ask the same of the other camp(s), and I’m just as sure you’ll get a dozen different replies of exponentially increasing complexity.
“Ask the same of the other camp(s), and I’m just as sure you’ll get a dozen different replies of exponentially increasing complexity.”
Indeed you might but it could well be because they aren’t thinking pure design. Instead they are allowing their design to be confused/influenced by the technologies they commonly use. Design patterns, CRUD, CRC cards (or similar techniques) etc are all largely ignored by the masses in favour of following “patterns” enforced by frameworks such as EJB. And when this happen, design goes out the window as you focus on fitting with the framework rather than having the framework fit you.
And then there’s the simple matter of simplicity - most people don’t seem to strive for this. I wonder if that’s because things like refactoring are frowned upon as un-necessary time waste with the resultant loss of learning opportunities.
Very compelling way of describing the fundamental difference between both approachs! I’m also thinking about a related REST diagram that would emphasize the URI hierarchies (composition) instead of the derivation from the Resource concept.
Stefan,
Indeed, it would be great if we could get everybody to agree on REST as primarily an approach to conceptual modelling (see my earlier comments on /blog/st/2006/02/22/moresoapvsrestarguments.html). We might then be able to move the debate forward and actually learn something.
A few things are perhaps still worth pointing out, however.
Firstly, as any analyst will know, there is no single “correct” way to model anything. Different approaches work better in different scenarios (see again “Data and Reality” for an old, but still relevant discussion). So this is not an either/or debate: both “service oriented” and “resource oriented” approaches might be valid and useful in different circumstances.
Secondly, there is nothing to stop anyone taking the same REST modelling approach and implementing a system using SOAP/WSDL, Corba, Java/RMI or any other technology. Similarly, a service-oriented approach can be taken with [raw] HTTP (as seems so often the case in the many pseudo-REST systems out there). So the debate clearly isn’t about implementation technology at all. Hmnnn. Isn’t this going to spoil everybody’s fun :-?
Thirdly, the “resource oriented” approach could equally well be called “object oriented” (at least in some sense). But the pure object-oriented approach has been shown to be ineffective in building large-scale distributed systems, hence the rise of the “service oriented” approach (abstract, stateless, coarse-grained objects, box-carring and so on).
Lastly, aren’t URLs supposed to be opaque according to the pure web architecture? But your example has much semantic information encoded within the URL character sequences. Surely this will lead people to (incorrectly) try and construct URLs themselves, or even worse unpick parts of the character strings for other purposes (e.g. extracting an orderId). Shouldn’t a REST system also have a system of “finders” and “factories” to avoid any dependencies on or implied assumptions about the format of URLs?
-Mike.
Mike, very valid points. To address them one by one:
You are right, of course; but contrary to most service-oriented approaches I’ve seen, REST does suggest a lot of decisions because of its constraints. I agree with Jason (see his comment) that most REST folks would arrive at a similar conclusion. My main goal, though, was to point out that the ‘canonical’ SO vs. RO approach are very different.
You are absolutely right, which is why REST vs. SOA(P) is not an implementation, but rather an architectural discussion. Both camps have a natural tendency towards one of these models — SOA(P)/WSDL + tooling on the one side, HTTP on the other side. Still, the debate would be very similar were we to argue a RESTful approach vs. a service-oriented approach, both implemented using SOAP and JMS.
The main different to the object-oriented approach is that there’s a single (uniform) interface; the main similarity is that of identity.
You are right, and this is a tradeoff — URIs which are easy to remember lead to the wrong assumption that one can de-construct and compose them meaningfully on the client.
REST seems to be a object-oriented version.
Is that the major difference between document-oriented development and object-oriented, Or document-first development and class-first?
I would say it’s the difference between resource-oriented and service-oriented :-)
As part of CXF (http://cwiki.apache.org/CXF/) I’ve been working on this:
Service: http://fisheye3.cenqua.com/browse/celtixfire/trunk/rt/bindings/http/src/test/java/org/apache/cxf/binding/http/bare/CustomerService.java?r=467368
Unit test: http://fisheye3.cenqua.com/browse/celtixfire/trunk/rt/bindings/http/src/test/java/org/apache/cxf/binding/http/bare/BareServiceTest.java?r=467382
I was surprised to see that it pretty much lined up exactly with a good portion of your diagram. I will have more details and docs within a week as part of our first milestone, but you may be interested in checking it out.
Hi,
REST seems to be a little bit similar in concept to OASIS’s WSRF (http://www.oasis-open.org/committees/tchome.php?wgabbrev=wsrf) or even more to WS-Transfer (http://www.w3.org/Submission/WS-Transfer/). But, REST seems to be much simpler.
Yes — that’s because both WSRF and WS-Transfer are bad re-inventions and basically do HTTP-over-SOAP-over-HTTP!
Hi,
I am still not sure I get the whole debate right. How would I express business services like:
1) promotePersonToCustomer (sure I could do an update (POST) on person and set a flag that he is a customer, but wouldn’t that mean, I have to check if the flag has changed, whenever a POST happens, and there are probably quite a bunch of different scenarios (use cases) that must then be checked with each POST)
2) customerMoved (I.e., this is not a correction of an address (typo) but he really has moved, which is probably something totally different. Probably it is necessary to keep the old address — ok, I could do a PUT to create a new address, with a flag “MainAdress”, but I think “customerMoved” is a much more expressive service)
3) markCustomerAsBadRisk (so I want to mark this customer as a bad risk, we shouldn’t do any new business with him. Again I could do an UPDATE on the customer, but again, I would have to watch for any changes to this flag, I would even have to create a big matrix of compatible changes on the diverse customer attributes, and again, markCustomerAsBadRisk is much more expressive)
So it perhaps boils down to: How do I express “verbs” that go beyond the CRUD pattern.
-Victor
Hi Victor,
First of all, update is more similar to PUT (you most often use POST to create something new).
As to your use cases:
For 1), one way would the one you describe (with PUT instead of POST). Another way would be to have both a customers/ and a persons/ collection resource, and add a new resource under customers/ that refers to an existing one under persons/.
For 2), again, you’ve mixed up PUT and POST; apart from that, one solution could be to create a new address resource under the existing customer (i.e. “customerMoved” would become “add address”). The customer would link to its addresses
For 3), you could have a “goodcustomers” collection, a “badcustomers” collection, or both, each of which would (or would not) include links to the customers that belong there.
Of course there are many other ways to do this, just as there are many different ways to choose operation names. Using REST, your variables are a) the resource identifier b) the verb and c) the content
HTH, Stefan
Hi Stefan,
thx for the prompt response. Putting things in collections to mark them in a certain way surely sounds unusual to me, but perhaps it’s just a certain kind of mind set that is needed.
But with “add address” I really see a problem: there can only be one main address, so “adding” a new address (as main address) would mean to move the previous main address into a “previous addresses” collection. Sure I can do that, but I really think an operation like “customerMoved” is much easier to understand because it really states the behaviour of this operation. When I compare it to “add address” or even “replace address”. And again there are a multitude of different operations that can be hidden behind a basic operation like “add address”.
I wouldn’t want to lose the expressiveness of naming operations — even if 80% of the operations are CRUD operations. The corner cases sometimes dictate how you want to handle the majority of the cases.
And w.r.t the mind set: not everything is a noun. (and not for every verb there is a good/fitting projection on the four REST verbs)
Again thx, and a happy new year.
Victor
I’m not following the difference here.. In my design I’d have /app/servics/Customer and /app/services/Order So what about that does not idenfity the identity? It seems you assumed that the two services would be combined into something less descriptive…
Gary, how would you send me a link to a specific customer? I assume you can’t — to get at one, I’d have to retrieve the WSDL for /app/services/Customer, find the getCustomerDetails() operation, understand your ID scheme, and POST appropriately. Right?
Exactly.. And I’m guessing that there is no specification on what a REST service takes as input nor what it’s output is? So I guess I’ll call your /customer/4711 and henry’s /customer/4711 and I shold get the sanme results right? And I guess you don’t need to be concerned with the fact that my customer has a composite key. It’ll all magically work for you…
No, you’ll probably not get the same result, but why would you? If you look at the URLs http://example1.com/customer/4711 and http://example2.com/customer/4711, they’re different — never mind that they end in the same string, this is just not relevant. From the documentation, you’ll (hopefully) find out the representations’ content type.
There is a machine-processable REST description language, WADL, but I’m not entirely sure you actually need it when you don’t generate code from it. Of course you do need documentation, but that’s true in any case.
And no, I don’t need to be concered with composite keys — if you insist on having them only, you can’t benefit from REST’s standardized identity scheme. Which may be OK — as usual, a question of what compromise works best for you.