I've been wondering lately — what good having the server-side web application generate URLs when the client side code is just as capable? Indeed, there is no way we'd ever want to hard-code the application URL paths inside the Javascript code. So why even entertain the notion?
Speaking in terms of overhead — with each URL on a given page, some CPU expense is incurred when constructing each URL. I'm making a presumption here in assuming URLs are in fact being constructed and not just hard-coded in templates. In reality, the overhead is inconsequential, but in some generic circumstances, I see absolutely no reason why these URL's can't be assembled locally on the user's browser.
Why URLs Are Constructed
It's for the best that URL's passed to the browser by the web application are constructed rather than stored statically. Ad-hoc construction of URLs doesn't solve any problems either. For example, if on one page you're formatting a string that'll be returned as a URL, and on another page, another set of URL construction functionality, it's difficult to establish patterns of reuse. Sure, we're able to share some of this code among our application's components — but why should we have to define this capability ourselves?
Look no further than Django's
URL resolution architecture for an example of how URLs are specified in one place and one place only. These are base URLs — they can take on different forms by inserting values into path segments. For instance, search strings or object identities.
The rest of the Django application can construct —
resolve in Django-speak — the URL to use. What I really like about this methodology is that URLs are treated just like classes in object oriented programming languages. The URL
blueprint is defined once, individual instances of the URL are constructed as many times necessary. Some URL instances are simple — they take no additional attributes. They have no path segments to fill in or no query strings to append. In the case of more complex URL instances, we have the URL resolution framework at our disposal — a consistent approach to instantiate our URL blueprints, passing in any additional details the URL class requires in order to make them unique and identifiable.
The theme here being that URLs can, and should be, a generalized concept — just like other systems we build. We're able to abstract away much complexity into classes, instantiating objects, letting the class machinery take care of eliminating what would be otherwise redundant repetitions of URL construction code. Sticking with the Django URL resolution architecture as the example, because it illustrates so well how URLs can be constructed, consider user interface code. The templates. The Django template system comes with a URL
tag to help instantiate URLs directly in the user interface. Again, when templates are rendered, we're injecting URL instances into the template. It's from here that we can follow the logical extension into generic URLs in Javascript.
Javascript And URLs
Javascript can do a lot with URLs that the web application, running on the web server doesn't necessarily need to deal with. But why would we want to use Javascript? Shouldn't we stick with the URL construction kit offered by the web application framework? Well, for the most part, I'd say yes, it is a good idea to use things like the
url tag, if you're building a Django template. Stick with the infrastructure provided for building URLs and you'll never worry about whether the correct URL is passed to the user interface. Just reference the URL blueprint by name and let the URL instance take care of the rest.
User interfaces in web applications follow patterns. That is a given. From one page to the next, controls repeat themselves. Things like pagination come to mind. Any given page with a list of objects on it uses pagination controls as a means to avoid dumping every object on a single page — making it impossible for the user to navigate in a cogent manor. The common items, or, generic items rather, are the
list and the
paginator. The list of objects and how they're rendered can be generalized inside the Django template. As can the pagination controls. These controls move back and forth through a set of objects — usually by appending constraints on the URL.
So how does this paginator change from one set of objects to the next? How does it distinguish between one type of object list and the next? Well, the reality is that it doesn't change much for different object types, or, at all. Forward in motion and backward in motion. Generic behavior that doesn't necessarily warrant using the URL resolution system. Any Javascript code that runs on the page already knows about the current URL — just look it up in the
window object. We know how to move forward and backward through a list — just update the current URL. For instance, the browser URL is simply updated from
/objects/page1 to
/objects/page2. There isn't a need to invoke the URL construction code for this — let the client take care of generic things like this where it makes sense while saving server CPU cycles for more important things.