A RESTful chess service: part 3Author: Dave Cassel | Category: Software Development
In part 2 of this series, I defined the data set and resources for my service. I’ve been following the procedure listed in RESTful Web Services for how to lay out the service. Here are those steps again:
- Figure out the data set
- Split the data set into resources
- Name the resources with URIs
- Expose a subset of the uniform interface
- Design the representation(s) accepted from the client
- Design the representation(s) served to the client
- Integrate this resource into existing resources, using hypermedia links and forms
- Consider the typical course of events
- Consider error conditions
For each resource:
Naming the Resources
I’ve finished the first two steps, and in doing so I identified Events, Players, Games, and search as resources that I want to expose through the service. Let’s take a look at the Games resource first. I need to decide how I will build the URI for a game. Let’s take another look at the PGN headers for my sample game again:
Of these fields, I believe you would need to specify Event, Site, Date, Round, White, and Black to be sure you’ve uniquely identified a game. This would cover cases where two players are playing a series of matches, with multiple games in the same day (I think this would be an unusual case, but it’s best to be sure). I can picture a couple different ways to identify this game with a URI. A very transparent way to do it would be to include each piece needed for uniqueness as a path variable:
Another approach, which is a bit more compact, is to take the hash of the needed values and use that:
If I could count on each game having a game id field, I could just use that, of course, but that does not appear to be a widely used field, so let’s think about the two options I’ve laid out. Clearly, the first is more informative to a human reader. That’s handy, but there is something I’m not wild about with this scheme: the slashes typically imply a hierarchy; here, no such hierarchy is really there. The authors use other punctuation to deal with cases where there isn’t actually a hierarchy. For instance, when they establish URIs for maps, they separate the latitude and longitude values with commas instead of slashes. The slash-based structure implies some hierarchy where none really exists.
On the other hand, the hash certainly doesn’t imply an hierarchy. In fact, it’s completely impenetrable: all you know from looking at the URI is that it identifies one particular game. Let’s think about how this service might be used. Picture doing a search and getting back a list of games. If you’re building an application that will present this list to the user, you won’t want to just give a list of hashes. You’ll want your user to have some way to decide what links to click. Using the first approach gives a lot of information about the game. Using the second approach, conversely, before a system could present a list it would need to retrieve each of the individual games in order to get the basic metadata. Because it will be more helpful for building applications around the service, I’m going to go with the more descriptive URI.
Exposing a Subset of the Uniform Interface
The Uniform Interface refers to the set of HTTP methods. The most commonly used are GET, POST, PUT, and DELETE. The protocol also supports HEAD, OPTIONS, TRACE, and CONNECT, but my service will not support any of these. In a nutshell, GET is used to retrieve a resource’s representation, POST and PUT are used to create and update resources, and DELETE removes a resource. For the use cases I’ve described, there is only one way data changes through my service: a tournament director uploads a game. The way I will support this is to let the TD POST a game to /games/. Doing so will return the URI of the game. I will also allow a TD to PUT to a particular game URI, replacing the previous resource, as a way of correcting mistakes, as well as DELETE to simply remove a game.
I want to let users retrieve games, of course, or this service wouldn’t be all that useful. As such, I’ll support GET on a game to return a representation of that game. Here, I’ll throw in a little wrinkle: I want to offer the PGN version of the game, as that’s the standard representation, but I also want to offer an XML version, to be machine friendly. One of the hallmarks of a RESTful service is links between various resources. PGN doesn’t typically have links, but my XML representation will. With this in mind, I’ll make one change the URI used to retrieve a game: I’ll add an extension, which must be either .xml or .pgn.
Designing the Representation Accepted from the Client
Although my service will offer two representations for a game, I’ll only accept one from the client: the PGN standard. My service will expect to find the fields used to construct the URI; any other fields will be stored too.
Designing the Representations Served to the Client
The PGN representation needs no design work: when requested, a PGN representation will follow the standard format. The XML representation will take a little bit of thought, however.
<game> <headers> <Event>First Saturday Quads</Event> <Site>West Chester Chess Club</Site> <Date>2003-02-01</Date> <Round>1</Round> <White>Joe Demetrick</White> <Black>David Cassel</Black> <Result>1/2-1/2</Result> <WhiteELO>1337</WhiteELO> <ECO>D13b</ECO> </headers> <moves> <move num="1" color="w">d4</move> <move num="1" color="b">d5</move> <move num="1" color="w">c4</move> <move num="1" color="b">c6</move> ... </moves> </game>
So far, this looks like an XMLized version of the PGN, with the one exception that I changed the date from 2003.02.01 to 2003-02-01. This simple change is to make the date a valid XML date. I’ll make a couple more changes in the next section.
One last comment before we move on, however. I took a quick look for XML representations of chess games. It seems none have caught on, simply because PGN has been so successful at capturing the information. So why am I bothering? Two reasons: 1) to provide the links that a good RESTful service needs to connect the resources, and 2) because for this exercise, I want to show multiple representations.
Integrate the Resource into Existing Resources
One of the key elements of a RESTful service is links to guide a consuming application from resource to resource. PGN doesn’t provide a way to do that, but our XML representation can. Let’s add a few changes:
<game> <link rel="alternate" type="application/x-chess-pgn" href="/games/First+Saturday+Quads/West+Chester+Chess+Club/2003.02.01/1/Joe+Demetrick/David+Cassel.pgn"/> <headers> <Event> <nameFirst Saturday Quads</name> <link uri="/events/First+Saturday+Quads"/> </Event> <Site>West Chester Chess Club</Site> <Date>2003-02-01</Date> <Round>1</Round> <White> <name>Joe Demetrick</name> <link uri="/players/Joe+Demetrick"/> </White> <Black> <name>David Cassel</name> <link uri="/players/David+Cassel"/> </Black> <Result>1/2-1/2</Result> <WhiteELO>1337</WhiteELO> <ECO>D13b</ECO> </headers> <moves> <move num="1" color="w">d4</move> <move num="1" color="b">d5</move> <move num="1" color="w">c4</move> <move num="1" color="b">c6</move> ... </moves> </game>
For this step, I needed to jump ahead a bit and define the URIs for events and players. In most organizations, players would likely be given a unique id, which I would certainly want to use in the players URIs to avoid name collisions. Since PGN does typically use names, though, I’m going to stick with that for this exercise.
This post is getting a bit long, so I’m going to wrap this one up. In the next post, I’ll take a look at the representations for events and players as well as looking at seach.