Go Test It, the awesome new web testing product I am currently working on, was
announced on Monday. I had
hinted at it back in December, but now that it
is taking shape it was time for me to start spreading the word.
Please see the
Go Test It website for details about the product; in summary, it allows web
developers and QA teams to very quickly and easily record functional tests on their web application,
and plays them back in our own cloud-hosted cross-browser infrastructure. It is going to be the
fastest way ever to get started with cross-browser testing, and also provide great tools for running
your existing test suites. With
Go Test It, there will be no more excuses for not having great coverage of
automated functional tests.
On this blog I would like to share from time to time some of the
technical challenges we have overcome in the process of building this product.
Today: Simple REST APIs in Scala
The Go Test It system consists of a number of different components using different
programming languages, different frameworks, different infrastructures. The main user front-end is a
Rails app, but not all tasks are so well suited to Ruby. In particular,
the multi-threaded parts of the system which do a lot of the internal coordination are being written
in Scala, a very elegant JVM-based language which lends itself well to
this sort of thing.
The various components of the system need to communicate, and depending on the
type of interaction needed, we’re using a combination of a
message queue and
REST APIs. There is good Java
library support for both, and since Scala can seamlessly use Java libraries, it all fits together
very nicely.
Jersey is a really neat Java (and, by extension, Scala)
library for writing REST APIs. (It falls into a similar category as
Sinatra in the Ruby world.) For example, a resource which returns a
HTML document can be written in just a few lines of Scala code:
A resource is defined by a
class, annotated with the path(s) under which it can be accessed, and has one or more methods to
handle different HTTP verbs (GET, POST, PUT, DELETE), and if you want, also different methods for
different content types.
Coda Hale has written up
some really nice examples of using Jersey
and doing nice clean
error handling of input. His examples are in Java, but translating them into Scala is a very simple
exercise – more or less a matter of removing the type declarations and the semicolons.
But here comes the tricky bit. Given the beautiful code snippet above, how do you actually build and run the
thing? That is something I wrestled with for a while, and here I would like to reveal my solution.
You can build it with
Maven (for the Ruby guys, it is basically
RubyGems and
Rake rolled into one, intended for building Java projects with
automatic dependency management). The process is a bit scary, but once it works, it is magic – it
automatically downloads all the right packages, sets the right classpaths and packages up the
results of your build into a war file (web archive).
But the scary bit first. You need to declare
your dependencies and build properties to Maven, and the prescribed way of doing that is using the
most ugly XML configuration file on the planet. I’m really sorry for the ugliness, but I think it’s
worth it. However, the good news is that you only need to set it up once and never touch it again;
once your build is working, you can create resources and handle them in Scala to your heart’s
content. And for a bonus, see below for a Capistrano recipe which allows you to easily deploy the
resulting war file to a Tomcat server, again and again.
First, put the following in a file called pom.xml in the base directory of your project:
That was a terrible mouthful. Urgh. But worry not, the worst is over. Just one other XML file, and this one
goes in src/main/webapp/WEB-INF/web.xml:
And that’s all the boilerplate you need. You can now write the actual code, with Scala source files in
src/main/scala and Java source files in src/main/java (if you want to use Java alongside Scala).
For example, place the source for the Hello resource above in
src/main/scala/com/example/restapi/Hello.scala. Tests go in src/test/scala and
src/test/java respectively.
Now go and build it! (You need to have Maven 2.0.9 or newer installed.) The two most useful commands are
mvn package, which compiles and packages your project, and places the result in
target/restapi-1.0-SNAPSHOT.war, and mvn glassfish:run, which launches an embedded
Glassfish application server and serves your new REST API on
http://localhost:8080/ for local testing. The example resource which we defined above
would then be accessible at http://localhost:8080/hello in your web browser.
If you don’t have the dependencies
yet, Maven will go away and download them. This will take a while, but they won’t be re-downloaded
once you have them. It’s a bit frightening at first to watch Maven doing its magic, but in my
limited experience so far it has always done a good job.
Now for the bonus points. Just building
your app locally is not enough; you also need to deploy it to a server and make it accessible to the
world. In our case this is
Tomcat, but any standard Java web container should do. I wanted to use
Capistrano for deployment, because it gets a lot of things right and also
fits well into the rest of our system which does have a lot of Ruby in it. There is an existing
Capistrano recipe for deploying war files to Tomcat,
but it needed a bit of improvement, so my own version is included below.
These deployment instructions assume you’re running a
Debian Lenny system, with a
restapi user account; for other systems, you’ll need to customise it to suit.
Create the following shell script in /etc/tomcat5.5/symlink-webapp and make it executable:
Next, add the following line to /etc/sudoers:
With that set up, here’s the Capfile for you to put in the base directory of your project:
So there we go. For the first time use cap deploy:setup to create the directories on the server, and
thereafter always type cap deploy. Those 11 keystrokes are all you need to fetch all the dependencies (no more
troubles replicating your build environment on different development machines), build a clean copy
of the entire app, ship it off to the server and run it. And your app can be all in beautiful,
concise and type-safe Scala. I have survived the XML deluge and I am happy :-)
If you found this post useful, please
support me on Patreon
so that I can write more like it!