Most web applications don’t store much state in path variables: they use query variables instead. You may have seen URIs like this:
• http://www.example.com/colorpair?color1=red&color2=blue • http://www.example.com/articles?start=20061201&end=20071201 • http://www.example.com/weblog?post=My-Opinion-About-Taxes Those URIs would look better without the query variables:
• http://www.example.com/colorpair/red;blue
• http://www.example.com/articles/20061201-20071201 • http://www.example.com/weblog/My-Opinion-About-Taxes
Sometimes, though, query variables are appropriate. Here’s a Google search URI: http:// www.google.com/search?q=jellyfish. If the Google web application used path variables, its URIs would look more like directories and less like the result of running an algo- rithm: http://www.google.com/search/jellyfish.
#Up to a point, anyway. See On Exactitude in Science by Jorge Luis Borges.
Both of those URIs would be legitimate resource-oriented names for the resource “a directory of web pages about jellyfish.” The second one doesn’t look quite right, though, because of how we’re socialized to look at URIs. Path variables look like you’re traversing a hierarchy, and query variables look like you’re passing arguments into an algorithm. “Search” sounds like an algorithm. For example, http://www.google.com/ directory/jellyfish" might work better than /search/jellyfish.
This perception of query variables is reinforced whenever we use the Web. When you fill out an HTML form in a web browser, the data you input is turned into query var- iables. There’s no way to type “jellyfish” into a form and then be sent to http://www.goo gle.com/search/jellyfish. The destination of an HTML form is hard-coded to http:// www.google.com/search/, and when you fill out that form you end up at http://www.goo gle.com/search?q=jellyfish. Your browser knows how to tack query variables onto a base URI. It doesn’t know how to substitute variables into a generic URI like http://www.goo gle.com/search/{q}.
Because of this precedent, a lot of REST-RPC hybrid services use query variables when it would be more idiomatic to use path variables. Even when a hybrid service happens to expose resources RESTfully, the resources have URIs that make them look like function calls: URIs such as http://api.flickr.com/services/rest/?method=flickr.pho tos.search&tags=penguin. Compare that URI to the corresponding URI on the human- usable Flickr site: http://flickr.com/photos/tags/penguin.
I’ve managed to avoid query variables so far: every planet, every point on a planet, and every corresponding map is addressable without them. I don’t really like the way query variables look in a URI, and including them in a URI is a good way to make sure that URI gets ignored by tools like proxies, caches, and web crawlers. Think back to the Google Web Accelerator I mentioned in “Why safety and idempotence matter” in “Split the Data Set into Resources. It never pre-fetches a URI that includes a query variable, because that’s the kind of URI exposed by poorly-designed web applications that abuse HTTP GET. My service won’t abuse GET, of course, but outside applica- tions have no way of knowing that.
But I’ve got one more type of resource to represent—lists of search results—and I’m out of tricks. It doesn’t make sense to keep going down the hierarchy of place, and I can’t keep piling on punctuation just to avoid the impression that my service is running an algorithm. Besides, this last type of resource is the result of running an algorithm. My search algorithm finds places that match map-specific criteria, just as a search en- gine finds web sites that match the client’s keywords. Query variables are perfectly appropriate for naming algorithmic resources.
The search interface for places can get as complex as I need it to be. I could expose a name query variable for place names and pollutant for sites of high pollution and cui sine for restaurants and all sorts of other query variables. But let’s imagine I’ve got the technology to make it simple. The only query variable I’ll add is show, which lets the client specify in natural language what feature(s) they’re searching for. The server will
parse the client’s values for show and figure out what places should be in the list of search results.
In “Split the Data Set into Resources” earlier in this chapter, I gave a whole lot of sample search resources: “places on Earth called Springfield,” and so on. Here’s how a client might use show to construct URIs for some of those resources.
• http://maps.example.com/Earth?show=Springfield • http://maps.example.com/Mars?show=craters+bigger+than+1km • http://maps.example.com/Earth/Indonesia?show=oil+tankers&show=container +ships • http://maps.example.com/Earth/USA/Mount%20Rushmore?show=diners • http://maps.example.com/Earth/24.9195;17.821?show=arsenic
Note that all of these URIs are searching the planet, not any particular map.
URI Recap
That’s a lot of details. After all, this is the first place where my fantasy resources come into contact with the real world of HTTP. Even so, my service only supports three basic kinds of URI. To recap, here they are:
• The list of planets: /.
• A planet or a place on a planet: /{planet}/[{scoping-information}/][{place-
name}]: The value of the optional variable {scoping-information} will be a hierar-
chy of place names like /USA/New%20England/Maine/ or it will be a latitude/longitude pair. The value of the optional variable {name} will be the name of the place. This type of URI can have values for show tacked onto its query string, to search for places near the given place.
• A map of a planet, or a point on a map: /{map-type}{scale}/{planet}/[{scoping-
information}]. The value of the optional variable {scoping-information} will al-
ways be a latitude/longitude pair. The value of the optional variable {scale} will be a dot and a number.