Resting Fox

It may not take great powers of intuition to put my last two technical posts together and figure out that I’m making a REST interface to a FoxPro database. (Plans only include GET access at this point.)

We’ve had a ‘cesfixes’ (CES being the name of the company) FoxPro application for a while to provide custom reporting. However, this only provides screen, printed, and sometimes spreadsheet output, all of which require manual operation to produce. I put ODBC to good use for a Perl database conversion system (I didn’t know the first thing about FoxPro at the time and thought the regular expression capability would help with data munging), but then you need FoxPro ODBC drivers on the client machine, which have to be configured, and are only available for windows.

Initially I expected to use a CGI application executed by a dedicated web server. As I looked into the mechanics of this, however, I ran across some bothersome trends. Startup speed was reported to be wanting. There ere ISAPI modes, but that required Microsoft’s IIS (of uncertain availability on our servers), or a reportedly buggy Apache ISAPI implementation. Then I ran across the FoxPro web servers.

One was shareware (our budget consists of begging the CEO for every purchase, and this is a an experimental R&D project) That left Eetasoft Eeva.

The hard parts get done in a COM control, with FoxPro code handling things at the HTTP level. The server actually supports ASP style code execution, but I’ve been avoiding that feature in case we ever need to switch to a dedicated web server with a client program. At this point I’m running a heavily modified version of it. I intend to offer the changes back to them by way of thanks once it seems fairly stable. The main thing I wanted was PATH_INFO style arguments, which make REST possible. The PATH_INFO is Apache’s (and possibly others) way of passing extra URL information – once the web server finds a cgi handler, the remainder gets stuck in PATH_INFO. So /cgi-bin/beep/really/loud would get ‘really/loud’ as path info. In order to figure out how to do that, I performed a major re-factoring of the HTTP handler. It’s possible I made it less efficient with the finer grained function breakup, but that can always be undone later if it proves to be a problem.

Actually, I ended up passing the entire URL to my REST handler, outside the web server proper. For one thing the user functions are implemented as a class library (where method inspection is used to validate URLS), and class libraries are a pain to develop with in FoxPro. If you using non-class code, you can usually edit the file and just use it. Class libraries can’t be edited when the program is running, and the program can’t run while the library is open. You can also define classes in code – at which point every time you stop the program it will ask you ‘Cancel?’ followed by ‘Remove classes from memory?’; um, yes, that’s why I canceled. In any case Eetasoft used a class library, which would add a lot of friction to the development cycle. So I have one default handler in the class library that calls out to a nice dynamic ‘PRG’, or code file.

Once it hits the REST handler, URL lookup is entirely database driven. The matcher walks down the path, trying to match the current component against a single level href, along with a context built up from previous matches. A database entry looks something like this:

title: Parts
context: /{db}
href: parts
kind: parts
execution: (blank)

title: Parts master
context: /{db}/parts/master
href: *
kind: {part_no}
execution: DO PartsHTML IN parts.prg

The curly bracket variable portions are an idea I picked up from an article I ran across during my research (which isn’t immediately presenting itself to me now) The author was using them as a sort of protocol specification that could be given to clients, but I found it pretty handy in the database lookup.

As the parser operates it builds up two paths: the concrete path (/southelgin/parts/master/12345) and the abstract path (/{db}/parts/master/{part_no}) The concrete path can be used for child URLS. the abstract path feeds later steps in the paring sequence. This ‘simplest possible method’ has important implications for the legal URLS. In short, the current implementation could not handle having both ../parts/12345 and ../parts/all, ../parts/type/.. etc. The ‘*’ for the part number would always match (and sometimes the constants) and the database query would return multiple rows. There are various ways to handle this (multiple passes, adding deeper validation than ‘*’, backtracking) but for now I’m embracing the un-ambiguity of the URLs.

I have a feeling that there is a general lesson about grammars in here, but I haven’t looked through my programming languages book enough to identify which class of grammar I’ve got. Actually, re-reading the book might be a good idea – I can probably understand a lot more of it with all the learning I’ve been doing lately.

In any case, the URL probably matches, The variable substitutions are stored and made available, via a GetParameter wrapper function, to the report generation functions in a manner indistinguishable from CGI parameters. So /parts/master/12345 is no different from /parts/all?part_no=12345 from that level. Which is handy, because one can be interactively browsed from root, (the intermediate browse pages are built automatically from the URL database – just find everything with a matching abstract context) and the other is compatible with HTML forms.

I’m at the point now where I’ve got five or six reports running. They can be built up fairly fast, but I’m starting to see a lot of code duplication. It may be time start putting up with the class headaches to get some cleaner re-use and inheritance. Some form of re-factoring is needed at minimum. I also need to address application packaging. I left the PRG files separate hoping to replace them live, but outside the development environment the program has the files locked and you can’t just copy a new version over it. With no piecemeal update benefit, copying around a bunch of separate files is a pain. I may leave a few groups separate (the foxpro html generation libraries haven’t changed since the first version, for instance) but some distribution file consolidation is definitely in order.

Posted Saturday, March 3rd, 2007 under Essay.

Comments are closed.