Copyright Notice

This text is copyright by InfoStrada Communications, Inc., and is used with their permission. Further distribution or use is not permitted.

This text has appeared in an edited form in Linux Magazine magazine. However, the version you are reading here is as the author originally submitted the article for publication, not after their editors applied their creativity.

Please read all the information in the table of contents before using this article.

Linux Magazine Column 70 (May 2005)

[Suggested title: ``Introduction to CGI::Prototype (part 1)'']

It's a rite of passage, they say.

Every new Perl programmer seems to want to create their own CGI form parser. And their own templating system. And their own way to parse @ARGV. And eventually, they even get fancy, and try to write their own SQL-eliminating database-as-objects wrapper. Or accessor autogenerator. Or lazy loader.

Or CGI framework. Yes, I'm now guilty of that, having created CGI::Prototype in the recent months, and shared it with the rest of the world. I hope to explain in the following paragraphs exactly why, and what it does, and how it does it, and why it works better than anything else I could find at the time. Please read on.

The problem

The main problem with web program design is that web applications are backwards. Let me explain.

In a traditional GUI application, the program is in control. The program puts up a widget onto the display, and drives the user into action. When the user is finished, the application then decides what to do, and displays another GUI widget for the user to then deal with. In other words, the application drives the user.

In a web application, the user says ``hey, I'll visit a web site''. The web application then has to respond to the user, providing some sort of web form (the web equivalent of the GUI) back to the user, after which, the web app is gone, dead, terminated. The user then examines the form, and if they so choose, fills out values and submits that form. A new web application invocation has to respond to this form, hopefully relying on notes that the previous application invocation left laying around in some server side database, and this happens repeatedly. In other words, the user drives the application.

So, every web application must figure out how to make sense of these seemingly unrelated hits coming inward. How does the web application maintain state, including credentials, intermediate results, database connections, and so on? This is a big problem, because although the highest level logic is common, the specifics are, well, specific to each application.

At the end of 2003, I was hired by a large unnamed university on the east coast to help develop a web application, getting as far as I could within the week that they had allocated for me. The application had some interesting goals: it had to talk to an existing Oracle application through a database; the look of the web app had already been prescribed by some HTML designers (a traditional multi-page form with the freedom to wander to any tab at any time); and it had to be flexible, because it was likely that the interfaces would change as more information was understood.

After spending the morning of the first day with the client trying to figure out what they really hired me to do, I got on IRC and PerlMonks and asked about existing frameworks with some particular requirements. After examining a few solutions, I realized by mid-afternoon that nobody had yet created a framework in a way that could be applied to this situation as I had wanted. So, being the resourceful guy I am, I wrote my own.

I knew I wanted to use Class::DBI for the database interface, and Template Toolkit for the display driver (both having large user communities, a bonus for my client). I also thought that I'd rely on the ol' workhorse of CGI.pm, mostly because it's had the most goings-over of any CGI form processor and HTML generator in the business, and I wanted to be conservative for my client.

This gave me the ``M'' and ``V'' of the famous ``MVC'' triad (a classic way of breaking down GUI frameworks into manageable pieces). A Model for the data, a View for the results. But where was the Controller? There didn't seem to be any detailed controllers in the CPAN that fit my client's needs directly (or configurably), nor anything like an abstract controller that I could subclass and extend as I saw fit. And that's where I sat back to think about every web application I had written.

Every web application

Every web application seems to have the following steps:

  1. Look at the incoming hit, and figure out the approximate rough state that we are in (initial hit, responding to some form, etc). Then dispatch to the code that will handle that broad category of hit.

  2. Attempt to respond to the hit, figuring out the details of the incoming parameters and cookies, and figure out what state we're now in, and select code to handle that.

  3. Finally, render a response, displaying results, errors, and most likely new forms to fill out.

The problem is, that errors can happen, and usually at bad times. For example, let's take the typical two-page ``form-and-response'' written with CGI.pm:

   use CGI qw(param);
   unless (param) { # no incoming parameters
     ... display the form ...
   } else {         # incoming parameters
     ... respond to the incoming params ...
   }

And this works fine. The first hit has no params, so we show the form. The response points back at the same script, so we see the params, and handle the form.

But what if the form wasn't filled out properly? Now we either have to figure out how to detect that before we dispatch to the ``display the form'' or ``respond to the params'' part, or we have to somehow get back up to the upper code after the lower code has been selected. Ugh.

My implementation

I decided that I wanted a very generic CGI controller, using an object-oriented model. Further, I had recently played around a bit with Class::Prototyped, and had really liked the way that subclasses could be created on the fly and that accessors were smart and autogenerated and dynamic. So, I decided that my top-level generic controller would be a Class::Prototyped-based object, and that helped define the name: CGI::Protoype.

The basic strategy is simple. The top-level application gets activated by the incoming hit, and calls the application's dispatch method. The dispatch method is responsible for determining the application's state, and then determine a particular controller to return to respond to that state. The respond controller then examines all of the available inputs, updating any external data, and then decides the new state, in the form of returning a render controller. The render controller spits out a page to send back to the user, usually by calling Template Toolkit on a particular template, and sending the result to STDOUT.

That sounds very complicated in theory, but in practice, it works out to be rather straightforward. You create an application class that inherits from CGI::Prototype. You then create one or more ``page/state'' classes that inherit from your application class, and a template for each page class that will be rendered to the user. You also need to create a dispatcher to decide which page class gets selected for a given state.

A sample program

The most trivial application you can create using CGI::Prototype is one that uses all of the defaults:

  #!/usr/bin/perl
  use base CGI::Prototype;
  main->activate;

Here, I've cheated, using main as my application class. Generally, you'll want to push this out into a real class for better testing. But this is indeed a complete application, and when hit, results in a small plain-text page that says ``This page intentionally left blank'', using CGI.pm for the header. Yes, cute. I know.

But this isn't a very interesting application. However, by overriding just one method, I can get a template of my choosing instead of the built-in template:

  sub template { 'mypage.tt' }

Now the main class has an overridden template method, which defines the template to hand to Template Toolkit. There, I've now got a template-running CGI application.

Looking under the hood

Let's look at what activate is doing, in essence:

  my $self = shift;
  my $this_page = $self->dispatch;
  my $next_page = $this_page->respond;
  $next_page->render;

First, the application's dispatch method is run to get a page controller object, which generally inherits from the application controller itself. (This makes it easy to move page-created methods up to the application level so that all pages can share them if needed.)

Next, the page controller object is asked to respond to the incoming parameters. When it completes, it is expected to return an object that will be rendered. Again, this is typically a page controller object that inherits from this application controller, and frequently even just itself ("$next_page" eq "$this_page"), especially when there are errors.

Finally, the $next_page object is asked to render something to the user, usually resulting in Template Toolkit being called on the result of $next_page's template method.

So how did the empty application work? Through the clever use of defaults. The default dispatch and respond return $self. The default template method returns the ``this page intentionally left blank'' template. So, it all ``just works''.

Of course, in practice, this is all enclosed in an eval block, like so:

  eval {
    my $self = shift;
    my $this_page = $self->dispatch;
    my $next_page = $this_page->respond;
    $next_page->render;
  };
  $self->error($@) if $@;

The default error method simply displays the string to STDOUT, with a text/plain MIME type so that most browsers will leave it alone. You'll almost certainly want to override that.

I've run out of space, and barely scratched the surface! Next time, I'll talk about overriding the dispatch and respond methods to create a real application, and about before and after hooks on all the steps to hang interesting behavior alterations. I'll also look at Class::Prototyped::Hidden, to handle the state recognition in an extensible consistent way. Until next time, enjoy!


Randal L. Schwartz is a renowned expert on the Perl programming language (the lifeblood of the Internet), having contributed to a dozen top-selling books on the subject, and over 200 magazine articles. Schwartz runs a Perl training and consulting company (Stonehenge Consulting Services, Inc of Portland, Oregon), and is a highly sought-after speaker for his masterful stage combination of technical skill, comedic timing, and crowd rapport. And he's a pretty good Karaoke singer, winning contests regularly.

Schwartz can be reached for comment at merlyn@stonehenge.com or +1 503 777-0095, and welcomes questions on Perl and other related topics.