< Acceptance
Category:Fictional Fictions >

Transactions of the Transaction Society: Sam and I got a question from reader Scott Davidson about the famous RESTful transaction design (quoted at length by Jon Udell here, in case you bought so many copies of the book that you're now deadlocked trying to decide which one to look up page 231 in). I think it's worth responding to at length:

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.

Filed under:


[Main]

Unless otherwise noted, all content licensed by Leonard Richardson
under a Creative Commons License.