Ktor HTTP Client Core - a multiplatform asynchronous HTTP client library for Kotlin providing comprehensive HTTP request/response handling with plugin architecture.
—
Comprehensive HTTP response processing including body extraction, status handling, streaming support, and type-safe response parsing.
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): TUsage 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
}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
) : HttpResponseUsage 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")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
}
}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
)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): BooleanUsage 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 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
}/**
* 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 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
}/**
* 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