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

routing.mddocs/

Routing System

Powerful routing DSL with pattern matching, parameter extraction, and nested route organization. Provides declarative route definition with support for HTTP methods, path patterns, and conditional routing based on headers, parameters, and other request characteristics.

Capabilities

Core Routing Interfaces

Base interfaces for route definition and organization.

/**
 * Represents a route node in routing tree
 */
interface Route {
    /** Parent route in the hierarchy */
    val parent: Route?
    
    /** Selector used to match this route */
    val selector: RouteSelector
    
    /** Whether development mode is enabled */
    val developmentMode: Boolean
    
    /** Application environment */
    val environment: ApplicationEnvironment
}

/**
 * Implementation of route with child routes and handlers
 */
open class RoutingNode : Route {
    /** Child routes */
    val children: List<RoutingNode>
    
    /** List of handlers for this route */
    val handlers: List<PipelineInterceptor<Unit, PipelineCall>>
    
    /** Create child route with given selector */
    fun createChild(selector: RouteSelector): RoutingNode
}

/**
 * Root routing node for an application
 */
class Routing : RoutingNode

Routing Builder DSL

DSL interface for constructing routes declaratively.

/**
 * DSL builder interface for constructing routes
 */
interface RoutingBuilder {
    /** Create child route with path pattern */
    fun route(path: String, build: Route.() -> Unit): Route
    
    /** Create route for specific HTTP method */
    fun method(method: HttpMethod, body: Route.() -> Unit): Route
    
    /** Create route matching parameter value */
    fun param(name: String, value: String, build: Route.() -> Unit): Route
    
    /** Create route matching optional parameter */
    fun optionalParam(name: String, value: String, build: Route.() -> Unit): Route
    
    /** Create route matching header value */
    fun header(name: String, value: String, build: Route.() -> Unit): Route
    
    /** Create route matching Accept header */
    fun accept(contentType: ContentType, build: Route.() -> Unit): Route
    
    /** Create route matching Content-Type header */
    fun contentType(contentType: ContentType, build: Route.() -> Unit): Route
    
    /** Create route matching host pattern */
    fun host(pattern: String, build: Route.() -> Unit): Route
    
    /** Create route matching port number */
    fun port(port: Int, build: Route.() -> Unit): Route
    
    /** Add handler to current route */
    fun handle(body: suspend PipelineContext<Unit, PipelineCall>.() -> Unit)
}

HTTP Method DSL Functions

Convenient DSL functions for common HTTP methods.

/** Handle GET requests */
fun Route.get(path: String = "", body: suspend PipelineContext<Unit, PipelineCall>.() -> Unit): Route

/** Handle POST requests */
fun Route.post(path: String = "", body: suspend PipelineContext<Unit, PipelineCall>.() -> Unit): Route

/** Handle PUT requests */
fun Route.put(path: String = "", body: suspend PipelineContext<Unit, PipelineCall>.() -> Unit): Route

/** Handle DELETE requests */
fun Route.delete(path: String = "", body: suspend PipelineContext<Unit, PipelineCall>.() -> Unit): Route

/** Handle PATCH requests */
fun Route.patch(path: String = "", body: suspend PipelineContext<Unit, PipelineCall>.() -> Unit): Route

/** Handle HEAD requests */
fun Route.head(path: String = "", body: suspend PipelineContext<Unit, PipelineCall>.() -> Unit): Route

/** Handle OPTIONS requests */
fun Route.options(path: String = "", body: suspend PipelineContext<Unit, PipelineCall>.() -> Unit): Route

/** Handle specific HTTP method */
fun Route.method(method: HttpMethod, path: String = "", body: suspend PipelineContext<Unit, PipelineCall>.() -> Unit): Route

Route Selectors

Classes that define how routes are matched against incoming requests.

Base Route Selector

/**
 * Base class for route selection criteria
 */
abstract class RouteSelector {
    /** Evaluate if this selector matches the request */
    abstract fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation
    
    /** Quality score for route selection priority */
    open val quality: Double
}

Path Segment Selectors

/**
 * Matches exact path segment
 */
data class PathSegmentConstantRouteSelector(val value: String) : RouteSelector

/**
 * Matches path segment parameter and captures value
 */
data class PathSegmentParameterRouteSelector(
    val name: String,
    val prefix: String? = null,
    val suffix: String? = null
) : RouteSelector

/**
 * Matches optional path segment parameter
 */
data class PathSegmentOptionalParameterRouteSelector(
    val name: String,
    val prefix: String? = null,
    val suffix: String? = null
) : RouteSelector

/**
 * Matches any single path segment
 */
object PathSegmentWildcardRouteSelector : RouteSelector

/**
 * Matches remaining path segments (catch-all)
 */
object PathSegmentTailcardRouteSelector : RouteSelector

HTTP-Based Selectors

/**
 * Matches HTTP method
 */
data class HttpMethodRouteSelector(val method: HttpMethod) : RouteSelector

/**
 * Matches HTTP header value
 */
data class HttpHeaderRouteSelector(
    val name: String,
    val value: String
) : RouteSelector

/**
 * Matches Accept header content type
 */
data class HttpAcceptRouteSelector(val contentType: ContentType) : RouteSelector

Connection-Based Selectors

/**
 * Matches connection port
 */
data class LocalPortRouteSelector(val port: Int) : RouteSelector

/**
 * Matches host pattern (supports wildcards)
 */
class HostRouteSelector(val hostPattern: String) : RouteSelector

Route Selection Evaluation

Classes representing the result of route selector evaluation.

/**
 * Result of route selector evaluation
 */
sealed class RouteSelectorEvaluation(val succeeded: Boolean) {
    /**
     * Successful match with quality score and extracted parameters
     */
    data class Success(
        val quality: Double,
        val parameters: Parameters = Parameters.Empty,
        val segmentIncrement: Int = 0
    ) : RouteSelectorEvaluation(true)
    
    /**
     * Failed match with quality score and failure status
     */
    data class Failure(
        val quality: Double,
        val failureStatusCode: HttpStatusCode
    ) : RouteSelectorEvaluation(false)
    
    companion object {
        // Quality constants
        const val qualityConstant: Double = 1.0
        const val qualityQueryParameter: Double = 1.0
        const val qualityParameterWithPrefixOrSuffix: Double = 0.9
        const val qualityParameter: Double = 0.8
        const val qualityPathParameter: Double = qualityParameter
        const val qualityWildcard: Double = 0.5
        const val qualityMissing: Double = 0.2
        const val qualityTailcard: Double = 0.1
        const val qualityTransparent: Double = -1.0
        const val qualityFailedMethod: Double = 0.02
        const val qualityFailedParameter: Double = 0.01
        
        // Common evaluation results  
        val Failed: RouteSelectorEvaluation.Failure
        val FailedPath: RouteSelectorEvaluation.Failure
        val FailedMethod: RouteSelectorEvaluation.Failure
        val FailedParameter: RouteSelectorEvaluation.Failure
        val FailedAcceptHeader: RouteSelectorEvaluation.Failure
        val Missing: RouteSelectorEvaluation
        val Constant: RouteSelectorEvaluation
        val Transparent: RouteSelectorEvaluation
        val ConstantPath: RouteSelectorEvaluation
        val WildcardPath: RouteSelectorEvaluation
    }
}

Route Resolution

Classes for resolving routes and handling the resolution process.

/**
 * Context for route resolution process
 */
class RoutingResolveContext {
    /** Root routing node */
    val routing: RoutingNode
    
    /** Current application call */
    val call: RoutingApplicationCall
    
    /** List of resolution tracers for debugging */
    val tracers: List<(RoutingResolveTrace) -> Unit>
    
    /** Captured route parameters */
    val parameters: Parameters
    
    /** Request headers */
    val headers: Headers
}

/**
 * Result of route resolution
 */
data class RoutingResolveResult(
    /** Matched route */
    val route: RoutingNode,
    
    /** Captured parameters */
    val parameters: Parameters,
    
    /** Quality score of match */
    val quality: Double
)

Routing Installation

Function to install routing into an application.

/**
 * Install and configure routing for the application
 */
fun Application.routing(configuration: Routing.() -> Unit): Routing

Route Introspection

Extensions for examining and debugging route structures.

/** Get all descendant routes recursively */
val RoutingNode.allRoutes: List<RoutingNode>

/** Get all routes recursively with filtering */
fun RoutingNode.getAllRoutes(predicate: (RoutingNode) -> Boolean = { true }): List<RoutingNode>

/** Create route from path pattern */
fun createRouteFromPath(path: String): List<RouteSelector>

Usage Examples

Basic Routing Setup

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

fun Application.basicRouting() {
    routing {
        // Simple GET route
        get("/") {
            call.respondText("Hello, World!")
        }
        
        // Route with path parameter
        get("/users/{id}") {
            val id = call.parameters["id"]
            call.respondText("User ID: $id")
        }
        
        // Multiple HTTP methods
        route("/api/users") {
            get {
                call.respondText("Get all users")
            }
            
            post {
                call.respondText("Create user")
            }
            
            route("/{id}") {
                get {
                    val id = call.parameters["id"]
                    call.respondText("Get user $id")
                }
                
                put {
                    val id = call.parameters["id"]
                    call.respondText("Update user $id")
                }
                
                delete {
                    val id = call.parameters["id"]
                    call.respondText("Delete user $id")
                }
            }
        }
    }
}

Advanced Path Patterns

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

fun Application.advancedPatterns() {
    routing {
        // Optional parameter
        get("/users/{id?}") {
            val id = call.parameters["id"]
            if (id != null) {
                call.respondText("User ID: $id")
            } else {
                call.respondText("All users")
            }
        }
        
        // Parameter with prefix/suffix
        get("/files/{name}.{ext}") {
            val name = call.parameters["name"]
            val ext = call.parameters["ext"]
            call.respondText("File: $name.$ext")
        }
        
        // Wildcard segment
        get("/static/*") {
            val path = call.parameters.getAll("*")?.joinToString("/")
            call.respondText("Static file: $path")
        }
        
        // Tailcard (catch remaining segments)
        get("/docs/{...}") {
            val pathSegments = call.parameters.getAll("...")
            val docPath = pathSegments?.joinToString("/") ?: ""
            call.respondText("Documentation: $docPath")
        }
        
        // Multiple parameters
        get("/api/v{version}/users/{userId}/posts/{postId}") {
            val version = call.parameters["version"]
            val userId = call.parameters["userId"]
            val postId = call.parameters["postId"]
            call.respondText("API v$version: User $userId, Post $postId")
        }
    }
}

Conditional Routing

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

fun Application.conditionalRouting() {
    routing {
        // Route based on header
        route("/api") {
            header("X-API-Version", "2") {
                get("/users") {
                    call.respondText("API v2: Users")
                }
            }
            
            header("X-API-Version", "1") {
                get("/users") {
                    call.respondText("API v1: Users")
                }
            }
        }
        
        // Route based on Accept header
        route("/data") {
            accept(ContentType.Application.Json) {
                get {
                    call.respond(mapOf("data" to "json"))
                }
            }
            
            accept(ContentType.Application.Xml) {
                get {
                    call.respondText("<data>xml</data>", ContentType.Application.Xml)
                }
            }
        }
        
        // Route based on Content-Type
        route("/upload") {
            contentType(ContentType.Application.Json) {
                post {
                    call.respondText("JSON upload")
                }
            }
            
            contentType(ContentType.MultiPart.FormData) {
                post {
                    call.respondText("Multipart upload")
                }
            }
        }
        
        // Route based on host
        host("api.example.com") {
            get("/") {
                call.respondText("API subdomain")
            }
        }
        
        host("admin.example.com") {
            get("/") {
                call.respondText("Admin subdomain")
            }
        }
        
        // Route based on port
        port(8080) {
            get("/dev") {
                call.respondText("Development server")
            }
        }
        
        port(443) {
            get("/secure") {
                call.respondText("Secure connection")
            }
        }
    }
}

Nested Route Organization

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

fun Application.nestedRouting() {
    routing {
        // API versioning
        route("/api") {
            route("/v1") {
                route("/users") {
                    get {
                        call.respondText("V1: Get users")
                    }
                    
                    post {
                        call.respondText("V1: Create user")
                    }
                    
                    route("/{id}") {
                        get {
                            call.respondText("V1: Get user ${call.parameters["id"]}")
                        }
                        
                        route("/posts") {
                            get {
                                call.respondText("V1: Get user posts")
                            }
                        }
                    }
                }
            }
            
            route("/v2") {
                route("/users") {
                    get {
                        call.respondText("V2: Get users")
                    }
                    
                    route("/{id}") {
                        get {
                            call.respondText("V2: Get user ${call.parameters["id"]}")
                        }
                    }
                }
            }
        }
        
        // Admin section
        route("/admin") {
            // Apply authentication here
            route("/users") {
                get {
                    call.respondText("Admin: List users")
                }
                
                delete("/{id}") {
                    call.respondText("Admin: Delete user ${call.parameters["id"]}")
                }
            }
            
            route("/settings") {
                get {
                    call.respondText("Admin: Settings")
                }
                
                post {
                    call.respondText("Admin: Update settings")
                }
            }
        }
    }
}

Route Parameters and Query Strings

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

fun Application.parameterHandling() {
    routing {
        get("/search") {
            val query = call.request.queryParameters["q"] ?: ""
            val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1
            val limit = call.request.queryParameters["limit"]?.toIntOrNull() ?: 10
            val sort = call.request.queryParameters["sort"] ?: "relevance"
            
            call.respond(mapOf(
                "query" to query,
                "page" to page,
                "limit" to limit,
                "sort" to sort,
                "results" to emptyList<String>() // Mock results
            ))
        }
        
        get("/users/{id}/posts") {
            val userId = call.parameters["id"]
            val category = call.request.queryParameters["category"]
            val published = call.request.queryParameters["published"]?.toBoolean()
            
            val filters = mutableMapOf<String, Any>()
            if (category != null) filters["category"] = category
            if (published != null) filters["published"] = published
            
            call.respond(mapOf(
                "userId" to userId,
                "filters" to filters,
                "posts" to emptyList<String>()
            ))
        }
        
        // Multiple parameter validation
        get("/date/{year}/{month}/{day}") {
            val year = call.parameters["year"]?.toIntOrNull()
            val month = call.parameters["month"]?.toIntOrNull()
            val day = call.parameters["day"]?.toIntOrNull()
            
            if (year == null || month == null || day == null) {
                call.respond(HttpStatusCode.BadRequest, "Invalid date format")
                return@get
            }
            
            if (month !in 1..12 || day !in 1..31) {
                call.respond(HttpStatusCode.BadRequest, "Invalid date values")
                return@get
            }
            
            call.respondText("Date: $year-$month-$day")
        }
    }
}

Route Introspection and Debugging

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

fun Application.routeIntrospection() {
    routing {
        get("/debug/routes") {
            val rootRoute = this@routing
            val allRoutes = rootRoute.getAllRoutes()
            
            val routeInfo = allRoutes.map { route ->
                mapOf(
                    "selector" to route.selector.toString(),
                    "hasHandlers" to route.handlers.isNotEmpty(),
                    "childCount" to route.children.size
                )
            }
            
            call.respond(mapOf(
                "totalRoutes" to allRoutes.size,
                "routes" to routeInfo
            ))
        }
        
        // Route that shows current call information
        get("/debug/call") {
            call.respond(mapOf(
                "method" to call.request.httpMethod.value,
                "uri" to call.request.uri,
                "parameters" to call.parameters.toMap(),
                "headers" to call.request.headers.toMap()
            ))
        }
    }
}

Custom Route Selectors

import io.ktor.server.routing.*

// Custom selector that matches based on user agent
class UserAgentRouteSelector(private val userAgent: String) : RouteSelector() {
    override val quality: Double = 0.8
    
    override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation {
        val requestUserAgent = context.headers["User-Agent"]
        return if (requestUserAgent?.contains(userAgent, ignoreCase = true) == true) {
            RouteSelectorEvaluation.Constant(quality)
        } else {
            RouteSelectorEvaluation.Failed
        }
    }
    
    override fun toString(): String = "UserAgent($userAgent)"
}

// Extension function to use custom selector
fun Route.userAgent(userAgent: String, build: Route.() -> Unit): Route {
    val selector = UserAgentRouteSelector(userAgent)
    return createChild(selector).apply(build)
}

fun Application.customSelectors() {
    routing {
        userAgent("Mobile") {
            get("/") {
                call.respondText("Mobile version")
            }
        }
        
        userAgent("Desktop") {
            get("/") {
                call.respondText("Desktop version")
            }
        }
        
        // Default fallback
        get("/") {
            call.respondText("Standard version")
        }
    }
}

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