Clojure Web Development WAR Style With Gradle
I don’t normally use Clojure to do web development, at least not in the full stack sense. I normally use Grails with the Clojure plugin. In short, I use Groovy and Grails to deal with the mutable stuff, and call Clojure function as if it’s a blackbox.
Lately, using Clojure for web development seems to be a hot topic. I decided to explore it a bit to see where things stand. I’ll be using Gradle 0.9-preview3 as the build tool, with Clojuresque as the plugin. Unlike other tutorials you may have come across, my focus is producing WAR files so the output can be deployed in any application server like Tomcat.
To start, all you need is to install Gradle 0.9-preview3, and download Clojuresque as outlined in the first 2 steps here
Someone pointed out the change from yesterday’s Clojuresque broke it. So here is the link to the one I built from last week.
Once you have it working, first create a sandbox directory called “webexample”. Inside, you want to create a file called build.gradle
apply {
plugin 'clojure'
plugin 'war'
plugin 'jetty'
}
group = 'com.example'
version = '1.0.0'
warnOnReflection = true
aotCompile = true
clojarsUpload = false
//jettyRun.contextPath = '/'
repositories {
clojureReleasesRepo()
clojureSnapshotsRepo()
clojarsRepo()
mavenCentral()
}
war {
copy {
from 'src/main/clojure/views'
into 'src/main/webapp/WEB-INF/classes/views'
}
}
dependencies {
compile 'org.clojure:clojure:1.2.0-beta1'
compile 'org.clojure:clojure-contrib:1.2.0-beta1'
compile 'ring:ring-core:0.2.5'
compile 'ring:ring-devel:0.2.5'
compile 'ring:ring-servlet:0.2.5'
compile 'compojure:compojure:0.4.1'
compile 'enlive:enlive:1.0.0-SNAPSHOT'
}
The aot is set to true because we need to produce class files for the servlet. The only other special task is the copy task inside WAR. I keep all the Enlive template in src/main/clojure/views because enlive needs to see it there during compile. However, when a WAR is being created, those template files need to be in WEB-INF/classes/views otherwise your classes can’t see it. So I create a copy task whenever a WAR is being created. As you can see from the dependencies, I’m using the latest shiny version of everything.
You may also notice jettyRun.contextPath = ‘/’ is commented out. I’ll come back to this later.
Now create src/main/clojure/mywebapp directory. It’s time to write the first servlet. Create firstservlet.clj with the content below
Some of this will look familiar to you. I’m using the same example as shown by Mark McGranaghan in his post of the same topic.
There are a few differences. I’m using gen-class because I need to create the servlet. The route pattern instead of just “/”, each of them has the web context prefix. Gradle by default, places your webapp under the context of the same name as your sandbox directory. So it would place it under webexample in this case. But Compojure’s route matching doesn’t take context into account. I was totally stumped by this. Thanks to the James Reeves and Saul Hazledine on the Compojure mailing list’s help, I got this to work. Now you know why I left jettyRun.contextPath = ‘/’ in the build.gradle file. That was the other way to solve the problem. Instead of having /webexample in every route, you can tell Gradle jetty plugin to run your webapp at contextPath /. But in general, I don’t think this is a good idea. On our application servers, we have a lot of apps deployed, each under its own context. I don’t think you can assume your app will always be deployed as ROOT.war. James has stated he’s working on a middleware to take care of this.
Having defined the routes. It’s time to write the heavy lifting part. Create src/main/clojure/mywebapp/add.clj
I’m using Enlive for the template. There are also two other functions for returning the result in either JSON or XML.
We still need the template though
Create src/main/clojure/views/addtwonums.html
I really like Enlive. I first saw this style of template system in Wicket. I also like it quite a bit in Lift. Lift calls this “View” first. For a functional language like Clojure, I’m not convinced the traditional MVC is a good match. Clojure has not yet found its own voice in web development up to this point.
One last detail to take care of. We need to define a web.xml file. So create src/main/webapp/WEB-INF/web.xml
That’s it. You can run it by using “gradle jettyRun”. It will compile everything, and start jetty for you. Try out some of the urls
http://localhost:8080/webexample/
http://localhost:8080/webexample/view
http://localhost:8080/webexample/add?a=1&b=2
http://localhost:8080/webexample/addjson?a=1&b=2
http://localhost:8080/webexample/addxml?a=1&b=2
You can produce a WAR file by using “gradle war”. It will produce a WAR file in build/libs. You can take that WAR file and upload it to tomcat, it will just work.
There is also another downside with this approach. Anytime you make any changes, you’ll have to restart.
One of Clojure’s strength is the fact it runs on JVM. For those of you that want to produce WAR files so you can run Clojure code on existing JVM application servers, I hope this is useful to you.
I also want to thank Meikel Brandmeyer for continuing to work on Clojuresque and his tireless support.


Is there something wrong with the latest 1.4.0-snapshot?
When I run it (on Ununtu) I get:
FAILURE: Build failed with an exception.
* Where:
Build file ‘/home/ems/Projects/glensprojects/trunk/webexample/build.gradle’ line: 1
* What went wrong:
A problem occurred evaluating root project ‘webexample’.
Cause: Could not find property ‘development’ on configuration container.
* Try:
Run with -s or -d option to get more details. Run with -S option to get the full (very verbose) stacktrace.
BUILD FAILED
Total time: 4.494 secs
Looks like the most recent change from yesterday in his hg repo broke it. Here is the link to the one that I built from last week. http://m.3wa.com/img/clojuresque-1.4.0-SNAPSHOT.jar
This is great, looking at the code you could come with a framework in clojure same as the Ruby Sinatra http://www.sinatrarb.com/
funny you should say that. Compojure, which I’m using, is very much inspired by sinatra.
[...] web dev, WAR style using #gradle (here, via @wmacgyver) — Following Mark McGranahan’s recent article about building webapps [...]
Things are fixed. Snapshot on clojars. The “clojarsUpload = false” is not necessary anymore. Instead do:
uploadArchives {
clojarsDeploy()
}
if you want to deploy to clojars. No action is needed otherwise.