CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Ktor HTTP Client Core - a multiplatform asynchronous HTTP client library for Kotlin providing comprehensive HTTP request/response handling with plugin architecture.

Pending
Overview
Eval results
Files

response-handling.mddocs/

Response Handling

Comprehensive HTTP response processing including body extraction, status handling, streaming support, and type-safe response parsing.

Capabilities

Response Body Extraction

Extract response bodies in various formats with type safety and charset handling.

/**
 * Get response body as text with optional charset
 * @param charset Character encoding (default: UTF-8)
 * @returns Response body as String
 */
suspend fun HttpResponse.bodyAsText(charset: Charset = Charsets.UTF_8): String

/**
 * Get response body as ByteReadChannel for streaming
 * @returns ByteReadChannel for reading response data
 */
suspend fun HttpResponse.bodyAsChannel(): ByteReadChannel

/**
 * Get response body as ByteArray
 * @returns Complete response body as byte array
 */
suspend fun HttpResponse.readBytes(): ByteArray

/**
 * Get typed response body using content negotiation
 * @returns Deserialized response body of type T
 */
suspend inline fun <reified T> HttpResponse.body(): T

/**
 * Get typed response body with explicit TypeInfo
 * @param typeInfo Type information for deserialization
 * @returns Deserialized response body
 */
suspend fun <T> HttpResponse.body(typeInfo: TypeInfo): T

Usage Examples:

val client = HttpClient()

// Get response as text
val response = client.get("https://api.example.com/users")
val jsonText = response.bodyAsText()

// Get response as bytes
val imageResponse = client.get("https://example.com/image.jpg")
val imageBytes = imageResponse.readBytes()

// Get typed response (requires content negotiation plugin)
val usersResponse = client.get("https://api.example.com/users")
val users: List<User> = usersResponse.body()

// Streaming response
val largeFileResponse = client.get("https://example.com/largefile.zip")
val channel = largeFileResponse.bodyAsChannel()
while (!channel.isClosedForRead) {
    val chunk = channel.readBuffer()
    // Process chunk
}

HttpResponse Interface

Core response interface providing access to status, headers, and metadata.

/**
 * HTTP response representation
 */
interface HttpResponse {
    /** HTTP status code and message */
    val status: HttpStatusCode
    
    /** Response headers */
    val headers: Headers
    
    /** Associated HTTP call */
    val call: HttpClientCall
    
    /** HTTP protocol version */
    val version: HttpProtocolVersion
    
    /** Request timestamp */
    val requestTime: GMTDate
    
    /** Response timestamp */
    val responseTime: GMTDate
    
    /** Response content */
    val content: ByteReadChannel
}

/**
 * Default implementation of HttpResponse
 */
class DefaultHttpResponse(
    override val call: HttpClientCall,
    override val status: HttpStatusCode,
    override val version: HttpProtocolVersion,
    override val requestTime: GMTDate,
    override val responseTime: GMTDate,
    override val content: ByteReadChannel,
    override val headers: Headers
) : HttpResponse

Usage Examples:

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

// Check status
when (response.status.value) {
    in 200..299 -> println("Success: ${response.status}")
    in 400..499 -> println("Client error: ${response.status}")
    in 500..599 -> println("Server error: ${response.status}")
}

// Access headers
val contentType = response.headers["Content-Type"]
val contentLength = response.headers["Content-Length"]?.toLong()

// Check protocol version
if (response.version == HttpProtocolVersion.HTTP_2_0) {
    println("Using HTTP/2")
}

// Check timing
val duration = response.responseTime - response.requestTime
println("Request took ${duration}ms")

HttpStatement Class

Prepared HTTP statement for lazy execution and advanced response handling.

/**
 * Prepared HTTP statement ready for execution
 */
class HttpStatement {
    /** The prepared request builder */
    val builder: HttpRequestBuilder
    
    /** The client that will execute this statement */
    val client: HttpClient
    
    /**
     * Execute the statement and return the response
     * @returns HttpResponse
     */
    suspend fun execute(): HttpResponse
    
    /**
     * Execute the statement with custom response handling
     * @param block Response processing block
     * @returns Result of the processing block
     */
    suspend fun <T> execute(block: suspend (HttpResponse) -> T): T
}

Usage Examples:

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

// Execute multiple times
val response1 = statement.execute()
val response2 = statement.execute()

// Execute with custom handling
val userCount = statement.execute { response ->
    val users: List<User> = response.body()
    users.size
}

// Execute with resource management
val result = statement.execute { response ->
    response.bodyAsChannel().use { channel ->
        // Process streaming data
        var totalBytes = 0L
        while (!channel.isClosedForRead) {
            val buffer = channel.readBuffer()
            totalBytes += buffer.remaining
        }
        totalBytes
    }
}

Response Pipeline Processing

Access to response processing pipeline for advanced scenarios.

/**
 * Response processing pipeline
 */
class HttpResponsePipeline {
    /** Receive phase for initial response processing */
    val Receive: PipelinePhase
    
    /** Parse phase for content transformation */
    val Parse: PipelinePhase
    
    /** Transform phase for final processing */
    val Transform: PipelinePhase
    
    /**
     * Execute the pipeline with response data
     * @param context Pipeline context
     * @param subject Initial subject
     * @returns Processed result
     */
    suspend fun execute(context: HttpResponseContainer, subject: Any): Any
}

/**
 * Response container for pipeline processing
 */
data class HttpResponseContainer(
    val expectedType: TypeInfo,
    val response: HttpResponse
)

Content Type and Encoding

Functions for handling content types and character encodings.

/**
 * Get content type from response headers
 * @returns ContentType object or null
 */
fun HttpResponse.contentType(): ContentType?

/**
 * Get charset from content type header
 * @returns Charset object or default
 */
fun HttpResponse.charset(): Charset

/**
 * Check if response has specific content type
 * @param contentType Expected content type
 * @returns True if content type matches
 */
fun HttpResponse.contentType(contentType: ContentType): Boolean

Usage Examples:

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

// Check content type
val contentType = response.contentType()
when {
    contentType?.match(ContentType.Application.Json) == true -> {
        val jsonData = response.bodyAsText()
        // Process JSON
    }
    contentType?.match(ContentType.Text.Html) == true -> {
        val htmlContent = response.bodyAsText()
        // Process HTML
    }
    contentType?.match(ContentType.Application.OctetStream) == true -> {
        val binaryData = response.readBytes()
        // Process binary data
    }
}

// Handle charset
val charset = response.charset()
val text = response.bodyAsText(charset)

Response Validation

Response validation and error handling utilities.

/**
 * Check if response is successful (2xx status code)
 * @returns True if status code is 2xx
 */
fun HttpResponse.isSuccessful(): Boolean

/**
 * Throw exception if response is not successful
 * @throws ResponseException for non-2xx status codes
 */
suspend fun HttpResponse.ensureSuccess()

/**
 * Get response body as text only if successful, null otherwise
 * @returns Response body text or null
 */
suspend fun HttpResponse.bodyAsTextOrNull(): String?

Usage Examples:

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

// Check success
if (response.isSuccessful()) {
    val data = response.bodyAsText()
    // Process successful response
} else {
    println("Request failed with status: ${response.status}")
}

// Ensure success (throws exception if not successful)
try {
    response.ensureSuccess()
    val data = response.bodyAsText()
} catch (e: ResponseException) {
    println("Request failed: ${e.message}")
}

// Safe body extraction
val safeData = response.bodyAsTextOrNull()
if (safeData != null) {
    // Process data
}

Types

Response Types

/**
 * HTTP status code representation
 */
data class HttpStatusCode(
    val value: Int,
    val description: String
) {
    companion object {
        // 2xx Success
        val OK: HttpStatusCode
        val Created: HttpStatusCode
        val Accepted: HttpStatusCode
        val NoContent: HttpStatusCode
        
        // 3xx Redirection
        val MovedPermanently: HttpStatusCode
        val Found: HttpStatusCode
        val NotModified: HttpStatusCode
        
        // 4xx Client Error
        val BadRequest: HttpStatusCode
        val Unauthorized: HttpStatusCode
        val Forbidden: HttpStatusCode
        val NotFound: HttpStatusCode
        
        // 5xx Server Error
        val InternalServerError: HttpStatusCode
        val BadGateway: HttpStatusCode
        val ServiceUnavailable: HttpStatusCode
    }
}

/**
 * HTTP protocol version
 */
enum class HttpProtocolVersion(val name: String, val major: Int, val minor: Int) {
    HTTP_1_0("HTTP/1.0", 1, 0),
    HTTP_1_1("HTTP/1.1", 1, 1),
    HTTP_2_0("HTTP/2.0", 2, 0),
    SPDY_3("SPDY/3.1", 3, 1),
    QUIC("QUIC", 1, 0)
}

/**
 * GMT date representation for timestamps
 */
data class GMTDate(
    val timestamp: Long,
    val seconds: Int,
    val minutes: Int,
    val hours: Int,
    val dayOfMonth: Int,
    val month: Month,
    val year: Int,
    val dayOfWeek: DayOfWeek,
    val dayOfYear: Int
) {
    companion object {
        fun start(): GMTDate
        fun parse(date: String): GMTDate
    }
}

Content Types

/**
 * Content type representation
 */
data class ContentType(
    val contentType: String,
    val contentSubtype: String,
    val parameters: List<HeaderValueParam> = emptyList()
) {
    companion object {
        object Application {
            val Json: ContentType
            val Xml: ContentType
            val OctetStream: ContentType
            val FormUrlEncoded: ContentType
            val Pdf: ContentType
        }
        
        object Text {
            val Plain: ContentType
            val Html: ContentType
            val CSS: ContentType
            val JavaScript: ContentType
        }
        
        object Image {
            val JPEG: ContentType
            val PNG: ContentType
            val GIF: ContentType
            val SVG: ContentType
        }
        
        object Audio {
            val MPEG: ContentType
            val OGG: ContentType
        }
        
        object Video {
            val MPEG: ContentType
            val MP4: ContentType
        }
    }
    
    fun match(pattern: ContentType): Boolean
    fun match(contentType: String): Boolean
    fun withParameter(name: String, value: String): ContentType
}

/**
 * Character set enumeration
 */
object Charsets {
    val UTF_8: Charset
    val UTF_16: Charset
    val ISO_8859_1: Charset
    val US_ASCII: Charset
}

Exception Types

/**
 * Base exception for HTTP response errors
 */
open class ResponseException(
    response: HttpResponse,
    cachedResponseText: String
) : Exception(cachedResponseText) {
    val response: HttpResponse
}

/**
 * Exception for client errors (4xx status codes)
 */
class ClientRequestException(
    response: HttpResponse,
    cachedResponseText: String
) : ResponseException(response, cachedResponseText)

/**
 * Exception for server errors (5xx status codes)
 */
class ServerResponseException(
    response: HttpResponse,
    cachedResponseText: String
) : ResponseException(response, cachedResponseText)

/**
 * Exception for redirect errors
 */
class RedirectResponseException(
    response: HttpResponse,
    cachedResponseText: String
) : ResponseException(response, cachedResponseText)

Install with Tessl CLI

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

docs

client-configuration.md

cookie-management.md

forms-and-uploads.md

http-caching.md

http-requests.md

index.md

plugin-system.md

response-handling.md

server-sent-events.md

websockets.md

tile.json