CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Ktor server core module for iOS ARM64 target providing essential server-side functionality for building asynchronous web applications and microservices in Kotlin Multiplatform

Pending
Overview
Eval results
Files

utilities.mddocs/

HTTP Utilities and Extensions

HTTP-specific utilities, link headers, server push support, logging capabilities, and various helper functions for enhanced server functionality.

Capabilities

HTTP Link Headers

Support for HTTP Link headers as defined in RFC 8288.

/**
 * Represents HTTP Link header information
 */
data class Link(
    /** URI reference for the link */
    val uri: String,
    
    /** Relation types for this link */
    val rel: List<String>,
    
    /** Content type of the linked resource */
    val type: ContentType? = null,
    
    /** Human-readable title for the link */
    val title: String? = null
)

/**
 * Add Link header to response
 */
fun ApplicationResponse.linkHeader(link: Link)

/**
 * Add Link header to response with simplified parameters
 */
fun ApplicationResponse.linkHeader(
    uri: String,
    rel: String,
    type: ContentType? = null,
    title: String? = null
)

HTTP/2 Server Push

Support for HTTP/2 server push functionality.

/**
 * Initiate HTTP/2 server push
 */
suspend fun ApplicationCall.push(block: ResponsePushBuilder.() -> Unit)

/**
 * Builder for HTTP/2 push promises
 */
class ResponsePushBuilder {
    /** URL to push */
    var url: Url
    
    /** HTTP method for pushed request */
    var method: HttpMethod
    
    /** Headers for pushed request */
    val headers: HeadersBuilder
}

Content Transformation

Default content transformations for request and response processing.

/**
 * Configure default content transformations
 */
fun ApplicationSendPipeline.defaultTransformations()

/**
 * Configure default content transformations for receive pipeline
 */
fun ApplicationReceivePipeline.defaultTransformations()

HTTP Parsing Utilities

Utilities for parsing HTTP headers and cookies.

/**
 * Parse Cookie header into individual cookies
 */
fun parseClientCookiesHeader(cookiesHeader: String): Map<String, String>

/**
 * Parse Set-Cookie header 
 */
fun parseServerSetCookieHeader(setCookieHeader: String): Cookie

Logging and MDC Support

Mapped Diagnostic Context (MDC) support for structured logging.

/**
 * Provides MDC (Mapped Diagnostic Context) functionality
 */
interface MDCProvider {
    /** Get MDC value by key */
    fun get(key: String): String?
    
    /** Set MDC value */
    fun put(key: String, value: String?)
    
    /** Remove MDC value */
    fun remove(key: String)
    
    /** Clear all MDC values */
    fun clear()
    
    /** Get copy of current MDC context */
    fun getCopyOfContextMap(): Map<String, String>?
    
    /** Set entire MDC context */
    fun setContextMap(contextMap: Map<String, String>)
}

/**
 * Call logging plugin for HTTP request/response logging
 */
object CallLogging : ApplicationPlugin<CallLoggingConfig>

Origin Connection Point

Data class for representing connection point information, useful for proxy scenarios.

/**
 * Represents connection point information for forwarded requests
 */
data class OriginConnectionPoint(
    /** URI scheme (http, https) */
    val scheme: String,
    
    /** Host name */
    val host: String,
    
    /** Port number */
    val port: Int,
    
    /** HTTP version */
    val version: String
)

Parameter Utilities

Enhanced parameter handling and URL building utilities.

/**
 * Type alias for parameter collections (string-based key-value pairs)
 */
typealias Parameters = StringValues

/**
 * Get parameter or throw exception if missing
 */
fun Parameters.getOrFail(name: String): String

/**
 * Encode parameters to URL format
 */
fun encodeParameters(parameters: Parameters): String

/**
 * Parse URL-encoded parameters
 */
fun parseParameters(encoded: String): Parameters

URL Building

Utilities for building URLs relative to current request context.

/**
 * Build URLs relative to current request
 */
fun ApplicationCall.url(block: URLBuilder.() -> Unit = {}): String

/**
 * Build paths relative to current request
 */
fun ApplicationCall.path(vararg segments: String): String

/**
 * Build URL with specific path segments
 */
fun ApplicationCall.href(path: String, block: URLBuilder.() -> Unit = {}): String

Path Utilities

Utilities for path manipulation and normalization.

/**
 * Combine path segments safely
 */
fun combinePath(vararg segments: String): String

/**
 * Resolve relative paths
 */
fun resolvePath(base: String, relative: String): String

/**
 * Normalize and relativize paths
 */
fun normalizeAndRelativize(path: String): String

Thread-Safe Collections

Copy-on-write hash map implementation for thread-safe operations.

/**
 * Thread-safe copy-on-write hash map implementation
 */
class CopyOnWriteHashMap<K, V> : MutableMap<K, V> {
    /** Get value by key */
    override fun get(key: K): V?
    
    /** Put key-value pair, returns previous value */
    override fun put(key: K, value: V): V?
    
    /** Remove key, returns previous value */
    override fun remove(key: K): V?
    
    /** Clear all entries */
    override fun clear()
    
    /** Get current size */
    override val size: Int
    
    /** Check if empty */
    override fun isEmpty(): Boolean
    
    /** Check if contains key */
    override fun containsKey(key: K): Boolean
    
    /** Check if contains value */
    override fun containsValue(value: V): Boolean
    
    /** Get all keys */
    override val keys: MutableSet<K>
    
    /** Get all values */
    override val values: MutableCollection<V>
    
    /** Get all entries */
    override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
}

Data Conversion Plugin

Plugin for automatic data type conversion.

/**
 * Plugin for data conversion between types
 */
object DataConversion : ApplicationPlugin<DataConversionConfig>

/**
 * Configuration for data conversion
 */
class DataConversionConfig {
    /** Add conversion from one type to another */
    fun <T, R> convert(from: KClass<T>, to: KClass<R>, converter: (T) -> R)
    
    /** Add conversion with conditions */
    fun <T, R> convert(
        from: KClass<T>, 
        to: KClass<R>, 
        predicate: (T) -> Boolean,
        converter: (T) -> R
    )
}

Error Handling Utilities

Exception classes for common HTTP error scenarios.

/**
 * Exception for bad requests (400)
 */
class BadRequestException(message: String = "Bad Request", cause: Throwable? = null) : Exception(message, cause)

/**
 * Exception for not found resources (404)
 */
class NotFoundException(message: String = "Not Found", cause: Throwable? = null) : Exception(message, cause)

/**
 * Exception when content cannot be transformed to requested type
 */
class CannotTransformContentToTypeException(
    message: String,
    cause: Throwable? = null
) : Exception(message, cause)

/**
 * Exception for unsupported media types (415)
 */
class UnsupportedMediaTypeException(
    contentType: ContentType,
    cause: Throwable? = null
) : Exception("Unsupported media type: $contentType", cause)

Usage Examples

HTTP Link Headers

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

fun Application.linkHeaders() {
    routing {
        get("/article/{id}") {
            val articleId = call.parameters["id"]
            
            // Add link headers for related resources
            call.response.linkHeader(
                uri = "/api/articles/$articleId",
                rel = "canonical"
            )
            
            call.response.linkHeader(Link(
                uri = "/articles/$articleId/comments",
                rel = listOf("related", "comments"),
                type = ContentType.Application.Json,
                title = "Article Comments"
            ))
            
            call.response.linkHeader(
                uri = "/css/article.css",
                rel = "stylesheet",
                type = ContentType.Text.CSS
            )
            
            call.respondText("Article $articleId")
        }
        
        get("/api/users") {
            val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1
            val limit = call.request.queryParameters["limit"]?.toIntOrNull() ?: 20
            
            // Pagination links
            if (page > 1) {
                call.response.linkHeader(
                    uri = "/api/users?page=${page - 1}&limit=$limit",
                    rel = "prev"
                )
            }
            
            call.response.linkHeader(
                uri = "/api/users?page=${page + 1}&limit=$limit",
                rel = "next"
            )
            
            call.response.linkHeader(
                uri = "/api/users?page=1&limit=$limit",
                rel = "first"
            )
            
            call.respond(emptyList<String>()) // Mock response
        }
    }
}

HTTP/2 Server Push

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

fun Application.serverPush() {
    routing {
        get("/") {
            // Push related resources before sending main response
            call.push {
                url = Url("/css/main.css")
                method = HttpMethod.Get
                headers.append(HttpHeaders.Accept, "text/css")
            }
            
            call.push {
                url = Url("/js/main.js")
                method = HttpMethod.Get
                headers.append(HttpHeaders.Accept, "application/javascript")
            }
            
            call.push {
                url = Url("/images/logo.png")
                method = HttpMethod.Get
                headers.append(HttpHeaders.Accept, "image/*")
            }
            
            // Send main HTML response
            call.respondText("""
                <!DOCTYPE html>
                <html>
                <head>
                    <link rel="stylesheet" href="/css/main.css">
                    <script src="/js/main.js" defer></script>
                </head>
                <body>
                    <img src="/images/logo.png" alt="Logo">
                    <h1>Welcome</h1>
                </body>
                </html>
            """.trimIndent(), ContentType.Text.Html)
        }
    }
}

URL Building and Path Utilities

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

fun Application.urlBuilding() {
    routing {
        get("/user/{id}") {
            val userId = call.parameters["id"]
            
            // Build URLs relative to current request
            val profileUrl = call.url {
                path("profile")
            }
            
            val apiUrl = call.url {
                path("api", "users", userId ?: "")
                parameters.append("include", "profile")
            }
            
            val avatarPath = call.path("avatar.jpg")
            
            val editHref = call.href("/edit") {
                parameters.append("id", userId ?: "")
            }
            
            call.respond(mapOf(
                "userId" to userId,
                "profileUrl" to profileUrl,
                "apiUrl" to apiUrl,
                "avatarPath" to avatarPath,
                "editHref" to editHref
            ))
        }
        
        get("/docs/{...}") {
            val pathSegments = call.parameters.getAll("...")
            val docPath = pathSegments?.joinToString("/") ?: ""
            
            // Path utilities
            val normalizedPath = normalizeAndRelativize(docPath)
            val combinedPath = combinePath("docs", "v1", normalizedPath)
            val resolvedPath = resolvePath("/documentation", combinedPath)
            
            call.respond(mapOf(
                "originalPath" to docPath,
                "normalizedPath" to normalizedPath,
                "combinedPath" to combinedPath,
                "resolvedPath" to resolvedPath
            ))
        }
    }
}

Parameter Handling

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

fun Application.parameterHandling() {
    routing {
        get("/required") {
            try {
                val userId = call.request.queryParameters.getOrFail("userId")
                val action = call.request.queryParameters.getOrFail("action")
                
                call.respond(mapOf(
                    "userId" to userId,
                    "action" to action
                ))
                
            } catch (e: IllegalArgumentException) {
                call.respond(HttpStatusCode.BadRequest, "Missing required parameters")
            }
        }
        
        post("/form") {
            val formParams = call.receiveParameters()
            
            // Encode parameters back to URL format
            val encoded = encodeParameters(formParams)
            
            call.respond(mapOf(
                "received" to formParams.toMap(),
                "encoded" to encoded
            ))
        }
    }
}

Thread-Safe Data Structures

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

class SessionManager {
    private val sessions = CopyOnWriteHashMap<String, SessionData>()
    
    fun createSession(sessionId: String, data: SessionData) {
        sessions[sessionId] = data
    }
    
    fun getSession(sessionId: String): SessionData? {
        return sessions[sessionId]
    }
    
    fun removeSession(sessionId: String): SessionData? {
        return sessions.remove(sessionId)
    }
    
    fun getAllSessions(): Map<String, SessionData> {
        return sessions.toMap()
    }
    
    fun getActiveSessionCount(): Int {
        return sessions.size
    }
}

data class SessionData(
    val userId: String,
    val createdAt: Long,
    val lastAccessedAt: Long
)

fun Application.sessionHandling() {
    val sessionManager = SessionManager()
    
    routing {
        post("/login") {
            val sessionId = generateSessionId()
            val sessionData = SessionData(
                userId = "user123",
                createdAt = System.currentTimeMillis(),
                lastAccessedAt = System.currentTimeMillis()
            )
            
            sessionManager.createSession(sessionId, sessionData)
            
            call.respond(mapOf(
                "sessionId" to sessionId,
                "activeSessions" to sessionManager.getActiveSessionCount()
            ))
        }
        
        get("/session/{id}") {
            val sessionId = call.parameters["id"]
            val session = sessionManager.getSession(sessionId ?: "")
            
            if (session != null) {
                call.respond(session)
            } else {
                call.respond(HttpStatusCode.NotFound, "Session not found")
            }
        }
    }
}

private fun generateSessionId(): String {
    return java.util.UUID.randomUUID().toString()
}

Error Handling

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

fun Application.errorHandling() {
    routing {
        get("/validate/{value}") {
            val value = call.parameters["value"]
            
            if (value.isNullOrBlank()) {
                throw BadRequestException("Value parameter is required")
            }
            
            val intValue = value.toIntOrNull() 
                ?: throw BadRequestException("Value must be a valid integer")
            
            if (intValue < 0) {
                throw BadRequestException("Value must be positive")
            }
            
            call.respond(mapOf("validatedValue" to intValue))
        }
        
        get("/resource/{id}") {
            val resourceId = call.parameters["id"]
            val resource = findResourceById(resourceId)
            
            if (resource == null) {
                throw NotFoundException("Resource with ID $resourceId not found")
            }
            
            call.respond(resource)
        }
        
        post("/convert") {
            val contentType = call.request.contentType
            
            when {
                contentType.match(ContentType.Application.Json) -> {
                    try {
                        val data = call.receive<Map<String, Any>>()
                        call.respond(data)
                    } catch (e: Exception) {
                        throw CannotTransformContentToTypeException(
                            "Failed to parse JSON content",
                            e
                        )
                    }
                }
                
                contentType.match(ContentType.Application.Xml) -> {
                    throw UnsupportedMediaTypeException(contentType)
                }
                
                else -> {
                    throw UnsupportedMediaTypeException(contentType)
                }
            }
        }
    }
}

private fun findResourceById(id: String?): Map<String, Any>? {
    // Mock implementation
    return if (id == "123") {
        mapOf("id" to id, "name" to "Sample Resource")
    } else {
        null
    }
}

Data Conversion

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

data class User(val id: Int, val name: String, val email: String)
data class UserDto(val id: String, val displayName: String, val contactEmail: String)

fun Application.dataConversion() {
    install(DataConversion) {
        // Convert User to UserDto
        convert<User, UserDto> { user ->
            UserDto(
                id = user.id.toString(),
                displayName = user.name,
                contactEmail = user.email
            )
        }
        
        // Convert String to Int with validation
        convert<String, Int>(
            predicate = { it.matches(Regex("\\d+")) }
        ) { it.toInt() }
        
        // Convert String to Boolean
        convert<String, Boolean> { str ->
            when (str.lowercase()) {
                "true", "yes", "1" -> true
                "false", "no", "0" -> false
                else -> throw IllegalArgumentException("Invalid boolean value: $str")
            }
        }
    }
    
    routing {
        get("/user/{id}") {
            val userId = call.parameters["id"]?.toIntOrNull() 
                ?: return@get call.respond(HttpStatusCode.BadRequest)
            
            val user = User(userId, "John Doe", "john@example.com")
            
            // DataConversion will automatically convert User to UserDto
            call.respond(user)
        }
    }
}

Logging and MDC

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

fun Application.loggingAndMdc() {
    install(CallLogging) {
        level = Level.INFO
        
        mdc("requestId") {
            java.util.UUID.randomUUID().toString()
        }
        
        mdc("userId") { call ->
            call.request.headers["X-User-ID"]
        }
        
        filter { call ->
            !call.request.path().startsWith("/health")
        }
    }
    
    routing {
        get("/api/data") {
            val mdcProvider = application.environment.monitor.mdcProvider
            
            // Add custom MDC values
            mdcProvider?.put("operation", "fetchData")
            mdcProvider?.put("startTime", System.currentTimeMillis().toString())
            
            try {
                // Simulate data fetching
                val data = fetchData()
                
                mdcProvider?.put("recordCount", data.size.toString())
                application.environment.log.info("Data fetch completed successfully")
                
                call.respond(data)
                
            } catch (e: Exception) {
                mdcProvider?.put("error", e.message ?: "Unknown error")
                application.environment.log.error("Data fetch failed", e)
                
                call.respond(HttpStatusCode.InternalServerError, "Data fetch failed")
            } finally {
                mdcProvider?.remove("operation")
                mdcProvider?.remove("startTime")
                mdcProvider?.remove("recordCount")
                mdcProvider?.remove("error")
            }
        }
    }
}

private fun fetchData(): List<String> {
    // Mock data fetching
    return listOf("item1", "item2", "item3")
}

Install with Tessl CLI

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

docs

application.md

config.md

engine.md

index.md

request-response.md

routing.md

utilities.md

tile.json