A RESTful chess service: part 4Author: Dave Cassel | Category: Software Development
This is part four in a series of posts walking through the process of building a RESTful chess service. I’ve been slacking off a bit in the pace of my posts, but hopefully that will pick back up — I have a bit more travel coming up, and evenings spent hanging out in hotel rooms are good for getting posts written!
The previous post in this series laid out representations of individual games. As part of that, I picked URLs for events and players, rooted at /events/ and /players/.
I think I’ve mentioned that I intend this blog as learning-in-public sort of exercise. Here’s a case in point: I don’t like the way I set up the event URLs in my last post. I have pictured that the representation of an event would list the participating players and the games. However, I set up the URL to only mention the name of the event. The problem with that is that the name of an event (“First Saturday Quads”) does not uniquely identify a specific tournament. To do that, you need to add at least the site and the date(s) on which the tournament was played. As such, I’m now revising the URL of event to take the form: /events/<event name>/<site name>/<date range>. I’m allowing (but not requiring) a date range, because while some events are over in one day, some last for a few days, weeks, or even (in the case of postal chess) years.
Representing Events and Players
Under the use cases I’ve identified so far, there is no way to enter event data other than the game information that shows up in the PGN. An event, under my setup so far, is simply a collection of games. I’m going to run with that for now, but I can picture storing addition infomation such as the name of the Tournament Director and the tournament winner. Eventually, that would require accepting a new representation for a tournament.
Since we don’t have much data about events, the representation won’t be that complex. Here’s the representation for /events/February 2010 Octet X/http%3A%2F%2Fwww.redhotpawn.com/2010.02.17-2010.04.01:
<event> <name>February 2010 Octet X</name> <site>http://www.redhotpawn.com</site> <date-start>2010-02-17</date-start> <date-end>2010-04-01</date-end> <players>8</players> </event>
Likewise, what we know about players comes from the PGN information about individual games. For our player representation, we’ll give the name and what we know about the player — not much at this point.
<player> <name>Cassel, David</name> <counts events="2" games="100"/> <rating type="highest">1546</rating> <rating type="latest">1542</rating> </player>
One more thing before we move on. I mentioned earlier that if we wanted to add, say, the Tournament Director to the representation of an event, we’d have to allow a consumer of this service to PUT a new representation. But notice that what’s contained in the representations right now is extracted from the actual game data. What would we do if someone uploaded a representation that contradicted what we knew from the game data? That’s an application-specific decision; we could either decide to overwrite what we saw in the game PGN data, or we could decide it is involatile. If we go with the latter approach, we could disregard contradicting information or trigger an error. Since I’m not going to allow PUTs to Event and Player resources, I don’t have to worry about it — but when you’re designing your service, watch out for gotchas like that and think through what should happen. (That’s step 9 in our authors’ procedure, for those keeping track.)
I’m going to offer two ways to search. The first will look pretty normal. I’ll use a URL like this: /search?q=. Is this RESTful? How does “search” count as a resource? Simply enough: search is an algorithm; the results of that algorithm are a resource, complete with a representation.
This is a free text search. Results may include games, players and events.
/search?q=quads <results> <game>/games/First+Saturday+Quads/West+Chester+Chess+Club/2000.04.01/1/Joe+Abner/David+Cassel</game> <game>/games/First+Saturday+Quads/West+Chester+Chess+Club/2003.02.01/1/Joe+Demetrick/David+Cassel</game> <game>/games/First+Saturday+Quads/West+Chester+Chess+Club/2000.04.01/1/David+Cassel/Charles+Jay</game> <game>/games/First+Saturday+Quads/West+Chester+Chess+Club/2000.04.01/1/David+Cassel/Fred+Austin</game> <event>/events/First+Saturday+Quads/West+Chester+Chess+Club/2000.04.01</event> </results>
We can see now how the decision to use transparent URLs is helpful: we can present these results a user, who will be able to determine something about them without having to load up the contents of the individual documents. But wait, there’s more! Let’s also set up search by path variable: we’ll let the user specify the parts they know about and use “any” for the remainder. We’ll only apply this style to game searches for now. I’ll also disallow wildcards, but you can probably see how that would be a useful extension. Let’s look at an example:
This URL will return a list of all games in which I played white in the West Chester Chess Club’s First Saturday Quads event, regardless or date or opponent. Of course, in a large database this could yield a lot of results, especially if you used “any” for a lot of fields. So let’s add two more fields in order to allow for paging: page number and page size.
<results> <game>/games/First+Saturday+Quads/West+Chester+Chess+Club/2000.04.01/1/Joe+Abner/David+Cassel</game> <game>/games/First+Saturday+Quads/West+Chester+Chess+Club/2003.02.01/1/Joe+Demetrick/David+Cassel</game> <game>/games/First+Saturday+Quads/West+Chester+Chess+Club/2000.04.01/1/David+Cassel/Charles+Jay</game> <game>/games/First+Saturday+Quads/West+Chester+Chess+Club/2000.04.01/1/David+Cassel/Fred+Austin</game> <!-- six more <game/> results, then: --> <page>1</page> <link rel="next">/games/First+Saturday+Quads/West+Chester+Chess+Club/any/David+Cassel/any/2/10</link> </results>
Now we’re asking for the same set of results as before, but we want the first page of 10 results. The <page/> element toward the bottom identifies the page and the <link/> element shows how to get to the next page. After the first page, the service would also provide a <link rel=”prev”/> element. This is part of being RESTful: a representation of a resource provides links to other things.
At this point, I’ve walked through the first seven steps of the process. The remaining steps are to consider the typical course of events, and to consider error conditions. I’ll pick that up in the next post. After that, it will be time to start whipping up some code!