In regard to cross-resource transactions, I’m a member of the camp that wonders whether distributed transactions are strictly necessary in the REST/HTTP world; indeed I wonder whether they represent a design failure in modeling the granularity of your resources.
That said, we don’t live in a perfect world — and even if I can’t envisage why a properly designed RESTful application might require access to a distributed transaction, I can certainly envisage the environment where such an application might evolve. I’ve worked in a few of them. Places where interdepartmental barriers are as solid as the Great Wall; bastions of archaic technology where “one might provide a pseudo-RESTful interface, but one certainly won’t be re-architecting one’s legacy system in the buzzword language of the day”.
But, I think there’s a certain amount of smoke and mirrors in the JBossTS article “Transactional support for JAX RS based applications“:
Certainly it is worth pointing out that if a system cannot be made reliable then it can be of only limited utility. That said it is a worthwhile exercise to show how a REST based system can be made reliable.
Lack of distributed transactions would hardly seem to make a REST based system “unreliable” and, as a consequence, of “only limited utility”. Imagine a hotel booking facility — perhaps a booking resource, which internally might be constructed from a number of components, all governed (again internally) by transaction demarcation. Does the fact that the booking resource is coarse-grained and does not require an external transaction make it less reliable than a number of fine-grained resources which do? On the contrary. The latter sounds more like a WS-* api than a RESTful architecture, nothing to do with reliability.
So… hopefully it’s obvious I think it’s a bad idea. But if I were to write such an API, I think the 8-year old spec mentioned in the article falls short of the mark. Here’s my first-cut attempt at an alternative (which I still think falls a bit short of the mark, but is possibly an improvement):
| Resource: tc | ||||
|---|---|---|---|---|
| Method | URL | Content | Description | Statuses |
| GET | /tc | Returns HTML containing a summary of all transactions (status), plus an href to the transaction detail | 200 – ok | |
| /tc/{txid} | Returns HTML containing detail for the transaction with id {txid}, including the status and a list of hrefs to the each of the participants. For example:
|
200 – ok 404 – if txid is not found 409 – if the transaction has been deleted |
||
| /tc?status={status-type} | Return HTML containing a summary of transactions with a specific status, with href to the transaction detail For example: /tc?status=recovering or /tc?status=active |
200 – ok | ||
| /tc/{txid}/participants | Return a list of participants in the transaction (list of hrefs) | 200 – ok 404 – if the transaction does not exist |
||
| /tc/{txid}/partipants/{rec-coord-id} | Return HTML containing the detail of a participant. For example:
|
200 – ok 404 – if the transaction or participant does not exist |
||
| POST | /tc | [timeout={timeout}] | Start a transaction (with default timeout) returning the url /tc/{txid} — which is deleted after the timeout or after completion (any HTTP method relating to {txid} thereafter returns 404). Use timeout={timeout} to override the default timeout period. | 201 – created |
| DELETE | /tc/{txid} | Rollback and stop a transaction | 204 – ok 404 – if the transaction does not exist |
|
| /tc/{txid}?commit | Commit and stop a transaction | 204 – ok 404 – if the transaction does not exist |
||
| POST | /tc/{txid}/participants | url={url}&[name={name}] | Enlist {url} in the transaction, returning a unique resource for that participant of the form /tc/{txid}/participants/{rec-coord-id}. If name exists, record against the participant detail | 201 – created 404 – if the transaction does not exist |
| PUT | /tc/{txid}/participants/{rec-coord-id} | url={url} | Replace the participant url | 200 – ok 404 – if the transaction or participant does not exist |
The resource identified by a participant URL will have the following semantics:
| Method | URL | Content | Description | Statuses |
|---|---|---|---|---|
| PUT | URL/tx/{rec-coord-id} | action=prepare | The participant prepares any work done in the context of the transaction. The Warning header will contain additional info about the state of the prepare (either readonly, or notok). | 200 – ok 200 – ok (+ Warning: readonly) 200 – ok (+ Warning: notok) 404 – participant has rolled back |
| action=commit | The participant commits any work done in the context of the transaction. | 200 – ok 200 – ok (+ Warning: heuristic) 404 – participant has rolled back |
||
| action=rollback | The participant commits any work done in the context of the transaction. | 200 – ok 200 – ok (+ Warning: heuristic) 404 – participant has already rolled back |
Basic usage might look something like the following:
| 1. Create a new transaction resource | |
|
|
| 2. Create a new resource of some kind (notify the resource that it will operate with a distributed transaction) | |
|
|
| 3. Update another resource (again notify that it will be operating within a transaction) | |
|
|
| 4. Enlist the url for each resource in the transaction | |
|
|
|
|
| 5. Commit the transaction | |
|
|
| 6. ‘Behind the scenes’, the commit results in the following (2-phase commit at this point)… | |
and
|
|


