Program yang dijalankan sejauh ini berhenti setelah tugasnya selesai, sedangkan program di sisi server justru berjalan terus sambil menunggu permintaan. Kotlin melayani pola itu melalui Ktor, yaitu framework sisi server dari JetBrains yang dibangun di atas coroutine. Topik ini memperkenalkan bentuk server Ktor yang paling sederhana, menjelaskan peran routing di dalamnya, lalu menguji konsep routing itu dengan simulasi kecil yang dijalankan nyata di JVM.
Peran framework di sisi server#
Server pada dasarnya berupa proses yang mendengarkan port jaringan, membaca permintaan HTTP yang masuk, lalu mengirim respons. Menyusun semuanya dari soket mentah memungkinkan dilakukan, tetapi pekerjaan berulang seperti mengurai header, memetakan URL, dan membentuk respons lebih baik diserahkan pada framework. Ktor mengisi peran itu dengan API yang terasa Kotlin, misalnya pemetaan rute yang ditulis sebagai blok kode bertingkat.
Satu kata yang muncul terus di dunia server adalah endpoint, yaitu pasangan metode HTTP dan jalur yang dapat dipanggil oleh klien. Endpoint GET /salam dan POST /hitung adalah dua endpoint berbeda meskipun jalurnya bertetangga. Framework bertugas mengarahkan setiap permintaan ke penangan yang tepat, dan mekanisme pengarahnya disebut routing.
Ktor memang dikembangkan sebagai proyek multiplatform, dan bagian server yang dibahas di sini lazim dijalankan di JVM, tempat engine seperti Netty menangani jaringan. Pilihan itu membuat server Kotlin dapat berbagi logika dengan aplikasi Android atau program desktop pada basis kode yang sama, sebagaimana konsep kode bersama pada KMP. Bagian yang khas untuk server, yaitu pemetaan rute dan pembentukan respons, tetap ditulis satu kali untuk semua jenis klien yang dilayaninya.
Server Ktor paling sederhana#
Kode server Ktor yang paling kecil terdiri atas tiga bagian, yaitu pemilihan engine jaringan, deklarasi port, dan daftar rute. Netty dipilih sebagai engine pada contoh berikut, sementara engine lain dapat diganti tanpa mengubah daftar rutinya.
// tidak-dijalankan
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
fun main() {
embeddedServer(Netty, port = 8080) {
routing {
get("/salam") {
call.respondText("Halo dari Ktor")
}
}
}.start(wait = true)
}Blok routing mendaftarkan penangan untuk tiap endpoint, dan di dalamnya call.respondText mengirim isi respons. Pemanggilan start(wait = true) membuat proses menunggu permintaan terus-menerus, sehingga program tidak selesai setelah baris terakhirnya, melainkan bertahan sebagai server. Dependensinya berupa artefak ktor-server-netty yang dinyatakan pada build proyek, dan bentuk berkasnya diperlihatkan pada bagian penutup topik ini.
Alur permintaannya dapat dibayangkan berurutan. Netty menerima koneksi, Ktor membaca permintaannya, routing mencocokkan metode dan jalurnya dengan rute terdaftar, lalu penangan yang cocok membentuk respons. Apabila tidak ada rute yang cocok, framework mengirim respons 404 tanpa perlu ditulis manual, sebagaimana perilaku 404 pada simulasi di bawah.
Routing dalam simulasi JVM#
Sebelum menyentuh server sungguhan, inti routing dapat diuji di JVM biasa tanpa dependensi apa pun. Router paling sederhana berupa pemetaan dari jalur ke tanggapan, ditambah sedikit aturan untuk metode HTTP yang tidak sesuai. Program berikut meniru perilaku itu dengan Map dan satu fungsi pengarah.
val rute: Map<String, String> = mapOf(
"/" to "Selamat datang di layanan penghitung kata",
"/bantuan" to "Kirim teks ke /hitung untuk menghitung jumlah katanya",
"/hitung" to "Berisi hasil penghitungan kata dari teks yang dikirim"
)
fun route(method: String, path: String): String {
val tanggapan = rute[path] ?: return "404 Not Found: $path"
if (path == "/hitung" && method != "POST") return "405 Method Not Allowed"
return "200 OK: $tanggapan"
}
fun main() {
println(route("GET", "/"))
println(route("GET", "/bantuan"))
println(route("GET", "/hitung"))
println(route("POST", "/hitung"))
println(route("GET", "/status"))
}# compiler Kotlin dan pustaka standar yang dipakai jalur ini
export PATH=/home/kal/my-project/tools/kotlinc/bin:/home/kal/my-project/tools/jdk-merged/bin:$PATH
export STDLIB=/home/kal/my-project/tools/kotlinc/lib/kotlin-stdlib.jar
# kompilasi SimulasiRute.kt, lalu jalankan hasilnya di JVM
kotlinc SimulasiRute.kt -d out.jar && java -cp "out.jar:$STDLIB" SimulasiRuteKt200 OK: Selamat datang di layanan penghitung kata
200 OK: Kirim teks ke /hitung untuk menghitung jumlah katanya
405 Method Not Allowed
200 OK: Berisi hasil penghitungan kata dari teks yang dikirim
404 Not Found: /statusTiga kasus pada keluaran memperlihatkan keputusan yang sama dengan yang diambil framework. Jalur yang terdaftar menghasilkan tanggapannya, jalur /status yang tidak terdaftar menghasilkan 404 Not Found, sedangkan GET /hitung menghasilkan 405 Method Not Allowed karena hanya menerima POST. Ktor mengambil keputusan yang sama, tetapi penangannya berupa blok kode yang dapat memanggil fungsi suspend, bukan sekadar String dari Map.
Bentuk Map dipilih agar simulasinya pendek, padahal router sungguhan menyimpan penangan berupa fungsi, bukan String siap pakai. Pendaftarannya pun dilakukan bertahap, yaitu setiap blok seperti get("/salam") { ... } menambahkan satu entri baru pada saat server dibangun. Apabila simulasi ini dikembangkan satu langkah lagi, yaitu mengganti nilai String dengan lambda, bentuknya mulai menyerupai routing Ktor yang sesungguhnya.
Menuju server sungguhan#
Proyek Ktor dikelola Gradle sebagaimana proyek Kotlin pada umumnya. Plugin Ktor menyiapkan task untuk menjalankan aplikasi, sedangkan dependensi ktor-server-netty membawa engine beserta seluruh pustaka turunannya. Berkas build berikut cukup untuk contoh minimal di atas, dengan kode servernya disimpan di Main.kt.
// tidak-dijalankan
plugins {
kotlin("jvm") version "2.2.21"
id("io.ktor.plugin") version "3.2.0"
}
application {
mainClass.set("MainKt")
}
dependencies {
implementation("io.ktor:ktor-server-netty:3.2.0")
}Versi 3.2.0 pada berkas itu hanyalah contoh yang sah, dan angkanya boleh diganti mengikuti rilis terbaru yang tercantum di situs Ktor. Setelah dependensi terunduh, task run dari Gradle menjalankan server, lalu endpoint GET /salam dapat dicoba dari browser ataupun perintah curl pada alamat localhost:8080. Dari titik ini, penambahan rute baru hanya berupa penambahan blok di dalam routing.
Struktur proyeknya pun sederhana. Kode server diletakkan di berkas sumber biasa, sedangkan kerumitan pengemasan diserahkan pada plugin, termasuk task untuk membuat berkas JAR yang siap dijalankan di server produksi. Kebiasaan pada proyek sungguhan adalah memindahkan daftar rute ke fungsi extension bernama modul, misalnya Application.module(), sehingga berkas utama tetap ramping dan rute dapat dikelompokkan per fitur.
# tidak-dijalankan
# menjalankan server Ktor dari proyek Gradle
./gradlew runKesalahan umum#
Kesalahan pertama yang muncul ketika server pertama dijalankan adalah port yang sudah dipakai proses lain. Server menolak naik dengan pesan dari keluarga BindException yang menyebut alamat dan portnya, sehingga terlihat seperti kode rute yang salah, padahal tidak. Angka port pada contoh, yaitu 8080, termasuk yang paling sering bentrok karena dipakai banyak alat pengembangan. Perbaikannya ada dua, yaitu menghentikan proses lama yang masih memegang port itu, atau mengganti angka port pada deklarasi server.
Kesalahan kedua adalah menaruh pekerjaan berat di bawah pemanggilan start(wait = true) dengan harapan berjalan bersamaan. Pemanggilan itu memblokir thread sampai server berhenti, sehingga baris di bawahnya baru dieksekusi setelah server dimatikan. Pekerjaan yang perlu berjalan selama server hidup diluncurkan dari dalam, misalnya melalui coroutine pada scope aplikasi, dan bukan sebagai kode berurutan di bawahnya.
Kesalahan ketiga terjadi saat endpoint POST diuji melalui alamat browser. Browser selalu mengirim GET, sehingga tanggapan 405 bukan tanda rutenya salah, melainkan bukti aturan metodenya bekerja. Untuk mengirim POST, gunakan perintah curl dengan opsi -X POST, dan tanggapan yang muncul saat itu barulah tanggapan penangan yang sesungguhnya.
Ringkasan#
- Framework sisi server mengurus pekerjaan HTTP yang berulang, dan Ktor melakukannya dengan API Kotlin yang dibangun di atas coroutine.
- Server Ktor minimal terdiri atas engine, port, daftar rute, dan pemanggilan
start(wait = true)agar proses bertahan menunggu permintaan. - Routing memetakan pasangan metode HTTP dan jalur ke penangannya, dengan 404 untuk jalur yang tidak terdaftar dan 405 untuk metode yang tidak sesuai.
- Proyek Ktor dikelola Gradle melalui plugin
io.ktor.plugindan dependensiktor-server-netty, lalu dijalankan dengan taskrun.
Referensi#
- Routing — Ktor — Dokumentasi resmi routing Ktor, termasuk pendaftaran penangan per metode dan jalur.
- Welcome to Ktor — Ktor — Halaman pembuka dokumentasi Ktor yang memetakan bagian-bagian pentingnya.