After posting quite a few times in June, I slowed down and I posted just once (book review) in July-August. One of the reasons for that is that it was quite busy period for me. I thought that I'd like to get back to writting by posting some cool stuff in here.
Recently I've read two books about Gradle build system, I've even reviewed here one of them. I decided to create an application that is built with Gradle, so that I can get more practice with it.
As cloud computing is getting more and more popular, then I thought I will create an app that will be run on Heroku platform. The application will use Spray-Can server for creating scala, actor based web application. The application will offer simple REST application and use spray-json module for json conversions between string and case class representation.
In first step we will create a build file (build.gradle) that will tell gradle what dependencies are needed for an application, how to get them and how to create a result package
We define 2 repositories that we will be getting dependencies from. There are few dependencies that include scala library and akka and spray modules. We define here a new task - "stage" that will be run later by heroku. Basically it will just trigger two other Gradle tasks: clean and installApp. The latter will gather dependencies and create a distributable package with a script that will run the app.
Some of you might be wondering what Akka is. Let me just tell you that it is an innovating and exciting framework for building scalable, distributed systems. It is used internally by Spray and will also be used by me in the app.
Now we need to write some Scala code for an actual application.
Creating Spray app
First let's create scala's App.
It just initializes Akka's actor system and creates an single actor in there (actor of class HelloWorldActor). Then there is a binding of this actor to port provided in environmental variable, or 8080 if not provided at all.
Let's now put our focus on the behavior of this actor. We will be creating REST api based on json, so I've created some code for our domain and conversion of it's case class to json (and from json to case class as well if needed).
Now, the behaviour of HelloWorldActor:
In Spray (or Spray-Routing, I should write), you create something called route, which is a set of routing rules. HelloWorldActor is basically just running the route from trait HelloWorld. You usually keep these two things separated as it allows you to unit test is more easily.
Route defined in HelloWorld specifies that whenever there's a request for path api/persons/X, convert X to an integer and run a closure that returns json object with my name :). As you see in the snippet above, to get json representation of case class I can just use .toJson method on Person - there is similar method to get case class from a string.
The app should be runnable by now. You can just "gradle run" and check the result in http://localhost:8080/api/persons/5
Deploying to Heroku
Now that we have a runnable application in place, we can think of running the app in the cloud. To run this app on Heroku, we need to provide a special file: Procfile. It will tell Heroku how to actually run the web application.
The Procfile can contain just a single line:
As you see, Heroku will just invoke the script that was created by the installApp task of Gradle's application plugin.
As last point, I'd like to tell you that Heroku's official build-pack (set of scripts that build the app) for Gradle based application is
a bit outdated and most probably this application cannot be run straight away.
But I've already forked Heroku's gradle build-pack repository on Github and updated it to fetch newest Gradle version (1.7). You can freely use it by setting an enviromental variable using heroku console:
That's basically it! Our REST API should already work on heroku. I've created repository on Github with the code of that application with even some more additions. As you see, creating app based on heroku,spray and gradle was pretty quick and easy.
Writing this post was fun and I look forward to posting again. I think that next time I might write about running web application on Raspberry Pi... :)