Written on 8/11/2014 in Web development

Readable routing


Web UX MVC

We arrive at yet another important part of every web application: Routing. Routing is important for Search Engine Optimization, but also for the user experience. I don't know about you, but readable url's is something I can appreciate about a website. Often enough, when looking for an item in a series, I try to alter the sequence number in the url. When the page is in the wrong language and I don't immediately see a language switcher, I try to change the language in the url. But that's not possible when your url is a random series of alphanumeric characters.

Routing

The easiest solutions would be the following urls following the basic Asp.NET MVC schema:

http://www.url.com/Post ==> Returns page 1 of a list of posts
http://www.url.com/Post/Details/1 (id) ==> Returns a post
http://www.url.com/Tag/Create ==> Create a new tag
http://www.url.com/Post/ByTopic/1?page=1 (id) ==> Returns page 1 of a list of posts of topic with id 1

That's perfectly fine, I would ALWAYS try to use this url format when I'm not building a consumer facing website. It separates the different entities nicely and keeps it concise and generic. In this case, 1 route will service all url's here. But a consumer does not want or should be able to see id's and SEO is unable to match this format of url to the contents of the page. I might use this format later on, when I'm implementing ways to edit posts, topics and tags4. For the consumer based pages, I will need something easier to read. What about:

http://www.url.com/Posts ==> Returns page 1 of a list of posts
http://www.url.com/Post/1/The_bear_*****_in_the_woods (seq number) ==> returns a post
http://www.url.com/Tags ==> Returns page 1 of a list of tags
http://www.url.com/Topic/1/Things_animals_do ==> Returns page 1 of a list of posts of topic with sequence number 1

That's easier to read in my opinion. Posts clearly suggests that there will be multiple posts. The title is shown for a specific post so it can more easily be indexed by a web crawler1. The id is replaced by a sequence number. It's better to use a sequence number instead of an id in this case for uniquely identifying an entity because an id is not supposed to be sequential. If what I provide in my url is not sequential, it could happen that a user wants to go back 5 posts, he edits the url and gets a 404, or he gets the previous post because the id's skip a few numbers2.

Multiple levels

I'm happy with this format, but you also have to consider growth in your website. Right now, everything here is about the blog5. But what if I want to use the same domain name for different applications. You should provide some way of separating these applications entirely. Something similar is done with the api. It runs under "www.url.com/api/{controller}/". Using a different suffix is a solid way of doing this. For my blog I can use the prefix "Blog" and when I want to add a code snippets repository later, I can just use another suffix ("Cnippets")3 => "www.url.com/Cnippets/".

Which gives us this:

http://www.url.com/Blog/Posts ==> Returns page 1 of a list of posts
http://www.url.com/Blog/Post/1/The_bear_*****_in_the_woods ==> Returns a post
http://www.url.com/Blog/Tags ==> Returns page 1 of a list of tags
http://www.url.com/Blog/Topic/1/Things_animals_do ==> Returns page 1 of a list of posts of topic with sequence number 1

Allright, looking fine. But there is one more thing. I need more structure. That last one does not look in any way like a url that will return posts. It looks like it will give me details about that certain topic. Another thing is that a unique post is defined by the combination of a topic and a sequence number. So I played around a bit with the final url's:

http://www.thevorpal.be/Blog/Posts ==> Returns page 1 of a list of posts
http://www.thevorpal.be/Blog/Web-development/Post/1/The_bear_*****_in_the_woods ==> Returns a post
http://www.thevorpal.be/Blog/Tags ==> Returns page 1 of a list of tags
http://www.thevorpal.be/Blog/Posts/ByTag/the-vorpal-story ==> Returns page 1 of a list of posts of tag 'the-vorpal-story'
http://www.thevorpal.be/Blog/Web-development/Posts ==> Returns page 1 of a list of posts of topic 'Web-development'

Added to the readability and logic of the url's I also added slugs as recommended by a friend. Slugs are a replacement for names / titles that can contain spaces or characters that aren't valid in a URL. I should have thought of this a lot sooner actually.

To implement these url's I used ASP.Net attribute routing. It's a new way of routing, now standard in MVC5 and allows you to define the route to a specific action by using the 'RouteAttribute'. MSDN has a great blog post about this. While I do like the new attribute routing for its simplicity. I am quite annoyed because it's not really neat. The older way was not perfect, far from it, because it got way too cluttered and it was just too hard to create simple standalone routes. But your routes were centralized, when a page wasn't found, you knew where to find it. Attribute routing has the distinct advantage to know exactly where your url's are going, but it has the disadvantage of not being able to change all routes from a single location.

I recently worked on a project using NancyFX and I believe these guys/girls have gotten it right. Working with Nancy was a charm, response times are low and you knew exactly what you were doing. It's that bit more work you got to do to get things set up, but you don't have to do extra work to change all the default behaviour because that never works the way you want it to. I will be writing about this project probably next month or so.

Newer Older Top
blog comments powered by Disqus