Pengembangan backend dengan Kotlin didominasi dua framework: Ktor dari JetBrains dan Spring Boot dari VMware. Ktor coroutine-native dan ringan; Spring Boot matang dengan ekosistem luas. Pada chapter ini kita memetakan kedua framework, mendemokan pola MVC sederhana tanpa dependency eksternal, dan membandingkan kapan memilih salah satunya.
Pola MVC Backend #
Sebagian besar backend Kotlin mengikuti pola Model-View-Controller yang disederhanakan menjadi Routing-Service-Model. Tiga lapisan tersebut terlihat seperti ini:
| Lapisan | Tugas | Contoh Ktor | Contoh Spring Boot |
|---|---|---|---|
| Routing | Petakan HTTP method + path ke handler | get("/users") { } | @GetMapping("/users") |
| Service | Logika bisnis + persistence | class UserService | @Service class UserService |
| Model | Data class untuk request/response | data class UserDto | data class UserDto |
Demo Router dan Service #
Cuplikan berikut memodelkan router Ktor/Spring sebagai class Kotlin murni. Routing didefinisikan dengan get() dan post(), dispatch mencocokkan method dan path, lalu handler memanggil service layer:
// panduan_backend.kt
// Tour singkat Panduan Backend Kotlin:
// - Ktor: https://ktor.io/docs/
// - Spring Boot: https://spring.io
//
// File ini mendemokan konsep server HTTP sederhana dan pola MVC
// tanpa dependency eksternal — dijalankan di JVM biasa.
import java.util.concurrent.ConcurrentHashMap
// 1. Routing — simulasi router Ktor/Spring
data class Route(val method: String, val path: String, val handler: (Map<String, String>) -> String)
class Router {
private val routes = mutableListOf<Route>()
fun get(path: String, handler: (Map<String, String>) -> String) {
routes.add(Route("GET", path, handler))
}
fun post(path: String, handler: (Map<String, String>) -> String) {
routes.add(Route("POST", path, handler))
}
fun dispatch(method: String, path: String, params: Map<String, String> = emptyMap()): String {
val route = routes.find { it.method == method && it.path == path }
?: return "404 Not Found: $method $path"
return route.handler(params)
}
}
// 2. Service layer — bisnis logika
class PenggunaService {
private val storage = ConcurrentHashMap<Int, String>()
fun simpan(id: Int, nama: String) { storage[id] = nama }
fun ambil(id: Int): String? = storage[id]
fun hapus(id: Int): Boolean = storage.remove(id) != null
fun daftar(): List<Pair<Int, String>> = storage.entries.map { it.key to it.value }.sortedBy { it.first }
}
// 3. Request / Response model
data class PenggunaRequest(val id: Int, val nama: String)
data class PenggunaResponse(val id: Int, val nama: String, val sukses: Boolean)
fun main() {
println("=== Panduan Backend Kotlin ===")
println("Ktor: https://ktor.io/docs/ | Spring Boot: https://spring.io")
println()
val service = PenggunaService()
val router = Router()
// Definisi route
router.get("/users") { _ ->
val users = service.daftar()
if (users.isEmpty()) "[]"
else users.joinToString(prefix = "[", postfix = "]") { "{\"id\":${it.first},\"nama\":\"${it.second}\"}" }
}
router.post("/users") { params ->
val id = params["id"]?.toIntOrNull() ?: -1
val nama = params["nama"] ?: ""
if (id < 0 || nama.isEmpty()) {
"400 Bad Request"
} else {
service.simpan(id, nama)
"201 Created: {\"id\":$id,\"nama\":\"$nama\"}"
}
}
router.get("/users/{id}") { params ->
val id = params["id"]?.toIntOrNull() ?: -1
service.ambil(id)?.let { "200 OK: {\"id\":$id,\"nama\":\"$it\"}" }
?: "404 Not Found"
}
println("--- 1. POST /users ---")
println(router.dispatch("POST", "/users", mapOf("id" to "1", "nama" to "Budi")))
println(router.dispatch("POST", "/users", mapOf("id" to "2", "nama" to "Siti")))
println(router.dispatch("POST", "/users", mapOf("id" to "3", "nama" to "Dewi")))
println()
println("--- 2. GET /users ---")
println(router.dispatch("GET", "/users"))
println()
println("--- 3. GET /users/{id} ---")
println(router.dispatch("GET", "/users/{id}", mapOf("id" to "2")))
println(router.dispatch("GET", "/users/{id}", mapOf("id" to "999")))
println()
println("--- 4. GET /unknown ---")
println(router.dispatch("GET", "/unknown"))
println()
println("--- 5. Framework backend populer ---")
val frameworks = listOf(
Triple("Ktor", "JetBrains", "Lightweight, coroutine-native, DSL routing"),
Triple("Spring Boot", "VMware/Pivotal", "Mature, dependency injection, annotation-based"),
Triple("http4k", "Community", "Functional HTTP, serverless-ready"),
Triple("Javalin", "Community", "Simple, Express.js-like untuk Kotlin/Java"),
Triple("Quarkus", "Red Hat", "Cloud-native, low memory, hot reload"),
Triple("Micronaut", "OCI", "Compile-time DI, fast startup, low overhead")
)
frameworks.forEach { (nama, pembuat, desk) ->
println(" ${nama.padEnd(14)} ($pembuat): $desk")
}
println()
println("--- 6. Perbandingan Ktor vs Spring Boot ---")
val perbandingan = listOf(
"Startup: Ktor <1s, Spring Boot 2-5s",
"Memory: Ktor ~50MB, Spring Boot ~200MB",
"Learning: Ktor mudah, Spring Boot kompleks (banyak konsep)",
"Ecosystem: Ktor kecil, Spring Boot masif (Spring Security, Data, Batch)",
"Coroutine: Ktor native, Spring Boot 5+ mendukung",
"Skala: Ktor microservice, Spring Boot enterprise monolith"
)
perbandingan.forEach { println(" $it") }
println()
println("--- 7. Panduan belajar backend Kotlin ---")
val panduan = listOf(
"1. Mulai dengan Ktor 'Hello World' (2 menit jalan)",
"2. Pelajari routing DSL: get(), post(), dll",
"3. Tambahkan persistence (Exposed, JOOQ, atau Hibernate)",
"4. Tambahkan JSON serialization (kotlinx.serialization)",
"5. Tambahkan autentikasi (JWT, OAuth2)",
"6. Deploy ke container (Docker, Kubernetes)",
"7. Untuk enterprise: migrasi ke Spring Boot bila butuh ekosistem"
)
panduan.forEach { println(" $it") }
}Output yang Dihasilkan:
=== Panduan Backend Kotlin ===
Ktor: https://ktor.io/docs/ | Spring Boot: https://spring.io
--- 1. POST /users ---
201 Created: {"id":1,"nama":"Budi"}
201 Created: {"id":2,"nama":"Siti"}
201 Created: {"id":3,"nama":"Dewi"}
--- 2. GET /users ---
[{"id":1,"nama":"Budi"}, {"id":2,"nama":"Siti"}, {"id":3,"nama":"Dewi"}]
--- 3. GET /users/{id} ---
200 OK: {"id":2,"nama":"Siti"}
404 Not Found
--- 4. GET /unknown ---
404 Not Found: GET /unknown
--- 5. Framework backend populer ---
Ktor (JetBrains): Lightweight, coroutine-native, DSL routing
Spring Boot (VMware/Pivotal): Mature, dependency injection, annotation-based
http4k (Community): Functional HTTP, serverless-ready
Javalin (Community): Simple, Express.js-like untuk Kotlin/Java
Quarkus (Red Hat): Cloud-native, low memory, hot reload
Micronaut (OCI): Compile-time DI, fast startup, low overhead
--- 6. Perbandingan Ktor vs Spring Boot ---
Startup: Ktor <1s, Spring Boot 2-5s
Memory: Ktor ~50MB, Spring Boot ~200MB
Learning: Ktor mudah, Spring Boot kompleks (banyak konsep)
Ecosystem: Ktor kecil, Spring Boot masif (Spring Security, Data, Batch)
Coroutine: Ktor native, Spring Boot 5+ mendukung
Skala: Ktor microservice, Spring Boot enterprise monolith
--- 7. Panduan belajar backend Kotlin ---
1. Mulai dengan Ktor 'Hello World' (2 menit jalan)
2. Pelajari routing DSL: get(), post(), dll
3. Tambahkan persistence (Exposed, JOOQ, atau Hibernate)
4. Tambahkan JSON serialization (kotlinx.serialization)
5. Tambahkan autentikasi (JWT, OAuth2)
6. Deploy ke container (Docker, Kubernetes)
7. Untuk enterprise: migrasi ke Spring Boot bila butuh ekosistemPerhatikan alur lengkap: tiga POST membuat pengguna baru, GET /users mengembalikan daftar lengkap sebagai JSON, GET /users/{id} mencari satu pengguna, dan GET path yang tidak terdaftar mengembalikan 404.
Ktor vs Spring Boot #
Ktor cocok untuk microservice dan project baru yang ingin startup cepat dan jejak memori kecil. DSL routing Ktor terlihat seperti kode Kotlin biasa, sehingga minim boilerplate. Spring Boot cocok untuk aplikasi enterprise yang butuh ekosistem matang: Spring Security, Spring Data JPA, Spring Batch, dan integrasi messaging. Spring Boot lebih berat (startup 2-5 detik, memori ~200 MB) tetapi kompensasinya adalah banyaknya modul siap pakai.
Referensi Lanjutan #
- Kotlin server-side overview — ringkasan Kotlin untuk backend mencakup framework Ktor dan Spring serta pustaka JVM populer
Selanjutnya #
Backend yang baik selalu diiringi pengujian yang baik. Chapter berikutnya membahas panduan testing — kotlin-test, JUnit 5, MockK, Testcontainers, dan Turbine untuk Flow.