CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-ktor--ktor-client-core-tvosarm64

Ktor HTTP Client Core for tvOS ARM64 - multiplatform asynchronous HTTP client library with coroutines support

Pending
Overview
Eval results
Files

response-handling.mddocs/

Response Handling

The response handling API provides comprehensive functionality for accessing response data, headers, status information, and converting response bodies to various types with streaming support.

Core Types

abstract class HttpResponse : HttpMessage, CoroutineScope {
    public abstract val call: HttpClientCall
    public abstract val status: HttpStatusCode
    public abstract val version: HttpProtocolVersion
    public abstract val requestTime: GMTDate
    public abstract val responseTime: GMTDate
    
    override fun toString(): String
}

class HttpStatement(
    private val builder: HttpRequestBuilder,
    internal val client: HttpClient
) {
    suspend fun execute(): HttpResponse
    suspend fun <T> execute(block: suspend (response: HttpResponse) -> T): T
    suspend inline fun <reified T> body(): T
}

// Extension properties and functions for HttpResponse
val HttpResponse.request: HttpRequest

// Response body reading extensions
suspend fun HttpResponse.bodyAsText(fallbackCharset: Charset = Charsets.UTF_8): String
suspend fun HttpResponse.bodyAsChannel(): ByteReadChannel
suspend fun HttpResponse.bodyAsBytes(): ByteArray

Response Properties

Status Information

val response = client.get("https://api.example.com/users")

println("Status: ${response.status}")           // Status: 200 OK
println("Status code: ${response.status.value}") // Status code: 200
println("Status description: ${response.status.description}") // Status description: OK

// Status checks
if (response.status.isSuccess()) {
    println("Request succeeded")
}

when (response.status.value) {
    200 -> println("OK")
    404 -> println("Not Found")
    500 -> println("Server Error")
}

Headers Access

val response = client.get("https://api.example.com/users")

// Individual headers
val contentType = response.headers["Content-Type"]
val contentLength = response.headers["Content-Length"]?.toLongOrNull()
val server = response.headers["Server"]

// All headers
response.headers.forEach { name, values ->
    println("$name: ${values.joinToString(", ")}")
}

// Typed header access
val etag = response.headers[HttpHeaders.ETag]
val lastModified = response.headers[HttpHeaders.LastModified]

Timing Information

val response = client.get("https://api.example.com/users")

println("Request time: ${response.requestTime}")
println("Response time: ${response.responseTime}")

val duration = response.responseTime.timestamp - response.requestTime.timestamp
println("Request took: ${duration}ms")

Protocol Information

val response = client.get("https://api.example.com/users")

println("HTTP version: ${response.version}")  // HTTP/1.1, HTTP/2.0, etc.

Reading Response Body

Text Content

suspend fun HttpResponse.bodyAsText(
    charset: Charset = Charsets.UTF_8
): String

suspend fun HttpResponse.bodyAsText(
    fallbackCharset: Charset = Charsets.UTF_8
): String
val response = client.get("https://api.example.com/users")
val text = response.bodyAsText()
println(text)

// With specific charset
val textUtf8 = response.bodyAsText(Charsets.UTF_8)

Binary Content

suspend fun HttpResponse.bodyAsBytes(): ByteArray
val response = client.get("https://api.example.com/image.jpg")
val bytes = response.bodyAsBytes()
File("downloaded-image.jpg").writeBytes(bytes)

Channel Content

fun HttpResponse.bodyAsChannel(): ByteReadChannel
val response = client.get("https://api.example.com/large-file")
val channel = response.bodyAsChannel()

// Stream processing
while (!channel.isClosedForRead) {
    val packet = channel.readRemaining(8192)
    // Process packet
}

Deserialized Content

With appropriate serialization plugins (like kotlinx.serialization):

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

val response = client.get("https://api.example.com/users/123")
val user = response.body<User>()
println("User: ${user.name}")

Response Streaming

Streaming Large Responses

val response = client.get("https://api.example.com/large-dataset")
val channel = response.bodyAsChannel()

val outputFile = File("dataset.json")
outputFile.outputStream().use { output ->
    while (!channel.isClosedForRead) {
        val packet = channel.readRemaining(8192)
        output.write(packet.readBytes())
    }
}

Progress Monitoring

With the BodyProgress plugin:

client.get("https://api.example.com/large-file") {
    onDownload { bytesSentTotal, contentLength ->
        val progress = (bytesSentTotal * 100 / contentLength).toInt()
        println("Download progress: $progress%")
    }
}.bodyAsBytes()

Statement Execution

Basic Statement Execution

val statement = client.prepareGet("https://api.example.com/users")
val response = statement.execute()
val text = response.bodyAsText()

Statement with Response Processing

val statement = client.prepareGet("https://api.example.com/users")

val users = statement.execute { response ->
    if (response.status.isSuccess()) {
        response.bodyAsText()
    } else {
        throw RuntimeException("Request failed: ${response.status}")
    }
}

Reusable Statements

val userStatement = client.prepareGet {
    url("https://api.example.com/users")
    header("Authorization", "Bearer $token")
}

// Use multiple times
val page1 = userStatement.execute {
    parameter("page", 1)
    bodyAsText()
}

val page2 = userStatement.execute {
    parameter("page", 2)
    bodyAsText()
}

Error Response Handling

Status Code Checking

val response = client.get("https://api.example.com/users/999")

when {
    response.status.isSuccess() -> {
        val user = response.bodyAsText()
        println("User: $user")
    }
    response.status.value == 404 -> {
        println("User not found")
    }
    response.status.value in 400..499 -> {
        val errorBody = response.bodyAsText()
        println("Client error: $errorBody")
    }
    response.status.value in 500..599 -> {
        println("Server error: ${response.status}")
    }
}

Exception Handling with Call Validator

client.get("https://api.example.com/users") {
    // With HttpCallValidator plugin, non-success responses throw exceptions
}

Response Validation

Content Type Validation

val response = client.get("https://api.example.com/users")
val contentType = response.headers[HttpHeaders.ContentType]

if (contentType?.startsWith("application/json") == true) {
    val json = response.bodyAsText()
    // Process JSON
} else {
    println("Unexpected content type: $contentType")
}

Content Length Validation

val response = client.get("https://api.example.com/file")
val contentLength = response.headers[HttpHeaders.ContentLength]?.toLongOrNull()
val actualBytes = response.bodyAsBytes()

if (contentLength != null && actualBytes.size.toLong() != contentLength) {
    println("Content length mismatch!")
}

Response Caching

Cache Headers

val response = client.get("https://api.example.com/users")

val cacheControl = response.headers[HttpHeaders.CacheControl]
val etag = response.headers[HttpHeaders.ETag]
val expires = response.headers[HttpHeaders.Expires]
val lastModified = response.headers[HttpHeaders.LastModified]

println("Cache Control: $cacheControl")
println("ETag: $etag")

Conditional Requests

// Using If-None-Match with ETag
val etag = "W/\"abc123\""
val response = client.get("https://api.example.com/users") {
    header(HttpHeaders.IfNoneMatch, etag)
}

if (response.status.value == 304) {
    println("Content not modified")
} else {
    val newContent = response.bodyAsText()
    val newEtag = response.headers[HttpHeaders.ETag]
}

Response Context

Coroutine Context

val response = client.get("https://api.example.com/users")

// Access coroutine context
val job = response.coroutineContext[Job]
val dispatcher = response.coroutineContext[CoroutineDispatcher]

// Use response as coroutine scope
response.launch {
    // Background processing of response
}

Call Information

val response = client.get("https://api.example.com/users")

println("Request URL: ${response.call.request.url}")
println("Request method: ${response.call.request.method}")
println("Response status: ${response.call.response.status}")

Install with Tessl CLI

npx tessl i tessl/maven-io-ktor--ktor-client-core-tvosarm64

docs

builtin-plugins.md

caching.md

cookies.md

engine-configuration.md

forms.md

http-client.md

index.md

plugin-system.md

request-building.md

response-handling.md

response-observation.md

utilities.md

websockets.md

tile.json