This blog post was written under the Pusher Guest Writer program.

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.

About Chris Nwamba

Chris is a JavaScript preacher. He also strives to make something out of other languages. Tech Writer. Dev Evangelist. Speaker.