CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-ktor--ktor

A multiplatform asynchronous framework for creating microservices, web applications, and HTTP clients written in Kotlin from the ground up

Pending
Overview
Eval results
Files

plugin-system.mddocs/

Plugin System

Plugin installation, configuration, and built-in plugins for extending client functionality with features like timeouts, cookies, authentication, and more.

Capabilities

HttpClientPlugin Interface

Core interface for creating and installing client plugins.

/**
 * Interface for HTTP client plugins
 */
interface HttpClientPlugin<out TConfig : Any, TPlugin : Any> {
    /** Unique key for identifying the plugin */
    val key: AttributeKey<TPlugin>
    
    /**
     * Prepare the plugin with configuration
     * @param block Configuration block
     * @return Configured plugin instance
     */
    fun prepare(block: TConfig.() -> Unit = {}): TPlugin
    
    /**
     * Install the plugin into a client
     * @param plugin Prepared plugin instance
     * @param scope HttpClient to install into
     */
    fun install(plugin: TPlugin, scope: HttpClient)
}

Plugin Installation

Methods for installing plugins into HttpClient configurations.

/**
 * Install a plugin with configuration in HttpClientConfig
 * @param plugin The plugin to install
 * @param configure Configuration block for the plugin
 */
fun <TBuilder : Any, TPlugin : Any> HttpClientConfig<*>.install(
    plugin: HttpClientPlugin<TBuilder, TPlugin>,
    configure: TBuilder.() -> Unit = {}
)

/**
 * Install a plugin by key with custom installation logic
 * @param key String identifier for the plugin
 * @param block Installation logic
 */
fun HttpClientConfig<*>.install(key: String, block: HttpClient.() -> Unit)

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.*

val client = HttpClient {
    // Install plugin with configuration
    install(HttpTimeout) {
        requestTimeoutMillis = 30000
        connectTimeoutMillis = 10000
        socketTimeoutMillis = 60000
    }
    
    // Install plugin without configuration
    install(HttpRedirect)
    
    // Install by string key
    install("CustomPlugin") {
        // Custom installation logic
    }
}

Built-in Plugins

HttpTimeout Plugin

Configures request, connection, and socket timeouts.

/**
 * HTTP timeout plugin for configuring request timeouts
 */
val HttpTimeout: ClientPlugin<HttpTimeoutConfig>

/**
 * Configuration for HTTP timeout plugin
 */
class HttpTimeoutConfig {
    /** Total request timeout in milliseconds */
    var requestTimeoutMillis: Long? = null
    
    /** Connection timeout in milliseconds */
    var connectTimeoutMillis: Long? = null
    
    /** Socket timeout in milliseconds */
    var socketTimeoutMillis: Long? = null
}

/**
 * Configure timeout for a specific request
 * @param block Configuration block for timeout
 */
fun HttpRequestBuilder.timeout(block: HttpTimeoutConfig.() -> Unit)

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*

// Global timeout configuration
val client = HttpClient {
    install(HttpTimeout) {
        requestTimeoutMillis = 30000
        connectTimeoutMillis = 5000
        socketTimeoutMillis = 60000
    }
}

// Per-request timeout configuration
val response = client.get("https://api.example.com/slow-endpoint") {
    timeout {
        requestTimeoutMillis = 60000
    }
}

HttpRedirect Plugin

Handles HTTP redirects automatically.

/**
 * HTTP redirect plugin for handling redirects
 */
val HttpRedirect: ClientPlugin<HttpRedirect.Config>

class HttpRedirect {
    /**
     * Configuration for HTTP redirect plugin
     */
    class Config {
        /** Whether to check HTTP method when following redirects */
        var checkHttpMethod: Boolean = true
        
        /** Whether to allow HTTPS to HTTP downgrades */
        var allowHttpsDowngrade: Boolean = false
        
        /** Maximum number of redirect jumps to follow */
        var maxJumps: Int = 20
    }
}

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.*

val client = HttpClient {
    install(HttpRedirect) {
        checkHttpMethod = false
        allowHttpsDowngrade = true
        maxJumps = 10
    }
}

HttpCallValidator Plugin

Validates responses and handles exceptions.

/**
 * HTTP call validator plugin for response validation
 */
val HttpCallValidator: ClientPlugin<HttpCallValidator.Config>

class HttpCallValidator {
    /**
     * Configuration for HTTP call validator plugin
     */
    class Config {
        /**
         * Add response validation logic
         * @param block Validation block that receives the response
         */
        fun validateResponse(block: suspend (response: HttpResponse) -> Unit)
        
        /**
         * Add exception handling logic for requests
         * @param block Exception handling block
         */
        fun handleResponseExceptionWithRequest(
            block: suspend (exception: Throwable, request: HttpRequest) -> Unit
        )
    }
}

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.*
import io.ktor.client.statement.*

val client = HttpClient {
    install(HttpCallValidator) {
        validateResponse { response ->
            if (response.status.value !in 200..299) {
                throw ResponseException(response, "HTTP ${response.status}")
            }
        }
        
        handleResponseExceptionWithRequest { exception, request ->
            println("Request to ${request.url} failed: ${exception.message}")
        }
    }
}

UserAgent Plugin

Sets the User-Agent header for requests.

/**
 * User-Agent plugin for setting user agent header
 */
val UserAgent: ClientPlugin<UserAgentConfig>

/**
 * Configuration for User-Agent plugin
 */
class UserAgentConfig {
    /** User agent string to use */
    var agent: String = "Ktor client"
}

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.*

val client = HttpClient {
    install(UserAgent) {
        agent = "MyApplication/1.0.0"
    }
}

DefaultRequest Plugin

Sets default configuration for all requests.

/**
 * Default request plugin for setting default request configuration
 */
val DefaultRequest: ClientPlugin<DefaultRequest.Config>

class DefaultRequest {
    /**
     * Configuration for default request plugin
     */
    class Config {
        /**
         * Configure default request settings
         * @param block Configuration block applied to all requests
         */
        fun request(block: HttpRequestBuilder.() -> Unit)
    }
}

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*
import io.ktor.http.*

val client = HttpClient {
    install(DefaultRequest) {
        request {
            host = "api.example.com"
            url {
                protocol = URLProtocol.HTTPS
                path("v1/")
            }
            header(HttpHeaders.Authorization, "Bearer $token")
        }
    }
}

// This request will use the default configuration
val response = client.get("users") // Becomes https://api.example.com/v1/users

HttpCookies Plugin

Handles HTTP cookies automatically.

/**
 * HTTP cookies plugin for cookie management
 */
val HttpCookies: ClientPlugin<HttpCookies.Config>

class HttpCookies {
    /**
     * Configuration for HTTP cookies plugin
     */
    class Config {
        /** Cookie storage implementation */
        var storage: CookiesStorage = AcceptAllCookiesStorage()
    }
}

/**
 * Interface for cookie storage implementations
 */
interface CookiesStorage : Closeable {
    /**
     * Get cookies for a request URL
     * @param requestUrl URL of the request
     * @return List of applicable cookies
     */
    suspend fun get(requestUrl: Url): List<Cookie>
    
    /**
     * Add a cookie from a response
     * @param requestUrl URL of the request
     * @param cookie Cookie to store
     */
    suspend fun addCookie(requestUrl: Url, cookie: Cookie)
}

/**
 * Cookie storage that accepts all cookies
 */
class AcceptAllCookiesStorage : CookiesStorage

/**
 * Cookie storage with constant cookies
 */
class ConstantCookiesStorage(vararg cookies: Cookie) : CookiesStorage

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.cookies.*
import io.ktor.http.*

val client = HttpClient {
    install(HttpCookies) {
        storage = AcceptAllCookiesStorage()
    }
}

// Custom cookie storage
val customStorage = ConstantCookiesStorage(
    Cookie("session", "abc123", domain = "example.com"),
    Cookie("preferences", "theme=dark", domain = "example.com")
)

val clientWithCustomCookies = HttpClient {
    install(HttpCookies) {
        storage = customStorage
    }
}

HttpCache Plugin

Provides HTTP response caching functionality.

/**
 * HTTP cache plugin for response caching
 */
val HttpCache: ClientPlugin<HttpCache.Config>

class HttpCache {
    /**
     * Configuration for HTTP cache plugin
     */
    class Config {
        /** Whether the cache is shared between multiple clients */
        var isShared: Boolean = false
        
        /**
         * Configure public cache storage
         * @param storage Cache storage implementation
         */
        fun publicStorage(storage: CacheStorage)
        
        /**
         * Configure private cache storage
         * @param storage Cache storage implementation
         */
        fun privateStorage(storage: CacheStorage)
    }
}

/**
 * Interface for cache storage implementations
 */
interface CacheStorage {
    /**
     * Find cached entry for URL and vary headers
     * @param url Request URL
     * @param vary Vary header values
     * @return Cached entry or null if not found
     */
    suspend fun find(url: Url, vary: Map<String, String>): HttpCacheEntry?
    
    /**
     * Find all cached entries for URL
     * @param url Request URL
     * @return Set of cached entries
     */
    suspend fun findAll(url: Url): Set<HttpCacheEntry>
    
    /**
     * Store cache entry
     * @param url Request URL
     * @param data Cache entry to store
     */
    suspend fun store(url: Url, data: HttpCacheEntry)
    
    companion object {
        /** Create unlimited cache storage */
        fun Unlimited(): CacheStorage
        
        /** Create disabled cache storage */
        fun Disabled(): CacheStorage
    }
}

/**
 * HTTP cache entry
 */
data class HttpCacheEntry(
    val url: Url,
    val statusCode: HttpStatusCode,
    val requestTime: GMTDate,
    val responseTime: GMTDate,
    val version: HttpProtocolVersion,
    val expires: GMTDate,
    val headers: Headers,
    val body: ByteArray
)

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.cache.*

val client = HttpClient {
    install(HttpCache) {
        publicStorage(CacheStorage.Unlimited())
        privateStorage(CacheStorage.Unlimited())
    }
}

BodyProgress Plugin

Tracks upload and download progress for request and response bodies.

/**
 * Body progress plugin for tracking upload/download progress
 */
val BodyProgress: ClientPlugin<BodyProgress.Config>

class BodyProgress {
    /**
     * Configuration for body progress plugin
     */
    class Config {
        /**
         * Register a progress listener
         * @param listener Progress listener to register
         */
        fun register(listener: ProgressListener)
    }
}

/**
 * Interface for progress listeners
 */
fun interface ProgressListener {
    /**
     * Called when progress is made
     * @param bytesSentTotal Total bytes sent so far
     * @param contentLength Total content length, null if unknown
     */
    fun onProgress(bytesSentTotal: Long, contentLength: Long?)
}

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*

val client = HttpClient {
    install(BodyProgress) {
        register { bytesSentTotal, contentLength ->
            val progress = if (contentLength != null) {
                (bytesSentTotal * 100 / contentLength).toInt()
            } else {
                -1
            }
            println("Upload progress: $bytesSentTotal bytes ($progress%)")
        }
    }
}

// Progress will be tracked for this upload
val response = client.post("https://api.example.com/upload") {
    setBody(largeFileContent)
}

Advanced Plugins

Server-Sent Events (SSE) Plugin

Provides Server-Sent Events support.

/**
 * Server-Sent Events plugin
 */
val SSE: ClientPlugin<SSEConfig>

/**
 * Configuration for SSE plugin
 */
class SSEConfig {
    /** Reconnection time for failed connections */
    var reconnectionTime: Duration? = null
    
    /** Whether to show comment events */
    var showCommentEvents: Boolean? = null
    
    /** Whether to show retry events */
    var showRetryEvents: Boolean? = null
    
    /** Maximum reconnection attempts */
    var maxReconnectionAttempts: Int = Int.MAX_VALUE
}

/**
 * SSE session interface
 */
interface ClientSSESession {
    /** Flow of incoming server-sent events */
    val incoming: Flow<ServerSentEvent>
}

/**
 * SSE session with deserialization support
 */
interface ClientSSESessionWithDeserialization {
    /** Flow of incoming typed server-sent events */
    val incoming: Flow<TypedServerSentEvent<String>>
    
    /**
     * Deserialize event data
     * @param data Event data string
     * @return Deserialized object of type T
     */
    suspend inline fun <reified T> deserialize(data: String?): T?
}

/**
 * Connect to Server-Sent Events endpoint
 * @param host Server host
 * @param port Server port
 * @param path URL path
 * @param request Request configuration
 * @param block SSE session block
 */
suspend fun HttpClient.sse(
    host: String = "localhost",
    port: Int = DEFAULT_PORT,
    path: String = "/",
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend ClientSSESession.() -> Unit
)

/**
 * Connect to Server-Sent Events endpoint with deserialization
 * @param request Request configuration
 * @param deserialize Deserialization function
 * @param block SSE session block
 */
suspend fun <T> HttpClient.sse(
    request: HttpRequestBuilder.() -> Unit,
    deserialize: (TypeInfo, String) -> Any?,
    block: suspend ClientSSESessionWithDeserialization.() -> Unit
)

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.sse.*
import kotlinx.coroutines.flow.collect

val client = HttpClient {
    install(SSE) {
        reconnectionTime = 3.seconds
        showCommentEvents = true
    }
}

// Connect to SSE endpoint
client.sse(
    host = "api.example.com",
    path = "/events"
) {
    incoming.collect { event ->
        println("Received: ${event.data}")
    }
}

WebSockets Plugin

Provides WebSocket client support.

/**
 * WebSockets plugin
 */
val WebSockets: ClientPlugin<WebSocketConfig>

/**
 * Connect to WebSocket endpoint
 * @param method HTTP method for handshake
 * @param host Server host
 * @param port Server port
 * @param path URL path
 * @param request Request configuration
 * @param block WebSocket session block
 */
suspend fun HttpClient.webSocket(
    method: HttpMethod = HttpMethod.Get,
    host: String = "localhost",
    port: Int = DEFAULT_PORT,
    path: String = "/",
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

/**
 * Connect to WebSocket endpoint with URL string
 * @param urlString WebSocket URL
 * @param request Request configuration
 * @param block WebSocket session block
 */
suspend fun HttpClient.webSocket(
    urlString: String,
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

/**
 * Connect to secure WebSocket endpoint
 */
suspend fun HttpClient.wss(
    host: String = "localhost",
    port: Int = DEFAULT_PORT,
    path: String = "/",
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

Usage Examples:

import io.ktor.client.*
import io.ktor.client.plugins.websocket.*
import io.ktor.websocket.*

val client = HttpClient {
    install(WebSockets)
}

// Connect to WebSocket
client.webSocket(
    host = "echo.websocket.org",
    port = 80,
    path = "/"
) {
    // Send message
    send("Hello WebSocket!")
    
    // Receive messages
    for (frame in incoming) {
        when (frame) {
            is Frame.Text -> {
                println("Received: ${frame.readText()}")
            }
            is Frame.Binary -> {
                println("Received binary data")
            }
            is Frame.Close -> {
                println("Connection closed")
                break
            }
        }
    }
}

Types

Plugin system related types:

/**
 * Attribute key for identifying plugins
 */
data class AttributeKey<T>(val name: String)

/**
 * Exception for SSE operations
 */
class SSEClientException(
    response: HttpResponse?,
    cause: Throwable?,
    message: String?
) : IllegalStateException()

/**
 * Server-sent event data
 */
data class ServerSentEvent(
    val data: String?,
    val event: String?,
    val id: String?,
    val retry: Long?,
    val comments: String?
)

/**
 * Typed server-sent event
 */
data class TypedServerSentEvent<T>(
    val data: T?,
    val event: String?,
    val id: String?,
    val retry: Long?
)

/**
 * Cookie data class
 */
data class Cookie(
    val name: String,
    val value: String,
    val encoding: CookieEncoding = CookieEncoding.URI_ENCODING,
    val maxAge: Int = 0,
    val expires: GMTDate? = null,
    val domain: String? = null,
    val path: String? = null,
    val secure: Boolean = false,
    val httpOnly: Boolean = false,
    val extensions: Map<String, String?> = emptyMap()
)

Install with Tessl CLI

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

docs

client-management.md

engine-system.md

form-data.md

http-utilities.md

index.md

plugin-system.md

request-operations.md

response-handling.md

routing-system.md

server-framework.md

tile.json