CodeBlanks Logo Icon CodeBlanks

Birleştirme

Tüm katmanları birleştirerek çalışan bir mini servis yazarsın.

Birleştirme: API + DB + coroutines

Son ders tüm parçaları birleştirir. UserRepo suspend metotlarla veri yönetir, UsersTable veriyi saklar, Api suspend route ile yol yönlendirir, main runBlocking ile çağrılır.

Bu yapı, Ktor API + Exposed DB + coroutines desenini küçük çapta bir araya getirir. Artık repoya bir kullanıcı ekleyip API üzerinden suspend erişebilirsin. Bu kalıp, üretim Kotlin backend'lerinin temelidir.

Proje yapısı

Projenin son hali dört katman içerir. User veri sınıfı en altta; UsersTable onu saklar; UserRepo iş mantığını sarar; Api dışarıdan gelen yolları repoya yönlendirir.

Tüm suspend metotlar runBlocking içinde çağrılır. Bu ayrım, her katmanı bağımsız test etmeyi ve ileride gerçek DB'ye geçişi kolaylaştırır. Beşinci ders, bu akışın çalıştığını bir main çağrısıyla gösterir.

Uygulama Final: tüm parçaları birleştir

Mevcut tüm tanımları koru. main içinde repo.save(User(1, "Ayşe")) ile kullanıcı ekle, val api = Api(repo) oluştur ve println(api.route("/users/1")) yazdır. main runBlocking ile acilmalı.

Başlangıç kodu

Main.kt
import kotlinx.coroutines.runBlocking

data class User(val id: Int, val name: String)

object UsersTable {
    val rows = mutableListOf<User>()
    fun insert(u: User) { rows.add(u) }
    fun select(id: Int): User? = rows.find { it.id == id }
}

class UserRepo {
    suspend fun save(u: User) { UsersTable.insert(u) }
    suspend fun find(id: Int): User? = UsersTable.select(id)
}

class Api(val repo: UserRepo) {
    suspend fun route(path: String): String {
        return when {
            path.startsWith("/users/") -> {
                val id = path.removePrefix("/users/").toInt()
                repo.find(id)?.name ?: "not found"
            }
            else -> "404"
        }
    }
}

// main = runBlocking: User ekle, Api oluştur, /users/1 yazdır

Örnek çözüm

Main.kt
import kotlinx.coroutines.runBlocking

data class User(val id: Int, val name: String)

object UsersTable {
    val rows = mutableListOf<User>()
    fun insert(u: User) { rows.add(u) }
    fun select(id: Int): User? = rows.find { it.id == id }
}

class UserRepo {
    suspend fun save(u: User) { UsersTable.insert(u) }
    suspend fun find(id: Int): User? = UsersTable.select(id)
}

class Api(val repo: UserRepo) {
    suspend fun route(path: String): String {
        return when {
            path.startsWith("/users/") -> {
                val id = path.removePrefix("/users/").toInt()
                repo.find(id)?.name ?: "not found"
            }
            else -> "404"
        }
    }
}

fun main() = runBlocking {
    val repo = UserRepo()
    repo.save(User(1, "Ayşe"))
    val api = Api(repo)
    println(api.route("/users/1"))
}

Beklenen çıktı

Ayşe

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Bu projede main neden runBlocking ile açılır?

  • Çünkü daha hızlıdır
  • Çünkü suspend fonksiyonlar çağrılır Doğru cevap
  • Çünkü test zorunludur
  • Çünkü derleme hatası verir

Açıklama: runBlocking suspend fonksiyonlar için scope açar.

2 Proje parçalarını eşle

Kavram Anlamı
UserRepo İş mantığı
UsersTable Veri katmanı
Apı Yönlendirme
runBlocking Coroutine scope

3 route çağrısını tamamla

Soru
val api = Api(repo)
println(api.____("/users/1"))
Cevap
val api = Api(repo)
println(api.route("/users/1"))

Açıklama: api.route bir yolu yorumlar.

İleri seviye bölümündeki tüm dersler