CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-ktor--ktor-server-core-jvm

Core server functionality for the Ktor asynchronous web framework, providing essential building blocks for HTTP servers including application lifecycle management, routing foundations, request/response handling, and plugin architecture specifically compiled for JVM targets.

Pending
Overview
Eval results
Files

config.mddocs/

Configuration Management

Hierarchical configuration system with type conversion, environment-specific settings, and support for multiple configuration sources including files, environment variables, and programmatic configuration.

Capabilities

Application Configuration

Core interface for accessing application configuration with hierarchical property access and type conversion.

/**
 * Interface for application configuration access
 */
interface ApplicationConfig {
    /** Get configuration property by path */
    fun property(path: String): ApplicationConfigValue
    /** Get optional configuration property */
    fun propertyOrNull(path: String): ApplicationConfigValue?
    /** Get nested configuration section */
    fun config(path: String): ApplicationConfig
    /** Get list of configuration sections */
    fun configList(path: String): List<ApplicationConfig>
    /** Get all configuration keys at current level */
    fun keys(): Set<String>
    /** Convert configuration to map */
    fun toMap(): Map<String, Any?>
}

/**
 * Configuration value with type conversion
 */
interface ApplicationConfigValue {
    /** Get value as string */
    fun getString(): String
    /** Get value as list of strings */
    fun getList(): List<String>
}

/** Access configuration from application call */
val ApplicationCall.config: ApplicationConfig get() = application.environment.config

Configuration Value Extensions

Extension functions for type-safe configuration value access with default values and validation.

/**
 * Get configuration value as Int
 * @param default - Default value if property not found or conversion fails
 * @return Integer value or default
 */
fun ApplicationConfigValue.getInt(default: Int = 0): Int = try {
    getString().toInt()
} catch (e: Exception) {
    default
}

/**
 * Get configuration value as Long
 */
fun ApplicationConfigValue.getLong(default: Long = 0L): Long = try {
    getString().toLong()
} catch (e: Exception) {
    default
}

/**
 * Get configuration value as Boolean
 */
fun ApplicationConfigValue.getBoolean(default: Boolean = false): Boolean = try {
    getString().toBoolean()
} catch (e: Exception) {
    default
}

/**
 * Get configuration value as Double
 */
fun ApplicationConfigValue.getDouble(default: Double = 0.0): Double = try {
    getString().toDouble()
} catch (e: Exception) {
    default
}

/**
 * Get required configuration value as Int
 * @throws ConfigurationException if property not found or conversion fails
 */
fun ApplicationConfigValue.getIntOrFail(): Int = try {
    getString().toInt()
} catch (e: Exception) {
    throw ConfigurationException("Cannot convert configuration value to Int", e)
}

/**
 * Get required configuration value as Long
 */
fun ApplicationConfigValue.getLongOrFail(): Long = try {
    getString().toLong()
} catch (e: Exception) {
    throw ConfigurationException("Cannot convert configuration value to Long", e)
}

/**
 * Get required configuration value as Boolean
 */
fun ApplicationConfigValue.getBooleanOrFail(): Boolean = try {
    getString().toBoolean()
} catch (e: Exception) {
    throw ConfigurationException("Cannot convert configuration value to Boolean", e)
}

Configuration Implementations

Concrete implementations of ApplicationConfig for different configuration sources and patterns.

/**
 * Map-based implementation of ApplicationConfig
 */
class MapApplicationConfig : ApplicationConfig {
    /** Create config from map */
    constructor(map: Map<String, Any>)
    /** Create config from vararg pairs */
    constructor(vararg values: Pair<String, Any>)
    
    /** Put configuration value */
    fun put(path: String, value: String)
    /** Put all values from map */
    fun putAll(values: Map<String, Any>)
    /** Remove configuration value */
    fun remove(path: String)
    /** Clear all configuration */
    fun clear()
}

/**
 * Merges multiple configuration sources with precedence
 */
class MergedApplicationConfig(vararg sources: ApplicationConfig) : ApplicationConfig {
    /** Add configuration source with higher precedence */
    fun withFallback(config: ApplicationConfig): MergedApplicationConfig
}

/**
 * Empty configuration implementation
 */
object EmptyApplicationConfig : ApplicationConfig

Configuration Loading

Utilities for loading configuration from various sources including files, environment variables, and system properties.

/**
 * Load configuration from HOCON file
 * @param file - Configuration file to load
 * @return ApplicationConfig instance
 */
fun loadApplicationConfig(file: File): ApplicationConfig

/**
 * Load configuration from resource
 * @param resource - Resource path to load
 * @return ApplicationConfig instance  
 */
fun loadApplicationConfig(resource: String): ApplicationConfig

/**
 * Load configuration from multiple sources
 * @param sources - Configuration sources in priority order
 * @return Merged configuration
 */
fun loadApplicationConfig(vararg sources: ApplicationConfig): ApplicationConfig

/**
 * Create configuration from environment variables
 * @param prefix - Environment variable prefix to filter
 * @return Configuration from environment
 */
fun environmentConfig(prefix: String = ""): ApplicationConfig

/**
 * Create configuration from system properties
 * @param prefix - System property prefix to filter
 * @return Configuration from system properties
 */
fun systemPropertiesConfig(prefix: String = ""): ApplicationConfig

Configuration Validation

Utilities for validating configuration values and providing meaningful error messages.

/**
 * Configuration validation exception
 */
class ConfigurationException(message: String, cause: Throwable? = null) : Exception(message, cause)

/**
 * Validate configuration property exists
 * @param path - Configuration path to check
 * @throws ConfigurationException if property not found
 */
fun ApplicationConfig.requireProperty(path: String): ApplicationConfigValue {
    return propertyOrNull(path) ?: throw ConfigurationException("Required configuration property '$path' not found")
}

/**
 * Validate configuration section exists
 * @param path - Configuration section path to check
 * @throws ConfigurationException if section not found
 */
fun ApplicationConfig.requireConfig(path: String): ApplicationConfig {
    return try {
        config(path)
    } catch (e: Exception) {
        throw ConfigurationException("Required configuration section '$path' not found", e)
    }
}

/**
 * Validate configuration value is in allowed set
 * @param allowedValues - Set of allowed values
 * @throws ConfigurationException if value not in set
 */
fun ApplicationConfigValue.requireOneOf(vararg allowedValues: String): String {
    val value = getString()
    if (value !in allowedValues) {
        throw ConfigurationException("Configuration value '$value' must be one of: ${allowedValues.joinToString()}")
    }
    return value
}

Configuration Scopes

Scoped configuration access for different parts of the application with inheritance and overrides.

/**
 * Scoped configuration access
 */
class ConfigurationScope(
    private val config: ApplicationConfig,
    private val path: String = ""
) {
    /** Get property in current scope */
    fun property(name: String): ApplicationConfigValue = config.property(scopedPath(name))
    /** Get optional property in current scope */
    fun propertyOrNull(name: String): ApplicationConfigValue? = config.propertyOrNull(scopedPath(name))
    /** Create nested scope */
    fun scope(name: String): ConfigurationScope = ConfigurationScope(config, scopedPath(name))
    
    private fun scopedPath(name: String) = if (path.isEmpty()) name else "$path.$name"
}

/**
 * Create configuration scope for specific section
 * @param path - Section path for scope
 * @return Scoped configuration access
 */
fun ApplicationConfig.scope(path: String): ConfigurationScope = ConfigurationScope(this, path)

Usage Examples:

import io.ktor.server.application.*
import io.ktor.server.config.*
import io.ktor.server.response.*
import io.ktor.server.routing.*

// Basic configuration access
fun Application.basicConfigExample() {
    // Access configuration values
    val appName = environment.config.property("app.name").getString()
    val port = environment.config.property("server.port").getInt(8080)
    val debugMode = environment.config.propertyOrNull("app.debug")?.getBoolean() ?: false
    
    log.info("Starting $appName on port $port (debug: $debugMode)")
    
    routing {
        get("/config") {
            call.respondText("App: $appName, Port: $port, Debug: $debugMode")
        }
    }
}

// Configuration with validation
fun Application.validatedConfigExample() {
    try {
        // Required configuration
        val dbUrl = environment.config.requireProperty("database.url").getString()
        val dbDriver = environment.config.requireProperty("database.driver").getString()
        
        // Optional with defaults
        val connectionTimeout = environment.config.propertyOrNull("database.timeout")?.getInt() ?: 30
        val maxConnections = environment.config.propertyOrNull("database.maxConnections")?.getInt() ?: 10
        
        // Validated enums
        val logLevel = environment.config.requireProperty("logging.level")
            .requireOneOf("DEBUG", "INFO", "WARN", "ERROR")
        
        log.info("Database: $dbUrl (timeout: ${connectionTimeout}s, max connections: $maxConnections)")
        log.info("Log level: $logLevel")
        
    } catch (e: ConfigurationException) {
        log.error("Configuration error: ${e.message}")
        throw e
    }
}

// Nested configuration sections
fun Application.nestedConfigExample() {
    // Database configuration section
    val dbConfig = environment.config.config("database")
    val dbUrl = dbConfig.property("url").getString()
    val dbUser = dbConfig.property("user").getString()
    val dbPassword = dbConfig.property("password").getString()
    
    // Server configuration list
    val serverConfigs = environment.config.configList("servers")
    for ((index, serverConfig) in serverConfigs.withIndex()) {
        val host = serverConfig.property("host").getString()
        val port = serverConfig.property("port").getInt()
        log.info("Server $index: $host:$port")
    }
    
    routing {
        get("/servers") {
            val servers = serverConfigs.map { server ->
                mapOf(
                    "host" to server.property("host").getString(),
                    "port" to server.property("port").getInt()
                )
            }
            call.respond(servers)
        }
    }
}

// Programmatic configuration
fun Application.programmaticConfigExample() {
    // Create configuration from map
    val appConfig = MapApplicationConfig(
        "app.name" to "My Ktor App",
        "app.version" to "1.0.0",
        "server.host" to "localhost",
        "server.port" to "8080"
    )
    
    // Merge with environment variables
    val envConfig = environmentConfig("KTOR_")
    val mergedConfig = MergedApplicationConfig(envConfig, appConfig)
    
    // Access merged configuration
    val appName = mergedConfig.property("app.name").getString()
    val host = mergedConfig.property("server.host").getString()
    val port = mergedConfig.property("server.port").getInt()
    
    log.info("App: $appName running on $host:$port")
}

// Configuration scopes
fun Application.scopedConfigExample() {
    // Create database scope
    val dbScope = environment.config.scope("database")
    val url = dbScope.property("url").getString()
    val user = dbScope.property("user").getString()
    
    // Create cache scope  
    val cacheScope = environment.config.scope("cache")
    val cacheSize = cacheScope.property("size").getInt(1000)
    val cacheTtl = cacheScope.property("ttl").getLong(3600)
    
    // Nested scopes
    val redisScope = cacheScope.scope("redis")
    val redisHost = redisScope.property("host").getString()
    val redisPort = redisScope.property("port").getInt(6379)
    
    log.info("Database: $url (user: $user)")
    log.info("Cache: size=$cacheSize, ttl=${cacheTtl}s")
    log.info("Redis: $redisHost:$redisPort")
}

// Route-specific configuration access
fun Application.routeConfigExample() {
    routing {
        get("/admin") {
            // Access configuration within route
            val adminEnabled = call.config.propertyOrNull("admin.enabled")?.getBoolean() ?: false
            if (!adminEnabled) {
                call.respond(HttpStatusCode.NotFound)
                return@get
            }
            
            val adminTitle = call.config.property("admin.title").getString()
            call.respondText("Welcome to $adminTitle")
        }
        
        get("/api/limits") {
            val rateLimit = call.config.property("api.rateLimit").getInt(100)
            val maxPayload = call.config.property("api.maxPayloadSize").getLong(1024 * 1024)
            
            call.respond(mapOf(
                "rateLimit" to rateLimit,
                "maxPayloadSize" to maxPayload
            ))
        }
    }
}

Example Configuration File (application.conf):

app {
    name = "My Ktor Application"
    version = "1.0.0"
    debug = false
}

server {
    host = "0.0.0.0"
    port = 8080
}

database {
    url = "jdbc:postgresql://localhost:5432/myapp"
    driver = "org.postgresql.Driver"
    user = "appuser"
    password = "secret"
    timeout = 30
    maxConnections = 20
}

cache {
    size = 10000
    ttl = 3600
    redis {
        host = "localhost"
        port = 6379
    }
}

logging {
    level = "INFO"
}

servers = [
    {
        host = "server1.example.com"
        port = 8080
    },
    {
        host = "server2.example.com" 
        port = 8080
    }
]

admin {
    enabled = true
    title = "Admin Panel"
}

api {
    rateLimit = 1000
    maxPayloadSize = 5242880  # 5MB
}

Install with Tessl CLI

npx tessl i tessl/maven-io-ktor--ktor-server-core-jvm

docs

application.md

config.md

engine.md

index.md

plugins.md

request.md

response.md

routing.md

tile.json