Introduction
Kotlin is a modern statically typed programming language that runs on the Java Virtual Machine (JVM) and is fully compatible with the Java ecosystem. Thanks to its conciseness, safety, and powerful functional capabilities, Kotlin has become one of the most popular languages for server-side application development, especially after Google chose it as the primary language for Android.
In this article, we will create a full-fledged REST API in Kotlin using the lightweight framework Ktor and the database library Exposed. We will implement a simple task management service (To-Do List) with support for all CRUD operations (create, read, update, delete). The entire process will take you no more than 30 minutes if you have already installed IntelliJ IDEA and JDK.
1. Project Setup
First, let's create a new Kotlin project with Gradle support. Open IntelliJ IDEA and select File → New → Project. In the project creation wizard, choose Kotlin → JVM.
Step 1.1: build.gradle.kts Structure
Add the following dependencies to the build.gradle.kts file:
plugins { kotlin("jvm") version "1.9.0" id("io.ktor.plugin") version "2.3.0" kotlin("plugin.serialization") version "1.9.0"}
dependencies { implementation("io.ktor:ktor-server-core:2.3.0") implementation("io.ktor:ktor-server-netty:2.3.0") implementation("io.ktor:ktor-server-content-negotiation:2.3.0") implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.0") implementation("org.jetbrains.exposed:exposed-core:0.41.1") implementation("org.jetbrains.exposed:exposed-dao:0.41.1") implementation("org.jetbrains.exposed:exposed-jdbc:0.41.1") implementation("com.h2database:h2:2.1.214") implementation("ch.qos.logback:logback-classic:1.4.7")}These dependencies include: the Ktor framework itself, JSON serialization support, the Exposed library for working with the database, and the embedded H2 database for testing.
Step 1.2: Entry Point
Create a file Application.kt in the package com.example:
import io.ktor.server.engine.*import io.ktor.server.netty.*import com.example.plugins.*
fun main() { embeddedServer(Netty, port = 8080) { configureSerialization() configureRouting() }.start(wait = true)}2. Configuring Serialization and Routing
Step 2.1: Application Plugins
Create a plugins directory and a file Serialization.kt:
package com.example.plugins
import io.ktor.serialization.kotlinx.json.*import io.ktor.server.application.*import io.ktor.server.plugins.contentnegotiation.*
fun Application.configureSerialization() { install(ContentNegotiation) { json() }}Step 2.2: Defining the Data Model
Create a file Models.kt:
package com.example.models
import kotlinx.serialization.Serializable
@Serializabledata class Task( val id: Int = 0, val title: String, val description: String = "", val completed: Boolean = false)3. Working with the Database
Step 3.1: Configuring the Connection
Create a file DatabaseFactory.kt:
package com.example.database
import org.jetbrains.exposed.sql.Databaseimport org.jetbrains.exposed.sql.SchemaUtilsimport org.jetbrains.exposed.sql.transactions.transaction
object DatabaseFactory { fun init() { Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver") transaction { SchemaUtils.create(TasksTable) } }}Step 3.2: Defining the Table
In the same package, create TasksTable.kt:
package co