Ktor server core module for iOS ARM64 target providing essential server-side functionality for building asynchronous web applications and microservices in Kotlin Multiplatform
—
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.
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 : ApplicationRequestInterfaces 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?
}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>
}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
}
}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: RequestConnectionPointExtension 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(): InputStreamCore 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 : ApplicationResponseInterface 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
}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)
}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
}
}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: RequestConnectionPointExtension 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?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
)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())
}
}
}
}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)
}
}
}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)
}
}
}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")
}
}
}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 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