Jan 28, 2017 • Written by David Åse Reading time: 0-0 min The source code for this tutorial can be found on GitHub . Please fork/clone and look while you read.

What You Will Learn

Setting up Kotlin with Maven

Creating a Spark/Kotlin CRUD REST API (no database)

Some neat Kotlin features

The instructions for this tutorial will focus on IntelliJ IDEA, as it’s made by JetBains, the same people who make Kotlin. We recommend downloading the free community edition of IDEA while following this tutorial, but there is also Kotlin support in Eclipse.

Setting up Kotlin with Maven (in IntelliJ IDEA)

The good people over at JetBrains have an up-to-date archetype for Kotlin. To use it, do as follows:

File -> New -> Project

Maven -> Create from archetype -> org.jetbrains.kotlin:kotlin-archetype-jvm -> Next

Follow the instructions and pick a project name

Create src/main/kotlin/app/Main.kt

There is no public static void main(String[] args) in Kotlin, instead you have a fun main(args: Array<String>) .

fun main ( args : Array < String >) { println ( "Hello, world!" ) }

Using Spark with Kotlin

Since this is just a normal Maven project, we can add Spark as we always do:

<dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-core</artifactId> <version>2.5.4</version> </dependency>

And the Spark Hello World example in Kotlin becomes:

import spark.Spark.* fun main ( args : Array < String >) { get ( "/hello" ) { req , res -> "Hello World" } }

Even smaller than before, and it looks pretty similar to Java8:

Java8: get("/path", (req, res) -> { ... });

Kotlin: get("/path") { req, res -> ...} .

The syntax (){} might look a little strange to Java programmers. Kotlin supports trailing closures and provides semicolon inference. Simplified, this means you don’t have to wrap closures in parentheses and end every statement with a semicolon.

Creating a Spark/Kotlin CRUD microservice

Kotlin data-classes

Kotlin has a really neat feature called Data classes. To create a data class you just have to write:

data class User ( val name : String , val email : String , val id : Int );

… and you’re done! If you declare all parameters as val you get an immutable class similar to the Lombok @Value annotation, only better. Regardless of if you use var or val (or a mix) for your data class, you get toString, hashCode/equals, copying and destructuring included:

val alice = User ( name = "Alice" , email = "alice@alice.kt" , id = 0 ) val aliceNewEmail = alice . copy ( email = "alice@bob.kt" ) // new object with only email changed val ( name , email ) = aliceNewEmail // choose the fields you want println ( "$name's new email is $email" ) // prints "Alice's new email is alice@bob.kt"

Initializing some data

Let’s initialize our fake user-database with four users:

val users = hashMapOf ( 0 to User ( name = "Alice" , email = "alice@alice.kt" , id = 0 ), 1 to User ( name = "Bob" , email = "bob@bob.kt" , id = 1 ), 2 to User ( name = "Carol" , email = "carol@carol.kt" , id = 2 ), 3 to User ( name = "Dave" , email = "dave@dave.kt" , id = 3 ) )

Kotlin has type inference and named paramters (we could have written our arguments in any order). It also has a nice standard library providing map-literal-like functions (so you won’t have to include guava in every project).

Creating a data access object

We need to be able to read out data somehow, so let’s set up some basic CRUD functionality, with one added function for finding user by email:

class UserDao { val users = hashMapOf ( 0 to User ( name = "Alice" , email = "alice@alice.kt" , id = 0 ), 1 to User ( name = "Bob" , email = "bob@bob.kt" , id = 1 ), 2 to User ( name = "Carol" , email = "carol@carol.kt" , id = 2 ), 3 to User ( name = "Dave" , email = "dave@dave.kt" , id = 3 ) ) var lastId : AtomicInteger = AtomicInteger ( users . size - 1 ) fun save ( name : String , email : String ) { val id = lastId . incrementAndGet () users . put ( id , User ( name = name , email = email , id = id )) } fun findById ( id : Int ): User ? { return users [ id ] } fun findByEmail ( email : String ): User ? { return users . values . find { it . email == email } } fun update ( id : Int , name : String , email : String ) { users . put ( id , User ( name = name , email = email , id = id )) } fun delete ( id : Int ) { users . remove ( id ) } }

The findByEmail function shows of some neat features. In addition to the trailing closures that we saw earlier, Kotlin also has a very practical find function and a special it keyword, which replaces user -> user style declarations with just it (docs). The function also demonstrates that == is the structural equality operator for Strings in Kotlin (equvivalent to .equals() in Java). If you want to check for referential equality in Kotlin you can use === . Another thing worth noticing is that the find-functions return User? , which means the function will return either a User or null . In Kotlin you have to specify the possibility of a null-return.

findByEmail() , Kotlin vs Java:

// Kotlin fun findByEmail ( email : String ): User ? { return users . values . find { it . email == email } } // Java public User findByEmail ( String email ) { return users . values (). stream () . filter ( user -> user . getEmail (). equals ( email )) . findFirst () . orElse ( null ); }

Creating the REST API

Kotlin and Spark play very well together (in fact, Kotlin seems to play well with all Java dependencies).

We can use trailing closures and implicit return values to create extremely clean route declarations:

val userDao = UserDao () path ( "/users" ) { get ( "" ) { req , res -> jacksonObjectMapper (). writeValueAsString ( userDao . users ) } get ( "/:id" ) { req , res -> userDao . findById ( req . params ( "id" ). toInt ()) } get ( "/email/:email" ) { req , res -> userDao . findByEmail ( req . params ( "email" )) } post ( "/create" ) { req , res -> userDao . save ( name = req . qp ( "name" ), email = req . qp ( "email" )) res . status ( 201 ) "ok" } patch ( "/update/:id" ) { req , res -> userDao . update ( id = req . params ( "id" ). toInt (), name = req . qp ( "name" ), email = req . qp ( "email" ) ) "ok" } delete ( "/delete/:id" ) { req , res -> userDao . delete ( req . params ( "id" ). toInt ()) "ok" } } // add "qp()" alias for "queryParams()" on Request object fun Request . qp ( key : String ): String = this . queryParams ( key )

In cases where findById() / findByEmail() returns null, Spark will return a 404 (null routes are by definition ‘not found’ in Spark). Unlike Java lambda expressions you don’t specify return values in Kotlin, the last line of a lambda expression is the return value (Kotlin lambda docs).

Our app references req.qp() a number of times, which is a method that doesn’t exist natively on a Spark Request. This works because we have defined an extension function on the Request object (last line).

Conclusion

I have only worked with Kotlin for a few hours while writing this tutorial, but I’m already a very big fan of the language. Everything just seems to make sense, and the interoperability with Java is great. IntelliJ will also automaticall convert Java code into Kotlin if you paste it into your project. Please clone the repo and give it a try!

The source code for this tutorial can be found on GitHub

Addendum - Other great Kotlin features

While playing around with Kotlin I found a lot of great features which I didn’t want to incorporate in the main tutorial, in order to keep it short and to the point. Keep reading if you want to learn more about Kotlin.

Multiline strings and string interpolation

get ( "/multiline-interpolation-example" ) { req , res -> val name = "Alice" val email = "alice@alice.kt" """ <h1>Hello $name</h1> <p>Your email is $email</p> """ }

Default arguments

fun serverError ( code : Int = 500 , message : String = "Internal server error" ): String { return """ <h1 style="font-family:monospace">$message (Error $code)</h1> <p style="font-family:monospace">We're sorry, but our server messed up. Please back and try again.</p> """ } get ( "/internal-server-error" ) { req , res -> serverError (); } get ( "/not-implemented" ) { req , res -> serverError ( code = 501 , message = "Not implemented" ); }

When expression

when is similar to Java’s switch , but it returns a value:

get ( "/when-example" ) { req , res -> when ( req . queryParams ( "lang" )) { "EN" -> "Hello!" "FR" -> "Salut!" "IT" -> "Ciao!" else -> "Sorry, I can't greet you in ${req.queryParams(" lang ")} yet" } }

Companion objects

This last one might be me dragging old Java habits into Kotlin. I’m not sure if this is a good idea at all when writing a Kotlin app, so please let me know in the comments:

// Inside fun main(): get ( "static-controller-example" , CompanionController . controllerOne ) get ( "static-controller-two-example" , CompanionController . controllerTwo ) // Inside CompanionController.kt class CompanionController { companion object { val controllerOne = { req : Request , res : Response -> "Hello controllerOne!" } val controllerTwo = { req : Request , res : Response -> "Hello controllerTwo!" } } }

This is a technique I use for structuring webapps in Spark when using Java. I might change my approach as I learn more about Kotlin, but I’m happy to see that it works.