kotlinintermediate

Type-Safe Builder for Configuration

Build configuration DSLs: server config, dependency injection setup, and nested builder patterns.

kotlin
// Server configuration DSL
@DslMarker
annotation class ConfigDsl

@ConfigDsl
class ServerConfig {
    var host: String = "localhost"
    var port: Int = 8080
    var workers: Int = Runtime.getRuntime().availableProcessors()

    private var _ssl: SslConfig? = null
    private var _database: DatabaseConfig? = null
    private var _routes = mutableListOf<RouteConfig>()
    private var _middleware = mutableListOf<String>()

    val ssl get() = _ssl
    val database get() = _database
    val routes get() = _routes.toList()
    val middleware get() = _middleware.toList()

    fun ssl(block: SslConfig.() -> Unit) {
        _ssl = SslConfig().apply(block)
    }

    fun database(block: DatabaseConfig.() -> Unit) {
        _database = DatabaseConfig().apply(block)
    }

    fun routing(block: RoutingConfig.() -> Unit) {
        RoutingConfig(_routes).apply(block)
    }

    fun middleware(vararg names: String) {
        _middleware.addAll(names)
    }
}

@ConfigDsl
class SslConfig {
    var certPath: String = ""
    var keyPath: String = ""
    var port: Int = 443
    var enabled: Boolean = true
}

@ConfigDsl
class DatabaseConfig {
    var url: String = ""
    var username: String = ""
    var password: String = ""
    var poolSize: Int = 10
    var timeout: Long = 5000

    private var _migrations: MigrationConfig? = null
    val migrations get() = _migrations

    fun migrations(block: MigrationConfig.() -> Unit) {
        _migrations = MigrationConfig().apply(block)
    }
}

@ConfigDsl
class MigrationConfig {
    var directory: String = "migrations"
    var autoRun: Boolean = false
}

@ConfigDsl
data class RouteConfig(
    val method: String,
    val path: String,
    val handler: String
)

@ConfigDsl
class RoutingConfig(private val routes: MutableList<RouteConfig>) {
    fun get(path: String, handler: String) {
        routes.add(RouteConfig("GET", path, handler))
    }
    fun post(path: String, handler: String) {
        routes.add(RouteConfig("POST", path, handler))
    }
    fun put(path: String, handler: String) {
        routes.add(RouteConfig("PUT", path, handler))
    }
    fun delete(path: String, handler: String) {
        routes.add(RouteConfig("DELETE", path, handler))
    }
}

// Entry point
fun server(block: ServerConfig.() -> Unit): ServerConfig =
    ServerConfig().apply(block)

// Pretty print
fun ServerConfig.summary(): String = buildString {
    appendLine("Server Configuration:")
    appendLine("  Host: $host:$port")
    appendLine("  Workers: $workers")
    ssl?.let {
        appendLine("  SSL: ${if (it.enabled) "enabled" else "disabled"} (port ${it.port})")
    }
    database?.let {
        appendLine("  Database: ${it.url} (pool: ${it.poolSize})")
        it.migrations?.let { m -> appendLine("    Migrations: ${m.directory} (auto: ${m.autoRun})") }
    }
    if (middleware.isNotEmpty()) {
        appendLine("  Middleware: ${middleware.joinToString(", ")}")
    }
    if (routes.isNotEmpty()) {
        appendLine("  Routes:")
        routes.forEach { appendLine("    ${it.method} ${it.path} -> ${it.handler}") }
    }
}

fun main() {
    val config = server {
        host = "0.0.0.0"
        port = 8080
        workers = 4

        ssl {
            certPath = "/etc/ssl/cert.pem"
            keyPath = "/etc/ssl/key.pem"
            port = 443
        }

        database {
            url = "jdbc:postgresql://localhost:5432/mydb"
            username = "admin"
            password = "secret"
            poolSize = 20
            timeout = 10_000

            migrations {
                directory = "db/migrations"
                autoRun = true
            }
        }

        middleware("cors", "logging", "auth", "rateLimit")

        routing {
            get("/api/users", "UserController::list")
            post("/api/users", "UserController::create")
            get("/api/users/{id}", "UserController::get")
            put("/api/users/{id}", "UserController::update")
            delete("/api/users/{id}", "UserController::delete")
        }
    }

    println(config.summary())
}

Use Cases

  • Application configuration DSLs
  • Declarative server setup
  • Type-safe nested configuration

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.