I’m using Snap in production!

Okay, it’s a tad less impressive than I might have hoped, but we’ve now officially deployed Snap into production in my job at Brindle Waye!

The funny part is, we didn’t deploy a web application. Instead, we provide offline preview in your choice of web browser for our web-based training authoring tool. We build the page and save it, but various web browsers don’t like running a lot of JavaScript stuff in a web browser running from a file-scheme URL. So in the latest version released a couple days ago, we actually spawn a Snap-based web server to serve the pages from some unused high port number on the loopback interface. Works great!

Why’d we use Snap for a static web server? Initially,

We wanted to bundle the thing with our application and not fiddle with configuration files, registry settings, and the like.

After a lot of searching, we could find no suitable, free, portable, simple web servers that don’t require excessive amounts of configuration.

Snap was handy, and it was no problem to throw together a two line application to serve a directory. (Two because we read the directory path from the command line on the first!)

Turns out that as we solidified and idiot-proofed the feature before release, it was nice that we used Snap for other reasons, too. We ran into some quirky requirements that would have been tough to satisfy with another server, like:

If the initially chosen port is already in use, we want to walk up port numbers one by one (we’re already in the dynamic/private range) trying to bind to different ports until we find one. Of course we then want to change the port number on the provided URL, so we launch the browser from the Snap-based server following a successful bind. Not only would these be tough to accomplish with a static web server; I don’t even know how I’d get something like Tomcat to do it! Being able to write your own main in the Haskell web programming world is nice.

We want to have the local web server shut down if there’s x minutes of inactivity. (I’ve honestly forgotten what x is here.) We normally terminate it on our own, but in case the main application crashes or there’s some bug where it’s left running, it’s nice to have that safeguard. I’m not sure how we could have measured time since the last incoming request using a static server.

To prevent some weird cache issues (related to the fact that if you swap between courses, we serve serving files from different physical directories with the same URL), we wanted to add Cache-control: no-store to prevent caching. Normally that requires yet more configuration files in Apache, and in a servlet container I might have had to lose the default file serving and write the file contents out by hand to the relevant OutputStream… but with Snap I just toss in a line right before the call to serveDirectory and add the header!

It definitely feels good that something like this — a really quirky set of requirements, for serving files in a setting that was completely unexpected to the people who wrote the server — was difficult to imagine with any other software we found, but easy in Haskell! Granted, we didn’t look at too many other languages’ application servers, but we did search the Java world (because that’s the language the authoring tool is written in, and we already install a JVM) for a while. Haskell was a refreshing change from tools where just copying all the relevant files to the right places was a daunting task.

This isn’t specific to Snap, either; I could have done this just as easily with Happstack, and probably Yesod (or bare WAI) as well. This just tells me that as a Haskell web programming community, we’re doing something right.