Thu May 31 2007 17:26 Transactions of the Transaction Society:
I'm perplexed why your transaction example in Chap. 8 didn't simply create a transaction resource that included both checking & savings account as well as the transfer amount w/ a PUT (defining the resource as XML in the request body). Then you could simply call /transaction/11a5/commit or even just assume that this is a request to commit the transaction by default and avoid the 2nd call altogether. Is there a specific reason why it was not done this way? I can already see the "REST-haters" rolling their eyes to this three request/response transaction pattern.
The short answer is that if I'd presented it that way, the "REST-haters" would have an even better reason to roll their eyes: it would look like I couldn't think of a resource-oriented way to do transactions and I'd had to fall back to the RPC style.
Let me explain. When I read this question my immediate vision was of a request that looked like this:
PUT [some URI] HTTP/1.1 Content-Type: application/xml <transaction type="transfer" amount="50.00"> <source href="/accounts/checking/11" /> <destination href="/accounts/savings/55" /> </transaction>
I don't know if this is what Scott had in mind, but let's run with it. This actually won't work as is: PUT only works when the client knows the URI of the new resource, and the URI for a transaction resource is chosen by the server. That's a minor problem we can fix by sending POST to a "transaction factory" resource:
POST /transactions HTTP/1.1 Content-Type: application/xml <transaction type="transfer" amount="50.00"> <source href="/accounts/checking/11" /> <destination href="/accounts/savings/55" /> </transaction>
My first suggestion about transactions (page 231) was: "You can expose simple transactions as batch operations..." This is a kind of batch operation (albeit not quite the kind I had in mind), one that affects two resources identified by URI.
The problem with this representation is that it makes the second HTTP request look a lot like an RPC-style overloaded POST request. It looks less like an object the client is creating, and more like a command that /transactions is supposed to execute.
I wouldn't go so far as to say it is overloaded POST, because its result is a new addressable resource (the transaction record). There's a fuzzy overlap here between RESTful and RPC-style, just as there is with a request like "GET /rest-endpoint?method=photos.search&tag=penguin". But in the book I don't design URIs that look like method calls, because it sets a bad example, and for the same reason I don't design representations that look like commands. If you looked at that second HTTP request in isolation, you'd probably think "okay, there's no fundamental difference between RESTful and RPC-style transactions". When in fact there is a more elegant way to do them that looks nothing like the RPC style.
Why do I think the way I showed in the book is more elegant? Mainly because requests on transaction views work exactly the same way as would non-transaction requests on the underlying resources. If you could change an account balance at will, you'd PUT to /accounts/savings/55. You can't, so you create a transaction and PUT to /transactions/11a5/accounts/savings/55.
Two lesser reasons. First, you don't have to do the whole transaction at once. You can build it up on the web service as real-world events happen on your end, and commit when you're ready. It works the same way as a transaction in a programming language. Second, a transaction is an addressable resource even while in progress. Multiple authenticated clients can inspect or collaborate on a transaction, and the rules for avoiding conflicts are the same as on the rest of the web (eg. If-Unmodified-Since).
That leaves the question of efficiency. You can package multiple operations into a single HTTP request for efficiency's sake. But if a single operation is an HTTP method applied to a URI, that's what you should package. If the uniform interface is good enough for one-at-a-time operations, it's good enough for descriptions of batch operations. You don't need an application-specific vocabulary like the one I came up with reflexively. A simple, uniform vocabulary will do; something like this:
<transaction> <request method="PUT" target="/accounts/checking/11"> <representation>balance=150</representation> </request> <request method="PUT" target="/accounts/savings/55"> <representation>balance=250</representation> </request> </transaction>
(You could probably use an XML document that contains a series of SOAP envelopes!)
I think POSTing that representation to a transaction factory satisfies Scott's original criteria: "create a transaction resource that included both checking & savings account as well as the transfer amount... defining the resource as XML in the request body". And it would make a good addendum to the "Transactions" section, once the reader has seen which HTTP requests underly the transaction. But presenting it instead of the multi-request version would probably be confusing, and would certainly give the impression that there was no RESTful way to make those HTTP requests one at a time.
No comments yet.