Ktor bukan sekadar framework HTTP, melainkan kerangka pipeline berbasis coroutine. Setiap permintaan HTTP mengalir melalui fase-fase yang ditetapkan sebelum mencapai handler route. Tiga konsep inti yang harus dipahami sebelum menulis kode Ktor produksi adalah Application class, pipeline phases, dan plugin. Pada chapter ini kita akan membedah ketiganya lewat model ringkas yang dapat dijalankan tanpa dependensi eksternal.
Application Class #
Application adalah objek pusat di Ktor. Saat server Ktor dimulai, framework membuat satu instance Application yang menjadi wadah bagi seluruh plugin, route, dan konfigurasi. Kode produksi menuliskan modul sebagai extension function fun Application.module() { ... } — function ini dipanggil Ktor saat bootstrap dan menjadi titik pemasangan plugin serta pendaftaran route.
Tidak seperti Spring Boot yang memakai anotasi @SpringBootApplication untuk menandai entry point, Ktor memakai konvensi file application.conf (HOCON) yang menentukan modul mana yang dimuat. Pendekatan ini membuat konfigurasi dan kode terpisah jelas.
Anatomi Application #
Komponen utama Application:
| Komponen | Peran |
|---|---|
phases | Tahapan pipeline tempat plugin dipasang |
plugins | Daftar plugin terpasang (ContentNegotiation, Authentication, dll.) |
routes | Peta path ke handler |
install(plugin) | Memasang plugin ke Application |
routing { } | Mendaftarkan route via DSL |
Pipeline Phases #
Pipeline Ktor terbagi menjadi fase-fase berurutan. Setiap permintaan HTTP melewati fase tersebut dalam urutan tetap: setup, monitoring, plugin, content, fallback. Plugin yang dipasang ke fase tertentu akan dijalankan saat permintaan mencapai fase itu.
Fase penting di Ktor antara lain Setup, Monitoring (logging), Plugins (auth, negotiation), Content (serialisasi body), dan Fallback (penanganan error). Sebuah plugin seperti ContentNegotiation mendaftar ke fase Content untuk mengonversi JSON ke objek Kotlin sebelum handler membaca body.
Plugin #
Plugin adalah unit modul di Ktor. Sebuah plugin mengenkapsulasi satu tanggung jawab: ContentNegotiation menangani serialisasi, Authentication memverifikasi identitas, StatusPages menerjemahkan exception ke respons HTTP. Plugin dipasang dengan install(MyPlugin) { config } dan dapat menerima konfigurasi tambahan via trailing lambda.
Memahami pola plugin penting karena hampir semua fitur Ktor diimplementasikan sebagai plugin. Bahkan Routing sendiri adalah plugin yang dipasang otomatis saat kita memakai routing { }.
Demo Application, Phases, dan Plugin #
Karena Ktor nyata membutuhkan dependensi eksternal, kita akan memodelkan konsep tersebut sebagai class Kotlin biasa. Model ini merepresentasikan Application dengan daftar phases, plugins, dan routes — lalu menyimulasikan permintaan HTTP melalui pipeline.
// ktor_fundamentals.kt
// Mendemonstrasikan konsep Application, pipeline phases, dan plugin
// dalam Ktor. Pada kode produksi, kita memakai io.ktor.server.application.Application.
// Di sini kita memodelkannya sebagai class ringkas untuk demonstrasi konsep.
// Merepresentasikan satu fase dalam pipeline request
data class PipelinePhase(val nama: String)
// Plugin adalah unit yang dipasang ke Application dan menerima callback
interface Plugin {
val nama: String
fun install(app: Application)
}
// Application mendaftar fase, plugin, dan handler route
class Application {
val phases = mutableListOf<PipelinePhase>()
val plugins = mutableListOf<Plugin>()
val routes = mutableMapOf<String, () -> String>()
fun install(plugin: Plugin) {
plugin.install(this)
plugins.add(plugin)
}
fun routing(pipeline: RoutingBuilder.() -> Unit) {
val builder = RoutingBuilder()
builder.pipeline()
routes.putAll(builder.routes)
}
fun handle(path: String): String {
val handler = routes[path] ?: return "404 Not Found"
return handler()
}
}
class RoutingBuilder {
val routes = mutableMapOf<String, () -> String>()
fun get(path: String, handler: () -> String) {
routes[path] = handler
}
}
// Contoh plugin: ContentNegotiation mensimulasikan konversi JSON
object ContentNegotiation : Plugin {
override val nama = "ContentNegotiation"
override fun install(app: Application) {
app.phases.add(PipelinePhase("ContentNegotiation"))
}
}
// Contoh plugin: CallLogging mensimulasikan pencatatan request
object CallLogging : Plugin {
override val nama = "CallLogging"
override fun install(app: Application) {
app.phases.add(PipelinePhase("CallLogging"))
}
}
fun main() {
val app = Application()
app.install(CallLogging)
app.install(ContentNegotiation)
app.routing {
get("/") { "Halo dari Ktor" }
get("/users") { "[{id:1,nama:Budi}]" }
get("/health") { "OK" }
}
println("=== Plugin terpasang ===")
app.plugins.forEach { println(" ${it.nama}") }
println("\n=== Fase pipeline ===")
app.phases.forEach { println(" ${it.nama}") }
println("\n=== Request simulation ===")
listOf("/", "/users", "/health", "/missing").forEach { path ->
println(" GET $path -> ${app.handle(path)}")
}
}Output yang Dihasilkan:
=== Plugin terpasang ===
CallLogging
ContentNegotiation
=== Fase pipeline ===
CallLogging
ContentNegotiation
=== Request simulation ===
GET / -> Halo dari Ktor
GET /users -> [{id:1,nama:Budi}]
GET /health -> OK
GET /missing -> 404 Not FoundMari kita bedah baris-baris penting kode di atas:
interface Plugin { val nama: String; fun install(app: Application) }: kontrak plugin — setiap plugin punya nama dan callbackinstallyang menerima Application. Saatinstalldipanggil, plugin boleh menambah fase ke pipeline atau mendaftarkan hook.fun install(plugin: Plugin): metode Application memanggilplugin.install(this)agar plugin dapat mengakses instance Application, lalu menyimpan plugin di listplugins.fun routing(pipeline: RoutingBuilder.() -> Unit): menerima lambda dengan receiverRoutingBuilder. Lambda ini dijalankan pada builder sementara untuk mengisi peta route. Pola ini meniru DSLrouting { get("/x") { ... } }di Ktor nyata.object ContentNegotiation : Plugin: singleton object yang merepresentasikan plugin. Pola ini lazim dipakai Ktor untuk plugin tanpa konfigurasi state.fun handle(path: String): String: simulasi dispatch — mencari route berdasarkan path dan mengembalikan string body. Bila tidak ditemukan, kembalikan “404 Not Found”.
Referensi Lanjutan #
- Ktor welcome — halaman pengenalan Ktor yang menjelaskan arsitektur coroutine-first dan struktur aplikasi
- Create and configure Ktor server
— panduan resmi membuat
EmbeddedServerdan mengonfigurasi modul Ktor
Selanjutnya #
Setelah memahami Application, phases, dan plugin, langkah berikutnya adalah menyiapkan proyek Ktor nyata. Chapter Ktor Project Structure akan membedah struktur direktori, file application.conf HOCON, dan layout source code yang dipakai Ktor di produksi.