Ktor HTTP Client Core for tvOS ARM64 - multiplatform asynchronous HTTP client library with coroutines support
—
The Ktor HTTP Client Core comes with a comprehensive set of built-in plugins that provide essential functionality for HTTP client operations. These plugins handle common cross-cutting concerns like redirects, retries, timeouts, response validation, and more.
Automatic HTTP redirect handling plugin that follows redirect responses according to HTTP specifications.
object HttpRedirect : HttpClientPlugin<HttpRedirect.Config, HttpRedirect> {
class Config {
var checkHttpMethod: Boolean = true
var allowHttpsDowngrade: Boolean = false
var maxJumps: Int = 20
fun checkHttpMethod(block: (HttpMethod) -> Boolean)
fun allowHttpsDowngrade(allow: Boolean)
}
}Usage Example:
val client = HttpClient {
install(HttpRedirect) {
checkHttpMethod = true
allowHttpsDowngrade = false
maxJumps = 10
}
}
// Automatically follows redirects
val response = client.get("https://httpbin.org/redirect/3")Request retry logic plugin that automatically retries failed requests based on configurable conditions.
object HttpRequestRetry : HttpClientPlugin<HttpRequestRetry.Config, HttpRequestRetry> {
class Config {
var maxRetries: Int = 3
var retryOnExceptionOrServerErrors: Boolean = true
var delayMillis: (retry: Int) -> Long = { retry -> retry * 1000L }
var modifyRequest: suspend HttpRequestBuilder.(retry: Int) -> Unit = {}
fun retryOnException(retries: Int = 3, block: suspend RetryEventData.() -> Boolean = { true })
fun retryOnServerErrors(maxRetries: Int = 3)
fun retryIf(block: suspend RetryEventData.(HttpResponse) -> Boolean)
fun exponentialDelay(base: Double = 2.0, maxDelayMs: Long = 60000)
fun constantDelay(delayMs: Long = 1000)
fun linearDelay(delayMs: Long = 1000)
}
class RetryEventData(
val executionCount: Int,
val request: HttpRequestBuilder,
val response: HttpResponse?,
val cause: Throwable?
)
}Usage Example:
val client = HttpClient {
install(HttpRequestRetry) {
retryOnServerErrors(maxRetries = 3)
exponentialDelay()
retryIf { request, response ->
response.status.value >= 500
}
modifyRequest { retry ->
header("X-Retry-Count", retry.toString())
}
}
}
// Automatically retries on failures
val response = client.get("https://unstable-api.example.com/data")Request timeout handling plugin for configuring connection, request, and socket timeouts.
object HttpTimeout : HttpClientPlugin<HttpTimeout.Config, HttpTimeout> {
class Config {
var requestTimeoutMillis: Long? = null
var connectTimeoutMillis: Long? = null
var socketTimeoutMillis: Long? = null
}
}Usage Example:
val client = HttpClient {
install(HttpTimeout) {
requestTimeoutMillis = 30000
connectTimeoutMillis = 5000
socketTimeoutMillis = 10000
}
}
// Per-request timeout override
val response = client.get("https://slow-api.example.com/data") {
timeout {
requestTimeoutMillis = 60000
}
}User agent header plugin for setting a consistent User-Agent header across all requests.
object UserAgent : HttpClientPlugin<UserAgent.Config, UserAgent> {
class Config {
var agent: String = "Ktor HTTP Client"
}
}Usage Example:
val client = HttpClient {
install(UserAgent) {
agent = "MyApp/1.0 (https://example.com)"
}
}
// All requests will include the User-Agent header
val response = client.get("https://httpbin.org/user-agent")Default request configuration plugin for applying common settings to all requests.
object DefaultRequest : HttpClientPlugin<DefaultRequest.Config, DefaultRequest> {
class Config : HttpRequestBuilder() {
// Inherits all HttpRequestBuilder functionality
// for setting default URL, headers, etc.
}
}Usage Example:
val client = HttpClient {
install(DefaultRequest) {
url {
protocol = URLProtocol.HTTPS
host = "api.example.com"
port = 443
}
header("Authorization", "Bearer $token")
header("Content-Type", "application/json")
parameter("api_version", "v1")
}
}
// All requests inherit default configuration
val response = client.get("/users") // Calls https://api.example.com/users?api_version=v1Response validation plugin for validating responses and handling exceptions.
object HttpCallValidator : HttpClientPlugin<HttpCallValidator.Config, HttpCallValidator> {
class Config {
internal val responseValidators = mutableListOf<suspend (response: HttpResponse) -> Unit>()
internal val responseExceptionHandlers = mutableListOf<suspend (exception: Throwable) -> Unit>()
fun validateResponse(block: suspend (response: HttpResponse) -> Unit)
fun handleResponseException(block: suspend (exception: Throwable) -> Unit)
fun handleResponseExceptionWithRequest(
block: suspend (exception: Throwable, request: HttpRequest) -> Unit
)
}
}Usage Example:
val client = HttpClient {
install(HttpCallValidator) {
validateResponse { response ->
val statusCode = response.status.value
if (statusCode >= 400) {
throw ClientRequestException(response, "Request failed with status $statusCode")
}
}
handleResponseException { exception ->
when (exception) {
is ClientRequestException -> {
println("Client error: ${exception.response.status}")
throw exception
}
is ServerResponseException -> {
println("Server error: ${exception.response.status}")
throw exception
}
}
}
}
}Plain text content handling plugin for automatic text serialization and deserialization.
object HttpPlainText : HttpClientPlugin<HttpPlainText.Config, HttpPlainText> {
class Config {
var charsets: MutableSet<Charset> = mutableSetOf(Charsets.UTF_8)
fun register(
contentType: ContentType,
converter: suspend (text: String) -> Any
)
fun register(
contentType: ContentType,
converter: suspend (charset: Charset, text: String) -> Any
)
}
}Usage Example:
val client = HttpClient {
install(HttpPlainText) {
charsets = mutableSetOf(Charsets.UTF_8, Charsets.ISO_8859_1)
// Custom text converter for CSV
register(ContentType.Text.CSV) { text ->
text.lines().map { line -> line.split(",") }
}
}
}
// Automatic text conversion
val csvData: List<List<String>> = client.get("https://example.com/data.csv").body()Request sending pipeline plugin for intercepting and modifying the send phase of requests.
object HttpSend : HttpClientPlugin<HttpSend.Config, HttpSend> {
class Config {
internal val interceptors = mutableListOf<suspend Sender.(HttpRequestBuilder) -> HttpResponse>()
fun intercept(block: suspend Sender.(request: HttpRequestBuilder) -> HttpResponse)
}
interface Sender {
suspend fun execute(requestBuilder: HttpRequestBuilder): HttpResponse
}
}Usage Example:
val client = HttpClient {
install(HttpSend) {
intercept { request ->
// Log request details
println("Sending ${request.method.value} request to ${request.url}")
// Add timestamp header
request.header("X-Request-Time", Clock.System.now().toString())
// Continue with the request
execute(request)
}
}
}Data conversion plugin for automatic serialization and deserialization of request/response bodies.
object DataConversion : HttpClientPlugin<DataConversion.Config, DataConversion> {
class Config {
internal val converters = mutableListOf<ContentConverter>()
fun register(
contentType: ContentType,
converter: ContentConverter,
configuration: ContentConverterConfiguration.() -> Unit = {}
)
}
interface ContentConverter {
suspend fun serialize(
contentType: ContentType,
charset: Charset,
typeInfo: TypeInfo,
value: Any
): OutgoingContent
suspend fun deserialize(
charset: Charset,
typeInfo: TypeInfo,
content: ByteReadChannel
): Any
}
}Usage Example:
// Note: DataConversion is typically used by higher-level serialization plugins
// like JSON, XML, etc. Direct usage is for custom serialization formats.
val client = HttpClient {
install(DataConversion) {
register(
ContentType.Application.Json,
MyJsonConverter()
)
}
}Body upload/download progress tracking plugin for monitoring transfer progress.
object BodyProgress : HttpClientPlugin<BodyProgress.Config, BodyProgress> {
class Config {
internal val sendProgressListeners = mutableListOf<ProgressListener>()
internal val receiveProgressListeners = mutableListOf<ProgressListener>()
fun onUpload(listener: ProgressListener)
fun onDownload(listener: ProgressListener)
}
typealias ProgressListener = (bytesSentTotal: Long, contentLength: Long?) -> Unit
}Usage Example:
val client = HttpClient {
install(BodyProgress) {
onUpload { bytesSentTotal, contentLength ->
val progress = contentLength?.let { (bytesSentTotal * 100 / it).toInt() } ?: 0
println("Upload progress: $progress% ($bytesSentTotal bytes)")
}
onDownload { bytesReceivedTotal, contentLength ->
val progress = contentLength?.let { (bytesReceivedTotal * 100 / it).toInt() } ?: 0
println("Download progress: $progress% ($bytesReceivedTotal bytes)")
}
}
}
// Progress will be tracked for file uploads/downloads
val response = client.post("https://httpbin.org/post") {
setBody("Large file content...")
}All built-in plugins follow the same installation pattern:
val client = HttpClient {
install(PluginName) {
// Plugin-specific configuration
}
}Multiple plugins can be installed together:
val client = HttpClient {
install(HttpTimeout) {
requestTimeoutMillis = 30000
}
install(HttpRequestRetry) {
retryOnServerErrors(maxRetries = 3)
}
install(UserAgent) {
agent = "MyApp/1.0"
}
install(HttpCallValidator) {
validateResponse { response ->
if (response.status.value >= 400) {
throw Exception("Request failed")
}
}
}
}Some plugins work better together or have implicit dependencies:
Install with Tessl CLI
npx tessl i tessl/maven-io-ktor--ktor-client-core-tvosarm64