Kotlin is the hot language right now but there is a misconception that, because it runs on the JVM, it’s just for the Java ecosystem. Some web developers (especially those with a JavaScript background) are keeping away from it because they think that it cannot be used for their web projects. This article is aimed at showing you how to build backend RESTful APIs that your client apps can consume.

Assuming that you already know the basics of Kotlin programming language, here are the tools we will use in this article:

Java 8: Kotlin is a programming language that compiles to Java Byte Code, and runs on the Java Virtual Machine. We are going to need the latest version of Java to kick things off

Spring Boot: A subproject of Spring Framework that allows for fast prototyping of HTTP web applications

Gradle: Our build tool and package manager

VSCode: Yes, VSCode. Just to show you that you don’t need IntelliJ IDE to build web apps.

Postman: For testing API endpoints.

Project Setup

Let’s get started by specifying dependencies and build scripts in our build.gradle file. Create an empty folder and add this file to the root of the project:

buildscript { ext.kotlin_version = '1.1.2-4' repositories { mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE" classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version" } } apply plugin: 'application' apply plugin: 'kotlin' // "bootRun" command for starting application apply plugin: 'org.springframework.boot' // Bindings between kotlin and spring apply plugin: 'kotlin-spring' repositories { mavenCentral() } dependencies { // Kotlin Dependencies compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version" // Spring Dependencies compile("org.springframework.boot:spring-boot-starter-web") { exclude module: "spring-boot-starter-tomcat" } compile "org.springframework.boot:spring-boot-starter-jetty" compile "org.springframework.boot:spring-boot-starter-actuator" // Jackson Dependencies compile "com.fasterxml.jackson.core:jackson-annotations" compile "com.fasterxml.jackson.core:jackson-core" compile "com.fasterxml.jackson.core:jackson-databind" runtime "com.fasterxml.jackson.datatype:jackson-datatype-jdk8" runtime "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" runtime "com.fasterxml.jackson.module:jackson-module-kotlin" } task wrapper(type: Wrapper) { gradleVersion = "3.5" }

You can see this file is like npm in Node or Composer in PHP. It manages all your packages with the added build scripts as well.

In summary, the dependencies include Kotlin, Spring Boot, Kotlin Spring, and Jackson. Jackson helps with serializing JSON which is what our app will be receiving as input and responding with as output via HTTP.

The last thing to complete the project setup is to create an entry point for our app. Create ./src/main/kotlin/api/Application.kt file with the following content:

// ./src/main/kotlin/api/Application.kt package api import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.EnableAutoConfiguration import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration // Entry point @EnableAutoConfiguration @Configuration class Application fun main(args: Array<String>) { SpringApplication.run(Application::class.java, *args) }

Kotlin doesn’t require you to create a full class just to register an entry main method. With the top-level functions feature, you can just write a class-independent function. The Application class which we will flesh out soon allows you to register your building blocks (eg. controllers).

Your First Controller

Spring Boot uses controllers to define route handlers. When you have a path like GET /comments , a method in a Spring controller is responsible for handling whatever happens when this route is hit.

Let’s add in index route as an example:

// ./src/main/kotlin/api/AppController.kt package api import java.time.Instant import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController class AppController { @RequestMapping("/") fun index() = "This is home!" }

Notice how what we got is just a basic class with a simple inline method that returns a string. Just Kotlin stuff. The obvious difference is the annotations made using the Spring RestController annotation on the AppController class and RequestMapping annotation on the method.

RestController annotation tells Spring that this class has members which will handle RESTful resources and should be treated as one, while RequestMapping defines a method as a HTTP handler. It also takes a string argument specifying the route path.

We need to let the entry class know about our new controller, hence:

class Application { @Bean fun controller() = AppController() }

You can test what we have so far by running the boot command:

gradle bootRun

Now head to http://localhost:8080 and see for yourself:

JSON Payload

Most times what we want is not a primitive value, but an object payload in the form of JSON. REST uses JSON for both making requests and sending responses. Let’s see how we can go about doing that.

First, create a data class to represent an object:

// ./src/main/kotlin/api/Models/Comment.kt package api import java.time.Instant data class Comment( val author: String, val content: String, val created: Instant )

The data class is named Comment with an author, content and created property. The author and content properties are of type String while created is of type Instant (which is the time at creation).

Next, add another route in the AppController to actually handle comment requests on the /comment path:

// ./src/main/kotlin/api/AppController.kt package api import java.time.Instant import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController class AppController { @RequestMapping("/") fun index() = "This is home!" // New route to hand comment request @RequestMapping("/comment") fun getComment() : Comment { val comment = Comment( author = "codebeast", content = "I'm so loving Kotlin", created = Instant.now() ) return comment } }

We just added a getComment method which returns an object when hit.

To serialize the JSON sent, you need to configure Jackson. Create an application.yml file in src/resources with the following content:

spring: jackson: serialization: indent_output: true write_dates_as_timestamps: false write_durations_as_timestamps: false

Now run the application again and visit /comment to see the output:

Making A Post Request

With Spring, you can also receive data from a client. You need to parse this input using the Jackson’s JsonCreator annotation:

// ./src/main/kotlin/api/Models/Comment.kt package api import java.time.Instant import com.fasterxml.jackson.annotation.JsonCreator data class Comment( val author: String, val content: String, val created: Instant ) // New data class for incoming comments data class NewComment @JsonCreator constructor( val author: String, val content: String )

We added another class and decorated its constructor with @JsonCreator which tells Jackson to parse any input coming through this class as JSON.

Next, add a controller method to handle an incoming POST /content request:

package api import java.time.Instant import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMethod @RestController class AppController { // ... @RequestMapping(value = "/comment", method = arrayOf(RequestMethod.POST)) fun createUser(@RequestBody newComment: NewComment): Comment { val comment = Comment( author = newComment.author, content = newComment.content, created = Instant.now() ) return comment } }

All this does is send us back what we sent in while adding a created timestamp.

Here is what the request looks like from Postman:

Query Strings and Parameters

You can also pass in query strings to requests:

package api import java.time.Instant import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.RequestParam @RestController class AppController { // ... @RequestMapping("/search") fun search(@RequestParam(name = "name") value: String) : String = value }

We use the RequestParam annotation to receive a value and then return the value. Simple enough to show how query strings work. Here is an image of the request:

Finally, you can have route parameters on routes using PathVariable annotation:

package api import java.time.Instant import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMethod import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.PathVariable @RestController class AppController { //... @RequestMapping("/search") fun search(@RequestParam(name = "name") value: String) : String = value @RequestMapping("/comment/{value}") fun findComment(@PathVariable("value") value: String) : String = value }

Please find the GitHub repo here.

Conclusion

There is more from Spring and Kotlin — more HTTP methods to handle, data persistence, deploying, etc. You can learn more about this from the Spring Boot website and if you need to brush up your Kotlin skills, Kotlin Koans is a good place to spend some of your time. Let me know in the comments if you run into issues getting started.