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

request-response.mddocs/

Request and Response Handling

Comprehensive request parsing and response building capabilities with content transformation pipelines. Provides full access to HTTP request data and flexible response generation with content negotiation support.

Capabilities

Application Request Interface

Core interface for accessing incoming HTTP request data and metadata.

/**
 * Represents client request with all HTTP data and metadata
 */
interface ApplicationRequest {
    /** The call this request belongs to */
    val call: ApplicationCall
    
    /** Pipeline for processing request content */
    val pipeline: ApplicationReceivePipeline
    
    /** Query string parameters */
    val queryParameters: Parameters
    
    /** HTTP request headers */
    val headers: Headers
    
    /** Local connection information */
    val local: RequestConnectionPoint
    
    /** Request cookies accessor */
    val cookies: RequestCookies
}

/**
 * Pipeline-specific request implementation
 */
interface PipelineRequest : ApplicationRequest

Request Connection Information

Interfaces for accessing connection and HTTP protocol information.

/**
 * Connection information for incoming request
 */
interface RequestConnectionPoint {
    /** URI scheme (http, https) */
    val scheme: String
    
    /** HTTP protocol version */
    val version: String
    
    /** Local port number */
    val port: Int
    
    /** Host name from Host header */
    val host: String
    
    /** Full request URI */
    val uri: String
    
    /** HTTP method */
    val method: HttpMethod
    
    /** Remote client host address */
    val remoteHost: String
    
    /** User-Agent header value */
    val userAgent: String?
}

Request Cookies

Interface for accessing HTTP cookies from the request.

/**
 * Request cookies accessor
 */
interface RequestCookies {
    /** Get cookie value by name */
    operator fun get(name: String): String?
    
    /** Get all cookies as a map */
    fun getAll(): Map<String, String>
}

Request Content Pipeline

Pipeline system for processing and transforming incoming request content.

/**
 * Pipeline for processing incoming request content
 */
open class ApplicationReceivePipeline : Pipeline<Any, PipelineCall> {
    companion object {
        /** Phase for pre-processing before transformation */
        val Before: PipelinePhase
        
        /** Phase for content transformation */
        val Transform: PipelinePhase
        
        /** Phase for post-processing after transformation */
        val After: PipelinePhase
    }
}

Request Extension Properties

Extension properties providing convenient access to common request data.

/** Full request URI */
val ApplicationRequest.uri: String

/** HTTP protocol version */
val ApplicationRequest.httpVersion: String

/** HTTP method */
val ApplicationRequest.httpMethod: HttpMethod

/** Request path without query parameters */
val ApplicationRequest.path: String

/** Document name from path */
val ApplicationRequest.document: String

/** Host header value */
val ApplicationRequest.host: String

/** Port number */
val ApplicationRequest.port: Int

/** User-Agent header */
val ApplicationRequest.userAgent: String?

/** Accept header */
val ApplicationRequest.accept: String?

/** Accept-Language header */
val ApplicationRequest.acceptLanguage: String?

/** Accept-Encoding header */
val ApplicationRequest.acceptEncoding: String?

/** Content-Type header parsed */
val ApplicationRequest.contentType: ContentType

/** Content-Length header */
val ApplicationRequest.contentLength: Long?

/** Authorization header */
val ApplicationRequest.authorization: String?

/** Cache-Control header */
val ApplicationRequest.cacheControl: String?

/** Whether request is multipart */
val ApplicationRequest.isMultipart: Boolean

/** Whether request is URL encoded */
val ApplicationRequest.isUrlEncoded: Boolean

/** Origin connection point */
val ApplicationRequest.origin: RequestConnectionPoint

Request Receive Functions

Extension functions for receiving and parsing request content with type safety.

/**
 * Receive request body converted to specified type
 */
suspend inline fun <reified T> ApplicationCall.receive(): T

/**
 * Receive request body converted to specified type or null if conversion fails
 */
suspend inline fun <reified T> ApplicationCall.receiveOrNull(): T?

/**
 * Receive request body with explicit type information
 */
suspend fun <T> ApplicationCall.receiveNullable(typeInfo: TypeInfo): T?

/**
 * Receive request body as plain text
 */
suspend fun ApplicationCall.receiveText(): String

/**
 * Receive form parameters from URL-encoded or multipart request
 */
suspend fun ApplicationCall.receiveParameters(): Parameters

/**
 * Receive multipart data for file uploads and complex forms
 */
suspend fun ApplicationCall.receiveMultipart(): MultiPartData

/**
 * Receive request body as byte array
 */
suspend fun ApplicationCall.receiveBytes(): ByteArray

/**
 * Receive request body as input stream
 */
suspend fun ApplicationCall.receiveStream(): InputStream

Application Response Interface

Core interface for building and sending HTTP responses.

/**
 * Represents server response being built and sent to client
 */
interface ApplicationResponse {
    /** The call this response belongs to */
    val call: ApplicationCall
    
    /** Pipeline for processing response content */
    val pipeline: ApplicationSendPipeline
    
    /** Response headers accessor */
    val headers: ResponseHeaders
    
    /** Response cookies accessor */
    val cookies: ResponseCookies
    
    /** Get current response status code */
    fun status(): HttpStatusCode?
    
    /** Set response status code */
    fun status(value: HttpStatusCode)
}

/**
 * Pipeline-specific response implementation
 */
interface PipelineResponse : ApplicationResponse

Response Headers Management

Interface for managing HTTP response headers.

/**
 * Response headers accessor with modification capabilities
 */
interface ResponseHeaders {
    /** Get header value by name */
    operator fun get(name: String): String?
    
    /** Get all values for header name */
    fun getAll(name: String): List<String>?
    
    /** Check if header exists */
    fun contains(name: String): Boolean
    
    /** Add header value (allows multiple values) */
    fun append(name: String, value: String)
    
    /** Add header value only if name doesn't exist */
    fun appendIfNameAbsent(name: String, value: String): Boolean
}

Response Cookies Management

Interface for managing HTTP response cookies.

/**
 * Response cookies accessor for setting cookies
 */
interface ResponseCookies {
    /** Get cookie configuration by name */
    operator fun get(name: String): Cookie?
    
    /** Add cookie to response */
    fun append(cookie: Cookie)
    
    /** Add expired cookie to delete client-side cookie */
    fun appendExpired(name: String, domain: String? = null, path: String? = null)
}

Response Content Pipeline

Pipeline system for processing and transforming outgoing response content.

/**
 * Pipeline for processing outgoing response content
 */
open class ApplicationSendPipeline : Pipeline<Any, PipelineCall> {
    companion object {
        /** Phase for pre-processing before transformation */
        val Before: PipelinePhase
        
        /** Phase for content transformation */
        val Transform: PipelinePhase
        
        /** Phase for post-processing after transformation */
        val After: PipelinePhase
        
        /** Phase for engine-specific processing */
        val Engine: PipelinePhase
    }
}

Request Extension Properties

Extension properties for convenient request data access.

/** Get request URI */
val ApplicationRequest.uri: String

/** Get HTTP method */
val ApplicationRequest.httpMethod: HttpMethod

/** Get request path */
val ApplicationRequest.path: String

/** Get request host */
val ApplicationRequest.host: String

/** Get request port */
val ApplicationRequest.port: Int

/** Get Content-Type header */
val ApplicationRequest.contentType: ContentType

/** Get User-Agent header */
val ApplicationRequest.userAgent: String?

/** Get request origin information */
val ApplicationRequest.origin: RequestConnectionPoint

Response Extension Properties

Extension properties for convenient response header management.

/** Get or set Content-Type header */
var ApplicationResponse.contentType: ContentType?

/** Get or set Content-Length header */
var ApplicationResponse.contentLength: Long?

/** Get or set Cache-Control header */  
var ApplicationResponse.cacheControl: CacheControl?

/** Get or set ETag header */
var ApplicationResponse.etag: String?

/** Get or set Last-Modified header */ 
var ApplicationResponse.lastModified: ZonedDateTime?

Response Send Functions

Extension functions for sending various types of response content.

/**
 * Send response content with automatic type handling
 */
suspend fun ApplicationCall.respond(message: Any)

/**
 * Send response with specific status code
 */
suspend fun ApplicationCall.respond(status: HttpStatusCode, message: Any)

/**
 * Send plain text response
 */
suspend fun ApplicationCall.respondText(
    text: String,
    contentType: ContentType? = null,
    status: HttpStatusCode? = null
)

/**
 * Send byte array response
 */
suspend fun ApplicationCall.respondBytes(
    bytes: ByteArray,
    contentType: ContentType? = null,
    status: HttpStatusCode? = null
)

/**
 * Send file response with optional content type detection
 */
suspend fun ApplicationCall.respondFile(
    file: File,
    contentType: ContentType? = null
)

/**
 * Send redirect response
 */
suspend fun ApplicationCall.respondRedirect(
    url: String,
    permanent: Boolean = false
)

/**
 * Send redirect response with status code
 */
suspend fun ApplicationCall.respondRedirect(
    url: String,
    status: HttpStatusCode
)

/**
 * Send streaming response from input stream
 */
suspend fun ApplicationCall.respondOutputStream(
    contentType: ContentType? = null,
    status: HttpStatusCode? = null,
    producer: suspend OutputStream.() -> Unit
)

/**
 * Send streaming response from writer
 */
suspend fun ApplicationCall.respondTextWriter(
    contentType: ContentType? = null,
    status: HttpStatusCode? = null,
    producer: suspend Writer.() -> Unit
)

Usage Examples

Request Data Access

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

fun Application.requestHandling() {
    routing {
        get("/request-info") {
            val request = call.request
            
            val info = mapOf(
                "method" to request.httpMethod.value,
                "uri" to request.uri,
                "path" to request.path,
                "host" to request.host,
                "port" to request.port,
                "userAgent" to request.userAgent,
                "contentType" to request.contentType.toString(),
                "accept" to request.accept,
                "headers" to request.headers.toMap(),
                "queryParams" to request.queryParameters.toMap(),
                "cookies" to request.cookies.getAll()
            )
            
            call.respond(info)
        }
        
        get("/users/{id}") {
            val userId = call.parameters["id"]
            val includeDetails = call.request.queryParameters["details"]?.toBoolean() ?: false
            
            val user = getUserById(userId)
            if (includeDetails) {
                call.respond(user.withDetails())
            } else {
                call.respond(user.summary())
            }
        }
    }
}

Request Content Handling

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

fun Application.contentHandling() {
    routing {
        // Receive JSON data
        post("/users") {
            try {
                val user = call.receive<User>()
                val savedUser = userService.createUser(user)
                call.respond(HttpStatusCode.Created, savedUser)
            } catch (e: ContentTransformationException) {
                call.respond(HttpStatusCode.BadRequest, "Invalid user data")
            }
        }
        
        // Receive form data
        post("/form") {
            val formParameters = call.receiveParameters()
            val name = formParameters["name"] ?: return@post call.respond(HttpStatusCode.BadRequest)
            val email = formParameters["email"] ?: return@post call.respond(HttpStatusCode.BadRequest)
            
            call.respond("Hello $name, your email is $email")
        }
        
        // Receive multipart data (file upload)
        post("/upload") {
            val multipart = call.receiveMultipart()
            var fileName: String? = null
            var fileBytes: ByteArray? = null
            
            multipart.forEachPart { part ->
                when (part) {
                    is PartData.FormItem -> {
                        if (part.name == "description") {
                            // Handle form field
                        }
                    }
                    is PartData.FileItem -> {
                        fileName = part.originalFileName
                        fileBytes = part.streamProvider().readBytes()
                    }
                    is PartData.BinaryItem -> {
                        // Handle binary data
                    }
                }
                part.dispose()
            }
            
            if (fileName != null && fileBytes != null) {
                // Save file
                call.respond("File $fileName uploaded successfully")
            } else {
                call.respond(HttpStatusCode.BadRequest, "No file provided")
            }
        }
        
        // Receive raw text
        put("/data/{id}") {
            val id = call.parameters["id"]
            val textData = call.receiveText()
            
            dataService.updateData(id, textData)
            call.respond(HttpStatusCode.OK)
        }
    }
}

Response Building

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

fun Application.responseHandling() {
    routing {
        // JSON response
        get("/api/users/{id}") {
            val userId = call.parameters["id"]
            val user = userService.findById(userId)
            
            if (user != null) {
                call.respond(user)
            } else {
                call.respond(HttpStatusCode.NotFound, "User not found")
            }
        }
        
        // Custom headers and status
        get("/api/data") {
            val data = dataService.getData()
            
            call.response.headers.append("X-Data-Version", "1.0")
            call.response.headers.append("X-Total-Count", data.size.toString())
            call.response.cacheControl = CacheControl.MaxAge(maxAgeSeconds = 300)
            
            call.respond(HttpStatusCode.OK, data)
        }
        
        // File response
        get("/files/{filename}") {
            val filename = call.parameters["filename"]
            val file = File("uploads/$filename")
            
            if (file.exists() && file.isFile) {
                call.respondFile(file)
            } else {
                call.respond(HttpStatusCode.NotFound)
            }
        }
        
        // Streaming response
        get("/large-data") {
            call.respondTextWriter(ContentType.Text.Plain) {
                for (i in 1..1000000) {
                    write("Line $i\n")
                    if (i % 1000 == 0) {
                        flush() // Flush periodically for streaming
                    }
                }
            }
        }
        
        // Binary response
        get("/image/{id}") {
            val imageId = call.parameters["id"]
            val imageData = imageService.getImageBytes(imageId)
            
            if (imageData != null) {
                call.respondBytes(
                    bytes = imageData,
                    contentType = ContentType.Image.PNG
                )
            } else {
                call.respond(HttpStatusCode.NotFound)
            }
        }
        
        // Redirect response
        get("/old-api/{path...}") {
            val path = call.parameters.getAll("path")?.joinToString("/") ?: ""
            call.respondRedirect("/api/v2/$path", permanent = true)
        }
    }
}

Cookie Management

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

fun Application.cookieHandling() {
    routing {
        get("/set-cookie") {
            // Set simple cookie
            call.response.cookies.append("session_id", "abc123")
            
            // Set cookie with options
            call.response.cookies.append(Cookie(
                name = "user_pref",
                value = "dark_mode",
                maxAge = 86400, // 24 hours
                domain = ".example.com",
                path = "/",
                secure = true,
                httpOnly = true,
                extensions = mapOf("SameSite" to "Strict")
            ))
            
            call.respond("Cookies set")
        }
        
        get("/get-cookies") {
            val sessionId = call.request.cookies["session_id"]
            val userPref = call.request.cookies["user_pref"]
            val allCookies = call.request.cookies.getAll()
            
            call.respond(mapOf(
                "sessionId" to sessionId,
                "userPref" to userPref,
                "allCookies" to allCookies
            ))
        }
        
        post("/logout") {
            // Delete cookies by setting expired ones
            call.response.cookies.appendExpired("session_id")
            call.response.cookies.appendExpired("user_pref", domain = ".example.com", path = "/")
            
            call.respond("Logged out")
        }
    }
}

Content Negotiation and Type Conversion

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

data class User(val id: Int, val name: String, val email: String)
data class CreateUserRequest(val name: String, val email: String)

fun Application.contentNegotiation() {
    routing {
        // Accept both JSON and XML
        post("/users") {
            val contentType = call.request.contentType
            
            when {
                contentType.match(ContentType.Application.Json) -> {
                    val request = call.receive<CreateUserRequest>()
                    val user = userService.create(request)
                    call.respond(user)
                }
                contentType.match(ContentType.Application.Xml) -> {
                    val xmlData = call.receiveText()
                    val user = parseUserFromXml(xmlData)
                    call.respond(user)
                }
                else -> {
                    call.respond(HttpStatusCode.UnsupportedMediaType)
                }
            }
        }
        
        // Content negotiation for response format
        get("/users/{id}") {
            val userId = call.parameters["id"]?.toInt()
            val user = userService.findById(userId)
            
            if (user == null) {
                call.respond(HttpStatusCode.NotFound)
                return@get
            }
            
            val acceptHeader = call.request.accept
            when {
                acceptHeader?.contains("application/json") == true -> {
                    call.respond(user)
                }
                acceptHeader?.contains("text/xml") == true -> {
                    call.respondText(
                        user.toXml(),
                        ContentType.Text.Xml
                    )
                }
                acceptHeader?.contains("text/plain") == true -> {
                    call.respondText("User: ${user.name} (${user.email})")
                }
                else -> {
                    call.respond(user) // Default to JSON
                }
            }
        }
    }
}

Exception Classes

Exception types related to request/response processing and content transformation.

/**
 * Base exception for bad request scenarios
 */
open class BadRequestException(message: String, cause: Throwable? = null) : Exception(message, cause)

/**
 * Thrown when a required request parameter is missing
 */
class MissingRequestParameterException(val parameterName: String) : BadRequestException(
    "Request parameter '$parameterName' is missing"
)

/**
 * Thrown when parameter conversion fails
 */
class ParameterConversionException(
    val parameterName: String,
    val type: String,
    cause: Throwable? = null
) : BadRequestException("Cannot convert parameter '$parameterName' to $type", cause)

/**
 * Thrown when a resource is not found
 */
class NotFoundException(message: String? = "Resource not found") : Exception(message)

/**
 * Base exception for content transformation failures
 */
abstract class ContentTransformationException(message: String) : IOException(message)

/**
 * Thrown when content cannot be transformed to the requested type
 */
class CannotTransformContentToTypeException(private val type: KType) : ContentTransformationException(
    "Cannot transform content to $type"
)

/**
 * Thrown when the request content type is not supported
 */
class UnsupportedMediaTypeException(private val contentType: ContentType?) : ContentTransformationException(
    "Content type $contentType is not supported"
)

/**
 * Thrown when request payload exceeds size limits
 */
class PayloadTooLargeException(private val sizeLimit: Long) : ContentTransformationException(
    "Request payload size exceeds limit of $sizeLimit bytes"
)

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