CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Ktor Server Core library providing foundational infrastructure for building asynchronous web applications and REST APIs with Kotlin

Pending
Overview
Eval results
Files

application.mddocs/

Application Management

Ktor's application management system provides comprehensive lifecycle control, plugin architecture, and event handling for web applications. The Application class serves as the central coordinator for all server functionality.

Core Application Class

Application Class

class Application internal constructor(
    environment: ApplicationEnvironment,
    developmentMode: Boolean,
    rootPath: String,
    monitor: Events,
    parentCoroutineContext: CoroutineContext,
    engineProvider: () -> ApplicationEngine
) : ApplicationCallPipeline, CoroutineScope {
    val engine: ApplicationEngine
    var rootPath: String
    val monitor: Events
    val parentCoroutineContext: CoroutineContext
    
    suspend fun disposeAndJoin()
}

Application Properties

// Access application properties
val app: Application = /* ... */

// Engine that runs the application (may be null during testing)
val engine: ApplicationEngine? = app.engine

// Root path for the application (useful for sub-applications)
val rootPath: String = app.rootPath

// Event monitoring system
val monitor: Events = app.monitor

// Parent coroutine context for structured concurrency
val parentContext: CoroutineContext = app.parentCoroutineContext

Application Lifecycle

// Dispose application resources
val disposeJob: Job = application.dispose()

// Dispose and wait for completion
application.disposeAndJoin()

Application Call Pipeline

The ApplicationCallPipeline processes incoming requests through defined phases.

Pipeline Phases

// Standard pipeline phases
object ApplicationPhase {
    val Setup = PipelinePhase("Setup")
    val Monitoring = PipelinePhase("Monitoring") 
    val Plugins = PipelinePhase("Plugins")
    val Call = PipelinePhase("Call")
    val Fallback = PipelinePhase("Fallback")
}

Pipeline Configuration

class ApplicationCallPipeline(
    developmentMode: Boolean = false,
    environment: ApplicationEnvironment
) {
    val receivePipeline: ApplicationReceivePipeline
    val sendPipeline: ApplicationSendPipeline
    val developmentMode: Boolean
    val environment: ApplicationEnvironment
}

Application Call Interface

ApplicationCall Properties

interface ApplicationCall : CoroutineScope {
    val attributes: Attributes
    val request: ApplicationRequest
    val response: ApplicationResponse
    val application: Application
    val parameters: Parameters
    
    suspend fun <T> receiveNullable(typeInfo: TypeInfo): T?
    suspend fun respond(message: Any?, typeInfo: TypeInfo?)
}

interface PipelineCall : ApplicationCall {
    override val request: PipelineRequest
    override val response: PipelineResponse
}

Pipeline Call Implementation

interface PipelineCall : ApplicationCall {
    val request: PipelineRequest
    val response: PipelineResponse
}

Context Extensions

// Access current call from pipeline context
val PipelineContext<*, PipelineCall>.call: PipelineCall

// Access current application from pipeline context  
val PipelineContext<*, PipelineCall>.application: Application

Plugin System

Plugin Interface

interface Plugin<TPipeline : Any, TConfiguration : Any, TPlugin : Any> {
    val key: AttributeKey<TPlugin>
    fun install(pipeline: TPipeline, configure: TConfiguration.() -> Unit): TPlugin
}

Application Plugin Types

// Base application plugin interface
interface BaseApplicationPlugin<TPipeline : Any, TConfiguration : Any, TPlugin : Any> : 
    Plugin<TPipeline, TConfiguration, TPlugin>

// Simplified application plugin interface
interface ApplicationPlugin<TConfiguration : Any> : 
    BaseApplicationPlugin<Application, TConfiguration, *>

Plugin Installation

// Install plugin with configuration
fun <P : Pipeline<*, ApplicationCall>, B : Any, F : Any> P.install(
    plugin: Plugin<P, B, F>,
    configure: B.() -> Unit = {}
): F

// Example plugin installation
fun Application.configurePlugins() {
    install(ContentNegotiation) {
        json {
            prettyPrint = true
            isLenient = true
        }
    }
    
    install(CallLogging) {
        level = Level.INFO
        filter { call -> call.request.path().startsWith("/api/") }
    }
}

Plugin Access

// Get installed plugin instance (throws if not installed)
fun <F : Any> ApplicationCallPipeline.plugin(key: AttributeKey<F>): F

// Get plugin instance or null
fun <F : Any> ApplicationCallPipeline.pluginOrNull(key: AttributeKey<F>): F?

// Access plugin registry
val ApplicationCallPipeline.pluginRegistry: PluginRegistry

// Example plugin access
fun Application.usePlugin() {
    val contentNegotiation = plugin(ContentNegotiation)
    val logging = pluginOrNull(CallLogging)
    
    if (logging != null) {
        // Plugin is installed, use it
    }
}

Plugin Creation

// Create application plugin with configuration
fun <TConfiguration : Any> createApplicationPlugin(
    name: String,
    createConfiguration: () -> TConfiguration,
    body: PluginBuilder<TConfiguration>.() -> Unit
): ApplicationPlugin<TConfiguration>

// Create route-scoped plugin
fun <TConfiguration : Any> createRouteScopedPlugin(
    name: String, 
    createConfiguration: () -> TConfiguration,
    body: PluginBuilder<TConfiguration>.() -> Unit
): Plugin<Route, TConfiguration, Unit>

// Example custom plugin
val CustomPlugin = createApplicationPlugin("CustomPlugin", ::CustomConfig) {
    val config = pluginConfig
    
    onCall { call ->
        // Plugin logic for each call
        call.attributes.put(CustomAttributeKey, config.value)
    }
    
    onCallReceive { call ->
        // Intercept request content
        transformBody { data -> 
            // Transform incoming data
            processData(data)
        }
    }
}

// Plugin configuration class
class CustomConfig {
    var value: String = "default"
    var enabled: Boolean = true
}

Exception Handling

Plugin Exceptions

// Thrown when attempting to install duplicate plugin
class DuplicatePluginException(key: String) : Exception(
    "Plugin $key is already installed"
)

// Thrown when accessing non-installed plugin
class MissingApplicationPluginException(key: AttributeKey<*>) : Exception(
    "Plugin ${key.name} has not been installed"
)

Exception Usage

fun Application.handlePluginErrors() {
    try {
        install(SomePlugin)
        install(SomePlugin) // This will throw DuplicatePluginException
    } catch (e: DuplicatePluginException) {
        log.warn("Plugin already installed: ${e.message}")
    }
    
    try {
        val plugin = plugin(NonInstalledPlugin.key)
    } catch (e: MissingApplicationPluginException) {
        log.error("Required plugin not installed: ${e.message}")
    }
}

Event System

Application Events

// Application lifecycle events
object ApplicationStarting : EventDefinition<Application>()
object ApplicationModulesLoading : EventDefinition<Application>() 
object ApplicationModulesLoaded : EventDefinition<Application>()
object ApplicationStarted : EventDefinition<Application>()
object ServerReady : EventDefinition<ApplicationEngine>()
object ApplicationStopPreparing : EventDefinition<Application>()
object ApplicationStopping : EventDefinition<Application>()
object ApplicationStopped : EventDefinition<Application>()

Event Subscription

fun Application.subscribeToEvents() {
    // Subscribe to application start
    monitor.subscribe(ApplicationStarted) { application ->
        application.log.info("Application started successfully")
        // Initialize resources, open connections, etc.
    }
    
    // Subscribe to server ready (engine-specific)
    monitor.subscribe(ServerReady) { engine ->
        val connectors = engine.resolvedConnectors()
        log.info("Server ready on connectors: $connectors")
    }
    
    // Subscribe to application stop preparation
    monitor.subscribe(ApplicationStopPreparing) { application ->
        application.log.info("Preparing to stop application")
        // Clean up resources, close connections, etc.
    }
    
    // Subscribe to application stopped
    monitor.subscribe(ApplicationStopped) { application ->
        application.log.info("Application stopped")
    }
}

Event Raising

// Raise custom events
fun Application.raiseCustomEvent() {
    // Define custom event
    object CustomEvent : EventDefinition<String>()
    
    // Subscribe to custom event
    monitor.subscribe(CustomEvent) { data ->
        log.info("Custom event received: $data")
    }
    
    // Raise the event
    monitor.raise(CustomEvent, "event data")
}

Hook System

Hook Interface

interface Hook<HookHandler : Function<Unit>> {
    fun install(pipeline: ApplicationCallPipeline, handler: HookHandler)
}

Using Hooks

fun Application.setupHooks() {
    // Example hook usage (implementation depends on specific hooks available)
    // Hooks provide extension points for plugin developers
    
    // Install hook handler
    MyHook.install(this) { context ->
        // Hook implementation
        log.debug("Hook executed for call: ${context.call.request.uri}")
    }
}

Server Configuration

ServerConfig Class

data class ServerConfig internal constructor(
    val environment: ApplicationEnvironment,
    val rootPath: String = "",
    val developmentMode: Boolean = false,
    val parentCoroutineContext: CoroutineContext? = null
) {
    // Internal properties
    internal val modules: List<Application.() -> Unit>
    internal val watchPaths: List<String>
}

ServerConfigBuilder

class ServerConfigBuilder {
    var environment: ApplicationEnvironment
    var watchPaths: MutableList<String>
    var rootPath: String = ""
    var developmentMode: Boolean = false
    var parentCoroutineContext: CoroutineContext? = null
    
    // Install application module
    fun module(body: Application.() -> Unit)
}

Server Configuration Creation

// Create server configuration
fun serverConfig(
    configure: ServerConfigBuilder.() -> Unit = {}
): ServerConfig

// Example server configuration
val config = serverConfig {
    environment = applicationEnvironment {
        // Environment configuration
    }
    
    developmentMode = true
    rootPath = "/api"
    
    module {
        // Application module configuration
        configureRouting()
        configureSerialization()
    }
    
    module {
        // Additional module
        configureSecurity()
    }
}

Logging

Application Logging

// Access logger from Application
val Application.log: Logger

// Example logging usage
fun Application.configureLogging() {
    log.info("Configuring application")
    
    monitor.subscribe(ApplicationStarted) { app ->
        app.log.info("Application started successfully")
    }
    
    monitor.subscribe(ApplicationStopPreparing) { app ->
        app.log.warn("Application is preparing to stop")
    }
}

MDC Provider

// MDC (Mapped Diagnostic Context) for structured logging
interface MDCProvider {
    fun withMDCBlock(block: () -> Unit)
}

Complete Application Example

fun main() {
    val server = embeddedServer(Netty, port = 8080) {
        // Install core plugins
        install(ContentNegotiation) {
            json()
        }
        
        install(CallLogging) {
            level = Level.INFO
        }
        
        // Subscribe to application events
        monitor.subscribe(ApplicationStarted) { app ->
            app.log.info("Server started on port 8080")
        }
        
        // Configure routing
        routing {
            get("/") {
                call.respondText("Hello, Ktor!")
            }
            
            get("/plugins") {
                val plugins = pluginRegistry.allKeys.map { it.name }
                call.respond(plugins)
            }
        }
        
        // Custom plugin installation
        install(createApplicationPlugin("RequestId") {
            onCall { call ->
                val requestId = UUID.randomUUID().toString()
                call.attributes.put(RequestIdKey, requestId)
                call.response.header("X-Request-ID", requestId)
            }
        })
    }
    
    server.start(wait = true)
}

val RequestIdKey = AttributeKey<String>("RequestId")

This comprehensive documentation covers all aspects of Ktor's application management system, from basic lifecycle control to advanced plugin development and event handling.

Install with Tessl CLI

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

docs

application.md

configuration.md

engine.md

index.md

request-response.md

routing.md

tile.json