Deploy and Run Spark(java) on Heroku.

March 28, 2018

Couple days ago I build my PoC (Proof of Concept) project based on Spark (java) framework. It was REST API which I deployed and run on Heroku cloud platform. The Dev process was really rapid and I am going to share my experience how to quickly create REST API and run it on Heroku. As an example of I am going to implement simple temperature converter.

Spark+Heroku

Requirements or tools

  • Java 7/8. I tested my app on Java 8 but I think it should work on Java 7.
  • Groovy. I use Groovy 2.5.3.
  • Maven. I use Maven only for letting know Heroku that I deploy Java Project
  • Spark. Spark Framework is a simple and expressive Java/Kotlin web framework DSL built for rapid development.

Project structure

The project structure is really simple. There are simple groovy script, pom.xml and Procfile.

1
2
3
4
5
├── Procfile
├── README.md
├── converter-api.groovy
└── pom.xml

As I mentioned I use Maven only for Heroky deployment process see details here. All logic located in converter-api.groovy.

Spark framework

As I mentioned Spark framework is a simple Java web framework, DSL based.

Spark intro

Spark provide declarative and expressive syntax it is really simple framework. You can find detailed documentation here. I am going to explain only basic conception or build blocks. All “build blocks” presented as static methods of Spark class.

Routes

Routes - the main build block of Spark Framework. By using Router you can handle all HTTP verbs - GET, POST, PUT, DELETE, HEAD, TRACE, CONNECT, OPTIONS. Verbs presented as static imported functions with arguments: (path, acceptType, callback, transformer). callback can receive request and produce response. See more details here.

Request

Request contains request information itself and functionality is provided by the request parameter. Attributes, cookies, headers, ip, host, params, etc. See more details here.

Response

Response, in its turn, contains response information: body - response content, header - set headers, status - response HTTP status, etc. See more details here.

Controller source code

Due to using Groovy and Spark framework source code on API PoC looks graceful and short.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Grab('com.sparkjava:spark-core:2.7.2')                                     // 1
@Grab('org.slf4j:slf4j-simple:1.7.21')

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import groovy.json.*
import static spark.Spark.*

def toJson = { JsonOutput.toJson(it) } as spark.ResponseTransformer          // 2
Logger logger = LoggerFactory.getLogger("Main")
float RATE = 1.8000
int GAP = 32

port(System.getenv("PORT") ? Integer.parseInt(System.getenv("PORT")) : 4567) // 3

get("/health", { req, res ->
    return [status: "UP"]
}, toJson)

path("/api", {
    path("/convert/to", {
        get("/celsius/:temperature", { req, res ->                            // 4
            float temperature = Float.parseFloat(req.params(":temperature"))
            Map result = [celsius: ((temperature - GAP) / RATE), fahrenheit: temperature]
            logger.info("Fahrenheit to Celsius: " + result)
            result
        }, toJson)                                                            // 5

        get("/fahrenheit/:temperature", { req, res ->
            float temperature = Float.parseFloat(req.params(":temperature"))
            Map result = [celsius: temperature, fahrenheit: ((temperature * RATE) + GAP)]
            logger.info("Celsius to Fahrenheit: " + result)
            result
        }, toJson)
    })
})

You can find this code in my repo alex-bezverkhniy/converter-api-sample

  1. I use Grape (Groovy Dependency Manager) to add two dependencies
  2. Spark allow us to intercept HTTP responses with spark.ResponseTransformer and apply same transformations on it. In my case I do JSON transformation.
  3. Port settings. Using ENV variable to get port number withing Heroku dyno
  4. Routes definition. By :temperature I define request param for passing temperature.
  5. By using Groovy Closure I pass ResponseTransformer to my Route.

Run on local

To run this API locally you have two ways: via Groovy script and via Heroku CLI.

To run as Groovy script use next command:

1
2
groovy converter-api

To run via Heroku CLI use next command:

1
heroku local web 

But before you need to create a new empty application by using next Heroku CLI command

1
2
3
heroku create
Creating app... done, ⬢ <your project name>
https://<your project name>.herokuapp.com/ | https://git.heroku.com/<your project name>.git

For more the details please see official documentation

Deploy and run on Heroku

To deploy on Heroku you need to push your changes to heroku master:

1
2
3
4
git push heroku master
Initializing repository, done.
updating 'refs/heads/master'
...

Use this same command whenever you want to deploy the latest committed version of your code to Heroku.

Testing

To test application use next requests:

Health check

1
curl -X GET http://<your project name>.herokuapp.com/health | python -m json.tool

If application works well you should see next JSON as a result:

1
2
3
{
  "status": "UP"
}

Convert fahrenheit to celsius

1
curl -X GET http://<your project name>.herokuapp.com/api/convert/to/celsius/10 | python -m json.tool

Convert fahrenheit to fahrenheit

1
curl -X GET http://<your project name>.herokuapp.com/api/convert/to/fahrenheit/10 | python -m json.tool

Instead conclusion

You can use this project as a template for your PoC. Fill free to ask questions and leave comments!

Written on March 28, 2018
groovy spark cheat-sheet maven gradle microservices heroku