I was showing some Coffeescript to a candidate today. It happened to be a Backbone.js model with a field called slug. “What’s a slug?” – he asked.
A slug is an external identity to an object reachable by an API call. For example, Steven Assael’s amazing graphite drawing entitled “Amber with Peacock Feathers” has a “steven-assael-amber-with-peacock-feathers” slug. Slugs are much more readable than a database object identity, such as “4dc706fb46895e000100128f”. They make URLs prettier and helps search engines index data. Slugs also enable developers to change the way data is stored. In general, I recommend hiding internal IDs and creating external IDs for every object that is exposed to the outside world.
In Ruby we use the mongoid-slug gem. To set this up we include Mongoid::Slug and specify which field to use to generate it.
I decided to implement the same thing for this blog, which is a bit obsolete architecture-wise and is written in ASP.NET. To keep things simple, I added a slug field to my Post model as an _nvarchar(256) _and slapped a unique key constraint on it. To generate an actual slug from a title I stole some code from here. It basically strips any non-alphanumeric text from the post’s title.
Slugs are unique, so we must avoid duplicates. While there’re more effective approaches to generating a unique slug, we’ll simply iterate until we find a unique value. After all, how often do we need to generate a new slug?
The routing is a bit trickier. Until now the posts were accessible as ShowPost.aspx?id=Integer. I started by making a change where a post can be fetched by slug, such as ShowPost.aspx?slug=String. The next problem is accepting slugs in the URL and internally rewriting the ASP.NET request path to the latter. The best place to do it seems to be Application_BeginRequest _in _Global.asax.cs.
First, we’re removing the virtual path from the request URL, stripping the /blog/ part from applications hosted at a /blog/ virtual directory. Then, we’re going to assume that anything that doesn’t have a period (.) in the URL is a slug and is being redirected to ShowPost.aspx. An alternative is to rely on a /posts/ path, but that will break all relative URLs in my existing application since, for example, /Style.css is not the same as /posts/Style.css. Naturally your mileage may vary depending on your existing requirements.
Secondly, we’d like to permanently redirect anyone with a ShowPost.aspx?id=Integer link to the new slugged URL and anyone directly hitting the ShowPost.aspx?id=slug url to the slug itself. This way there’s only one way to address a post, by it’s slug.
Here’s a URL that I get after running a task to re-slug all existing posts to my infamous Github is Your New Resume post. It’s a lot nicer!
The URL has changed, yet Discus comments are fine (phew.) – they use my unique identifier. The twitter RT count is lost though and is reset at zero, since Twitter is a URL-based system. Too bad, here’s a screenshot for the memories.
314 RTs, holy crap! This blog’s source code is available under the MIT license on Github.