Blog

RESTful API with Spark Kotlin

The not-so-mainstream way of building an API

BinHong Lee

March 21, 2018

When speaking of building a backend API, the most common tools is either Spring Boot for Java or ExpressJS for JavaScript. Even for Kotlin, Spring Boot and JetBrain’s own ktor is the usual option to go with. But today I’ll explore into the less popular option of spark-kotlin.

Disclaimer : I am not in anyway affiliated nor do I work at the project. I just simply stumbled upon it and started using it when working on a side project. (coming soon™)

Understanding REST

If you already know or built a RESTful API, you can skip this part. There are already quite a few guides out there that goes into the specifics of what REST is and all the amazing things about it. So instead, I’ll just cover the basics (more like, that’s all I know about it). It’s the standard way of communication on the internet through HTTP. In the world of internet, the frontend web interface needs a way to communicate with the backend. While the frontend can say all kinds of things, they still need to declare a set of standard ‘phrases’ between them so the backend knows what the frontend is asking for.

Setting up

Here are a few thing you might want to have installed before getting started:

  • Maven / Gradle
  • Kotlin
  • Java? (not too sure but you’ll probably need it)
  • (optional) IntelliJ

Getting started

According to the official GitHub repo of spark-kotlin, here are the following things to include to use it for either Maven or Gradle. Personally, I’m using Gradle for this simply because I’ve never used it outside of Android Development. (Also, its the new sexy thing. Kinda?)

1
2
3
4
5
<dependency>
    <groupId>com.sparkjava</groupId>
    <artifactId>spark-kotlin</artifactId>
    <version>1.0.0-alpha</version>
</dependency>
1
2
3
4
5
dependencies {
    ...
    compile "com.sparkjava:spark-kotlin:1.0.0-alpha"
    ...
}

The basics

This is what attracted me to use it over spring-boot. It just looks so much easier and straightforward comparatively. Admittedly, I’ve never used spring-boot for server development so I could be totally wrong especially if/when it comes down to a large scale application.

GET request

1
2
3
4
5
6
7
import spark.kotlin.*

fun main(args:Array<String>) {
    get("/") {
        "Welcome to website abc."
    }
}

That’s it! I could’ve just ended the article here and you can pretty much figure out the rest on your own. But yea, let’s explore into a few more interesting features.

POST request

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import spark.kotlin.*

fun main(args:Array<String>) {
    post("/checkExist") {
        checkItem(request.body())
    }
}

fun checkItem(input:String): String {
    return if(exists) "Exists." else "Does not exist."
}

fun exist(input:String): Boolean {
    //Some check to make sure given string exist
}

For POST request, they work as easily too! All you need to know is that the request body can be retrieved with request.body().

More fun stuff

redirect(), params()

Now, what if you want to have the same output for separate links? Well, you can just do redirect("/path"). You can also get information from the URL through params(":path") tag. Something like this…

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import spark.kotlin.*

fun main(args:Array<String>) {
    post("/checkExist") {
        redirect("/checkExist/" + request.body())
    }

    get("/checkExist/:id") {
        checkItem(params(":id"))
    }
}

fun checkItem(input:String): String {
    if (exist(input)) {
        return "Exist."
    } else {
        return "Does not exist."
    }
}

fun exist(input:String): Boolean {
    //Some check to make sure given string exist
}

Instance API

You can also have a separate instance API that is running on a different port or with a different setting than the static API simply by declaring it as a separate variable.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import spark.kotlin.*

fun main(args:Array<String>) {
    val http = ignite {
        port = 4567
        ipAddress = "0.0.0.0"
    }

    http.get("/") {
        "Welcome to website abc."
    }

    http.get("/404") {
        status(404)
        "Page does not exist."
    }
}

Of course, there are a lot of more advanced features (such as session, uri, etc.) that I did not cover. Feel free to explore them on your own following the README of the repo.


From here on out, I’m including some relevant but not exactly spark-kotlin stuff on it.

Dealing with JSON

In many (or most) occasions, both requests and responses will be in JSON format. Here’s where Google’s Gson library comes in handy. It is really easy to use and had a wide range of support. I put together a simple example below to show how it is and can be used.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import com.google.gson.GsonBuilder

fun main(args:Array<String>) {
    // Some codes
    val json: String = "{\"id\": 32151986,\"info\": \"someWords\"}"

    // Creating the item from JSON
    val newItem: Item = GsonBuilder().create().fromJson(json, Item::class.java)

    // Creating JSON string from item
    print(GsonBuilder().setPrettyPrinting().create().toJson(newItem))
}

data class Item (val id: Long, val info: String)

Unit testing

It took me a while to find a testing library that works as easily as I wished. This is a test library made specifically for the spark framework by Despegar called spark-test.

 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
import com.despegar.http.client.*
import com.despegar.sparkjava.test.SparkServer
import spark.servlet.SparkApplication

class YourTest: SparkApplication {
    override fun init() {
        main(arrayOf())
    }
}
var testServer: SparkServer<YourTest> = SparkServer(YourTest::class.java, 4567)

class Tests {
    @Test
    fun getTest() {
        var get: GetMethod = testServer.get("/", false)
        var httpResponse = testServer.execute(get)
        assertEquals(httpResponse.code(), 200)
        assertEquals(String(httpResponse.body()), "Welcome to website abc.")
        get = testServer.get("/404", false)
        httpResponse = testServer.execute(get)
        assertEquals(httpResponse.code(), 404)
    }

    @Test
    fun checkExistTest() {
        val post: PostMethod = testServer.post("/checkExist", "someInput", true)
        val httpResponse = testServer.execute(post)
        assertEquals(httpResponse.code(), 200)
        assertEquals(String(httpResponse.body()), "Exist.") // or "Does not exist."
    }
}

A few things to keep in mind though:

  • This is a Java library made for spark-java instead of spark-kotlin
  • The server needs to be running on the background (in my case, on port 4567) for this to work
  • Unable to attach a request body for DELETE request

Note: As mentioned at the time of writing, the DELETE request is unable to attach any kind of request body to it making it hard to test your DELETE request. Personally, I use different URL each feature so I just redirect a POST request from the same url to the DELETE request and test it through the POST request instead. Not ideal, but it works for now.


References

This article was originally published on Hacker Noon.