<D <M <Y
Y> M> D>

: I've finally got the green-light for my Frank Zappa/Samuel L. Jackson crossover vehicle, Baby Snakes on a Plane.

[Comments] (2) Acceptance: I can't find the link [UPDATE: it was Paul Sandoz], but someone posted a weblog entry that mentioned something I say in RWS about choosing different URIs for different representations. The example I (and the unknown weblog entry writer) used was a press release which is available in two languages (English and Spanish) and two data formats (HTML and plain text). The URI to this resource is /releases/104, and you can choose a representation format by setting the Accept and Accept-Language headers. But I also recommend exposing a URI for each language and format:

When a client requests one of those URIs they can leave out one or both of the Accept- headers and still get what they want. The Content-Location response header is set to /releases/104 so that you have a URI to use when talking about the press release in general, rather than a specific version of it.

The question in the weblog entry I can't find is more or less this: what about the other two Accept- request headers, Accept-Charset and Accept-Encoding? Why don't I recommend exposing URIs like /releases/104.es.txt.gzip.UTF8?

The reason I put any special levers in the URI is because we pass around URIs, not URIs plus headers. Lots of programs and services take a URI, perform a GET on it, and expect that they got what you told them to get. One example I give in the book is the W3C HTML validator. If the only URI I exposed was /releases/104, there'd be no way to validate the Spanish version separate from the English version. If the default representation format for /releases/104 was plain text (unlikely, but this is just a thought experiment), there'd be no way to validate the HTML formats at all.

To the extent that this reason applies to some piece of information, I argue for putting a lever for it in the URI. Obviously it applies to things like which press release you want. I think it also clearly applies to the language and the data format. I think it doesn't apply to compression or character encodings. Here's a quote from page 243, in the section "Compression" where I talk about Accept-Encoding:

You probably remember that I think different representations of a resource should have distinct URIs. Why do I recommend using HTTP headers to distinguish between compressed and uncompressed versions of a representation? Because I don't think the compressed and uncompressed versions are different representations. Compression, like encryption, is something that happens to a representation in transit, and must be undone before the client can use the representation. In an ideal world, HTTP clients and servers would compress and decompress representations automatically, and programmers should not have to even think about it.

We can argue over what counts as a different representation (as you can see I take a fairly high-level view), but even if you think the compressed and uncompressed data are different representations, this isn't a difference that needs to go into the URI. A client can be automatically programmed to detect a compressed representation and uncompress it. The key is this ability. If it were possible to algorithmically translate any human language into another, or any data format into another, there'd be a much weaker case for extending the URI with levers for language and data format.

The same logic holds for character encodings, because a client can be automatically programmed to convert any character encoding into Unicode. The case is weaker because 1) the programming is difficult unless there happens to be a library for your language, and 2) you only get compression if you ask for it, but you get a character encoding whether you like it or not.

If you're exposing a resource in multiple encodings, and you have reason to believe that a URI-driven client might choke on your default encoding, then sure, put an encoding selection lever in the URI. But at the risk of sounding provincial (if being too cosmopolitan can be a kind of provinciality), your default encoding ought to be UTF-8 or UTF-16.

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.

[Comments] (6) Category:Fictional Fictions: I feel a sense of unease whenever I'm revising a story and I change what happens. I feel like there's some residual sense in which A "really" happened and B is a lie to cover it up. But if the story is published, most people will think B "really" happened and A will seem a curiosity if they know about it at all. How do we discuss different kinds of fictional events? Lay some vocabulary on me.

[Comments] (1) : A set of algorithms for experimental travel. "Arrange to spend a weekend away with your partner. Travel to your chosen destination by different means and don't arrange a meeting time or place. Now look for each other..." There's a lot of overlap with the Lonely Planet guide, which I've had my traveling eye on.


[Main]

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