Deploying to App Engine
In my last post, I set up a basic Hello World Compojure app, running on a local Jetty instance. Now I want to deploy this to Google App Engine.
Creating a Servlet
App Engine expects a standard Java web application, which means we have to take a small step out of pure Clojure-land into the Java realm and implement the HttpServlet interface. The defservice macro from the ring API makes this trivial.
Obviously, Google runs their own app servers, so we don't need to start a Jetty instance. The updated core.clj looks like this:
The project.clj file needs to be updated to reflect the changed dependencies:
Note that I added a :namespaces entry. This triggers the AOT compilation of the Clojure source into Java bytecode. [Edit] I also customized some paths - more on that below. [/Edit]
Google App Engine requires two config files, web.xml and appengine-web.xml. For my simple app, these are pretty straight-forward. The web.xml defines the mapping from URL patterns to servlet classes. Here it is:
The servlet name ("blog") is a generic identifier, you can use anything you like. The servlet-class needs to be the clojure namespace that implements the HttpServlet interface - in this case compojureongae.core.
In the appengine-web.xml we set the GAE application id and an arbitrary version string:
I set up a github repository for my experiments at http://github.com/christianberg/compojureongae
The code as of the time of this blog post can be found at http://github.com/christianberg/compojureongae/tree/v0.1.1
Building the war
[Update]
Sometimes things are much easier than they first appear. My initial "build process" (using leiningen-war) was way too complicated. Thanks to http://buntin.org/2010/03/02/leiningen-clojure-google-app-engine-interesting/ for putting me on the right track. Here's how I do it now:
The deployment artifact for GAE is a standard java war file - actually a war directory, i.e. an unzipped war file. This makes the build process pretty trivial, you just have to adhere to the standard war directory structure. This is accomplished by customizing the :library-path and :compile-path in the project.clj (see above). Building the project is simply done with the standard lein commands:
lein cleanlein depslein compile
The current stable version of leiningen (1.1.0) mixes the dependencies and the dev-dependencies. If you don't want the dev-dependency jars included in your deployment, run this sequence of commands before deploying:
lein cleanlein deps skiplein compile
The development version of leiningen (1.2.0-SNAPSHOT) separates the dev-dependencies into lib/dev, so you might want to check it out.
[/Update]
Now we have a war directory that can be used by the scripts that come with the App Engine SDK. If you haven't yet, download it now.
Testing the war
To make sure our war file is ok, let's test it locally. I unpacked the SDK in the directory $GAESDK. Here's how to start the local server:
$GAESDK/bin/dev_appserver.sh war
You should see the familiar page at http://localhost:8080/
Into the Cloud!
It's time to deploy. Just run
$GAESDK/bin/appcfg.sh update war
Enter your Google login when prompted and wait for the app to deploy. (Remember that you need to create an Application in the GAE admin dashboard first and put it's app id in the appengine-web.xml.)
The app is now live in the cloud. You can see my deployed version here:
Have fun! If this inspires you to do your own experiments with Clojure on App Engine, leave a comment below!
