Handling variations of a page (or, the revenge of REST)

February 23, 2011

Suppose that you have a web application with users, and different users (or different sorts of users) need to see slightly different versions of various pages and forms. It's both obvious and very tempting to implement these page and form variations with conditional logic in a single URL's view handler; you have to retrieve the user's information anyways (and check access permissions), so you simply put in some checks and switches based on what sort of user they are or what permissions they have.

(This is also the sort of situation where you start reaching for features like on the fly modification of what fields are included in a form, read-only fields, and so on.)

Through recent hard experience, I've come to feel that this is a mistake. What you should really do is put each separate version of the page or form on its own distinct URL.

The problem with having all of the versions of the page accessed through the same URL is that you have no simple, good way to give a single user access to more than one of them. You can't easily handle things like a user who has multiple roles that would get different versions of the page, or allowing administrative users to drop down to simpler, more restricted interfaces (or even to see the simpler interfaces for training purposes).

(I've recently stubbed my toes on both of these cases. Our current workarounds for both of them are unaesthetic and awkward.)

You can solve this several ways, but the easy solution is the RESTful way. Given that you actually have different (albeit closely related) pages, you should give each different page a distinct URL. Among other advantages, this means that users can immediately use as many different versions as they have permissions for just by going to different URLs.

(Under the hood you might still use all of the dynamic form modification and conditional templates and so on that you used to; it's just that now you're making choices based on the URL instead of the user's data. You only use the user's data to insure that they have access to this version of the page, and you needed to do those access checks anyways.)

What this really drives home for me is that REST is a really good idea. The moment I hid application state in my code instead of exposing it in my URLs, it bit me, just like REST told me it would. I can only hope that I'll learn the next time around.

Sidebar: how to avoid complicating URLs in the rest of your application

So, now you have three or four URLs for different versions of a page instead of a single page that displays differently for various people. How do you link to it from other pages? In particular, do you have to put conditional logic (or special rendering tags or the like) in your other pages that look up what version of the page the user is entitled to and link to just it?

My answer is no. Suppose that you have three different versions of a creation page (for three different classes of users), and you put them at /manage/create/sponsor, /manage/create/gradoff, and /manage/create/staff. Set up a fourth page, /manage/create/. What this page does is look up what the user can access, pick the preferred version, and answer with a HTTP redirect to it. Once you have this set up you can just point all of your outside links to /manage/create and everything will just work. Knowledge of what the user has access to and where they should wind up is now localized in /manage/create; no one else has to care.

This scheme gets a bit more complicated if you need to pass components of the URL through, if you have eg /manage/edit/<id> and it needs to be redirected to one of /manage/edit/staff/<id> or /manage/edit/sponsor/<id>. But this can be handled too with a bit more work.

Written on 23 February 2011.
« A quick tour of my desktop
Why I am not enthused about ZFS for my root filesystem »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Feb 23 21:58:13 2011
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.