Ktor server core module for iOS ARM64 target providing essential server-side functionality for building asynchronous web applications and microservices in Kotlin Multiplatform
—
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.
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 : RoutingNodeDSL 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)
}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): RouteClasses that define how routes are matched against incoming requests.
/**
* 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
}/**
* 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/**
* 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/**
* Matches connection port
*/
data class LocalPortRouteSelector(val port: Int) : RouteSelector
/**
* Matches host pattern (supports wildcards)
*/
class HostRouteSelector(val hostPattern: String) : RouteSelectorClasses 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
}
}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
)Function to install routing into an application.
/**
* Install and configure routing for the application
*/
fun Application.routing(configuration: Routing.() -> Unit): RoutingExtensions 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>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")
}
}
}
}
}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")
}
}
}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")
}
}
}
}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")
}
}
}
}
}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")
}
}
}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()
))
}
}
}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