Rails and REST: Don't use auto-incremented database IDs as your resource identifier

By default, Rails expects your resource to be identified by its model’s primary key ID. Don’t give in to temptation. There are a lot of good reasons to avoid going that route, and they’ll save you pain and trouble later. This isn’t news in the Rails community, as the framework has always had excellent routing support for custom URLs. But the default XML serialization code isn’t as forgiving, and it’s worth ticking off a few reasons to take the extra step.

They aren’t human-friendly

Database IDs mean nothing to the human beings consuming your resource. This matters even when all you’re providing is pure REST service with no UI component, as with the project I’m working on now, because although it may be other applications consuming the service, human beings are writing the code. One of the great advantages of a RESTful API is that they’re pretty easy for even casual programmers, maybe technically-minded domain experts, to consume with simple, hacky script. Anything you can do to encourage those people and make their lives easier will redound back in user happiness and cool, unexpected new uses.

This isn’t just useful for the warm fuzzies, though. Most importantly, it allows users to self-identify the resource, saving you an unnecessary search. More on that later.

They’re (usually) generated arbitrarily

My current project involves importing a large amount of data from a third-party system. For a long time, whenever we re-ran that import any system that relied on a link to our resource broke because the IDs got regenerated. Of course you can fix this with a smarter import (and we have) but a better solution is simply to use the data we’re given. A URL-friendly ID that’s inherently tied to the data is much less fragile.

They don’t allow you to model concepts

Some resources don’t map cleanly to database tables, or it doesn’t make any sense to map them that way. Consider a resource that exposes the weather on a given day, and retains a history of that weather. Your historical data is probably stored in a database somewhere, but the concept you’re modeling is the date.

Exposing the resource with database IDs forces the user to perform a search if they want to find out what the weather was five years ago from this Tuesday. Without a URL representation you end up with a query of the form /weather?date=2003-08-26, which is more appropriately a /show/ than it is an /index/ call. /weather/2003-08-26 is not only a cleaner URL but retains cleaner semantics; an index should give you a list of things back, so the former URL will deserialize into an array with a single Weather resource (courtesy of ActiveResource) whereas the latter is simply a single object.

In a future post I’ll talk about ways to minimize the amount of trouble involved in moving over to a human-friendly resource identifier.

This is part of a series of posts on Rails and REST. Read the rest.

The difference between commentary and conversation

Rails and REST: A reference to commonly-used HTTP status codes and their use in REST APIs