robert hahn a darn good web developer

Building User-Programmable Websites

One of the things that I immediately picked up on when I studied Representational State Transfer (REST) was the notion that you could apply Object Oriented terminology to URI’s quite easily. Assuming that http://roberthahn.ca/ was a prompt, URI fragments such as book/search seemed to be pretty obviously an object/method call. In other words, if you were to see this in program code, you’d probably see book.search() .

With that realization, I saw a couple of avenues were thought experiments could be conducted. The first avenue that I’d like to discuss is whether it’s considered legal to actually write object/method calls in the URI. I haven’t properly finished this research, but my first look through RFC 3986 seems to suggest that while characters such as parentheses are reserved, whether they need to be encoded depends on the scheme that you are using. As far as I know, parentheses do not require encoding for the http scheme.

Ok, so what does that buy me? That question segue’s neatly to my second avenue of research. How could I write programs with URI’s? If want to design an OO interface to your application, you’d realize that the only thing to do is to predefine a set of objects and methods, and expose the API to prospective URI hackers, which I’ll dub ‘yurihackers’.

So: Let’s consider a hypothetical developer, Alex, building a web enabled address book for me, and wants to build some kind of API for people who will be using this. For the purpose of the exercise, I’m setting aside any considerations about how user-friendly writing OO syntax is, because I’m talking to you-the-developer here. If I’m leaving anything as an exercise to the reader, figuring out how to make this user-friendly will be it.

We’re going to start small, and we’ll basically talk about three kinds of data this address book will store. Those would be names, addresses, and phone numbers. Alex decides to set up three URI-queriable objects: Person, Address, and Phone. He then adds a basic set of methods for these objects, and, for the sake of keeping this post less long than it already is, preloads my addressbook data, into the database. NOTE: all the URI’s you’ll see DO NOT work - this is a hypothetical example, ok?

Excited to have at last a web based, programmable addressbook, I try out a search:

http://roberthahn.ca/Phone.find(area_code=519)

And I get a list of phone numbers in the 519 area code. Hmm… I think I’m going to need that. Let’s save it:

http://roberthahn.ca/p=Phone.find(area_code=519)

So far, since I’m typing all this into a browser, the natural response would be formatted as HTML. What if I wanted it formatted in Atom?

http://roberthahn.ca/p.atom

This search engine is pretty dumb. As I said, I just get a list of phone numbers that matched my criteria - no names, no addresses. In fact, the search method is so dumb, it just does a literal substring match of the term 519 to the area code field in the database. This level of dumbness is exactly what I want, since Alex has thoughtfully provided me with tools to process my own search results in a way that I find relevant to me.

Realizing that the 519 area code will include numbers local to London, Ontario, and Waterloo, ON, I’m thinking that it would be good to filter down that list so that I’m only seeing Waterloo phone numbers. Let’s try something:

http://roberthahn.ca/w=Address.find(city=Waterloo)

And we get a bunch of Waterloo addresses. No phone numbers though. Thankfully Alex added a Results object with some handy methods, like ‘match’:

http://roberthahn.ca/pw=Results.match(p,w)

And what we’ll get back are a list of phone numbers matched up to their addresses. Obviously an explanation is owed at this point, but I’d really like to get the people’s names first, then spit out the results as a tab delimited format.

http://roberthahn.ca/n=Names.find_all http://roberthahn.ca/npw=Results.match(n,pw) http://roberthahn.ca/npw.tdf

Ok, so let’s talk about what’s going on. If you have any experience building web apps, the first thing is obvious: you have to involve a session cookie or this whole exercise is pointless.

The next thing to realize is that if I make an assignment like this: n=Names.find_all then i’d have to store that string in a database, linked to the session, so that if I might need n later on, the server will have a way to find out what it represents.

Outputting data to different formats really should be a straightforward exercise if you’ve built your app in such a way that the view logic is separated from the business logic, and that the same view logic is applied to different file formats. One of the best known apps that play with this idea is blosxom, which has been one of my favourite blogging tools for a long time. As long as you have the necessary format files prepared, all you need to do to use them is change the file extension on the URI.

The Results.match() object is probably the most interesting aspect to this because what’s being enabled is the possibility of accessing an object not linked to a database for the purpose of processing search results in a useful way. This object works simply by examining the arguments passed to it, and looking up the assignments in the saved set of searches for that user’s session. Once the assignments are found, they are then processed so that Results.match() has a set of data to work with. It should be pretty easy to dream up other methods to add to the Results object that would further improve it’s usefulness.

There perhaps is only one more gotcha left in this idea - how can we parse these URI’s in a sane way? Regex’s are obviously out of the question. The inspiration for the answer came to me from this article at perl.com: Lexing Your Data - in short, build a Lexer parser designed to tokenize your URI’s and turn them into something your application can use.

I haven’t yet had the time to realize these thought experiments as working code, but the notion seemed interesting enough that I wanted to share it first. If you see some problems with this, please let me know. If you don’t get it at all, I’d like to hear that too. And if you build something, let me see how you did!