Ktor es un cliente HTTP asíncrono para Kotlin, desarrollado por JetBrains como parte del framework homónimo para el desarrollo de servidores y clientes. Ktor está construido sobre corrutinas de Kotlin y es multiplataforma. Según JetBrains, 2025, Ktor ofrece integración nativa con el ecosistema Kotlin sin reflexión ni dependencias adicionales.
Puntos clave
Ktor es un framework para construir aplicaciones asíncronas de servidor y cliente en Kotlin, creado por JetBrains. Ktor Client es la parte cliente del framework, que proporciona un cliente HTTP con soporte completo para corrutinas de Kotlin, multiplataforma (JVM, Native, JS) y una arquitectura modular basada en complementos.
Ktor surgió en 2018 como alternativa a Retrofit y OkHttp para proyectos Kotlin-first. A diferencia de Retrofit, que adaptó el enfoque Java con anotaciones, Ktor Client utiliza Kotlin DSL para la configuración de solicitudes — sin anotaciones ni reflexión. Esto hace que el código sea más legible y type-safe para los desarrolladores Kotlin.
Según la encuesta de Kotlin Multiplatform 2024, Ktor Client se utiliza en el 35% de los proyectos Kotlin Multiplatform Mobile (KMM), lo que lo convierte en el segundo cliente HTTP más popular después de OkHttp en la comunidad Kotlin. Ktor se prefiere en proyectos donde la multiplataforma y la integración nativa con el ecosistema Kotlin son importantes.
Arquitectura de Ktor Client se basa en un pipeline de complementos. Cada solicitud pasa por una secuencia de complementos instalados que pueden modificar la solicitud, la respuesta o realizar acciones secundarias — registro, compresión, serialización, autenticación.
Al crear un cliente HTTP mediante el bloque DSL HttpClient { }, se especifica el motor (OkHttp, Android, CIO, Darwin) y se instalan los complementos. Cada motor implementa el envío de solicitudes de bajo nivel para una plataforma específica: en Android se usa el motor OkHttp, en iOS — Darwin (URLSession), en Escritorio — CIO (Coroutine I/O). HttpClient selecciona automáticamente el motor óptimo para la plataforma actual.
Una solicitud en Ktor Client se ejecuta mediante una función suspend, lo que significa integración total con corrutinas. Sin Callbacks, sin RxJava ni LiveData — solo código secuencial con suspend que funciona de forma asíncrona sin bloquear el hilo.
El pipeline de Ktor consta de fases: primero la solicitud pasa por los complementos instalados (por ejemplo, ContentNegotiation para JSON, Logging para registros), luego el motor ejecuta la solicitud HTTP, y la respuesta vuelve a pasar por los complementos para la deserialización. Cada complemento es una función suspend que se ejecuta en la corrutina del pipeline.
Una ventaja importante del pipeline de Ktor es la capacidad de realizar procesamiento condicional. Un complemento puede verificar la URL o los encabezados de la solicitud y omitir el procesamiento si no se cumple la condición. Por ejemplo, ContentEncoding con gzip solo se aplica a respuestas que contienen el encabezado Content-Encoding: gzip, y Auth solo se activa para endpoints protegidos sin afectar las API públicas.
Este enfoque de pipeline permite combinar complementos de manera flexible: se puede instalar ContentNegotiation con JSON, añadir Auth con token Bearer, activar la compresión ContentEncoding y HttpTimeout — y todos funcionarán juntos en el orden correcto. El orden de instalación de los complementos importa: el primer complemento instalado procesará la solicitud antes que los demás.
Los complementos son el sistema de extensión modular de Ktor, que reemplaza las anotaciones de Retrofit y los interceptores de OkHttp. Cada complemento resuelve una tarea específica y se instala mediante la función install() en el bloque HttpClient. Ktor proporciona complementos integrados y también permite crear personalizados.
| Complemento | Propósito |
|---|---|
| ContentNegotiation | Serialización y deserialización de JSON, XML mediante Kotlinx Serialization |
| Logging | Registro de solicitudes y respuestas con nivel configurable |
| Auth | Autenticación: Basic, Bearer, Digest con actualización automática de token |
| HttpTimeout | Configuración de tiempos de espera de conexión, lectura y solicitud |
| ContentEncoding | Compresión transparente gzip y deflate |
| DefaultRequest | Establecimiento de valores predeterminados para todas las solicitudes |
Para tareas específicas, se crea un complemento personalizado mediante createClientPlugin. El complemento puede interceptar la solicitud (onRequest), la respuesta (onResponse) o manejar errores (onError). Esto reemplaza completamente el Interceptor de OkHttp, pero con una API Kotlin tipada y soporte de funciones suspend.
Los complementos personalizados son útiles para añadir métricas, lógica de reintento automático, trazado de solicitudes o pruebas A/B de endpoints. A diferencia de los interceptores de OkHttp, los complementos de Ktor están escritos en Kotlin y se ejecutan en el contexto de la corrutina, simplificando el manejo de errores y tiempos de espera.
Para la depuración de solicitudes se utiliza el complemento Logging con nivel ALL, HEADERS o BODY. Logging muestra el método, URL, estado, encabezados y cuerpo de la solicitud y respuesta. A diferencia de HttpLoggingInterceptor de OkHttp, Ktor Logging funciona de forma asíncrona y puede configurarse para filtrar por nivel de registro (ERROR, WARN, INFO, DEBUG) sin detener la aplicación para cambiar la configuración.
Veamos una solicitud GET básica con Ktor Client. Se crea un HttpClient con el complemento ContentNegotiation instalado para JSON. La solicitud se ejecuta mediante la función suspend get(), y el resultado se deserializa automáticamente en una data class.
data class User(
val login: String,
val id: Int,
val avatarUrl: String
)
val client = HttpClient {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
}
suspend fun getUser(): User {
return client.get("https://api.github.com/users/octocat").body()
}
Para una solicitud POST con cuerpo se utiliza la función post() con contentType() y body(). Ktor serializa automáticamente el objeto a JSON mediante ContentNegotiation instalado. El estilo DSL hace que el código sea secuencial y legible.
data class CreateRepo(
val name: String,
val description: String,
val private: Boolean
)
suspend fun createRepo(): Unit {
val repo = CreateRepo(
name = "my-project",
description = "Sample project",
private = false
)
client.post("https://api.github.com/user/repos") {
contentType(ContentType.Application.Json)
setBody(repo)
}
}
HttpTimeout y DefaultRequest son dos complementos clave para la configuración. HttpTimeout establece límites de tiempo, y DefaultRequest especifica encabezados y parámetros URL para todas las solicitudes, eliminando la duplicación de código en cada llamada.
val client = HttpClient {
install(HttpTimeout) {
connectTimeoutMillis = 15000
requestTimeoutMillis = 30000
}
install(DefaultRequest) {
url("https://api.github.com/")
header("Accept", "application/json")
}
}
La multiplataforma es la principal ventaja de Ktor sobre OkHttp y Retrofit. Ktor Client funciona en JVM (Android, Servidor), Native (iOS, macOS, Windows, Linux) y JS (Navegador). El mismo código de cliente HTTP se ejecuta en todas las plataformas sin cambios, lo que es especialmente valioso para proyectos Kotlin Multiplatform.
Para cada plataforma, Ktor utiliza su propio motor. En Android, se utiliza por defecto el motor OkHttp, que proporciona compatibilidad total con el ecosistema OkHttp. En iOS se usa DarwinEngine, basado en URLSession. Para Servidor — CIOEngine (Coroutine I/O). El motor puede especificarse explícitamente: HttpClient(OkHttp) { } o HttpClient(Darwin) { }.
Al elegir un motor, considere sus capacidades: el motor OkHttp admite HTTP/2 y pool de conexiones, DarwinEngine ofrece integración nativa de red iOS y sesiones URLSession en segundo plano, CIOEngine es una implementación pura de corrutinas sin dependencias externas. Para objetivos Web, se utiliza JsEngine o BrowserEngine, que funciona mediante fetch API.
Gracias a una API unificada en todas las plataformas, el código para cargar datos se ve igual en Android, iOS y Escritorio. Esto reduce la duplicación de código en un 60–80% en proyectos KMM en comparación con implementaciones separadas en Retrofit (Android) y URLSession (iOS). Los complementos también funcionan en todas las plataformas sin cambios.
Ignorar el cierre de HttpClient es un error frecuente en Ktor. HttpClient implementa Closeable, y debe cerrarse al finalizar la aplicación mediante client.close(). En Android, esto se hace en onDestroy() de Activity o ViewModel.onCleared(). Un cliente no cerrado provoca fugas de corrutinas y subprocesos del motor.
Orden incorrecto de los complementos puede romper el procesamiento de solicitudes. Por ejemplo, ContentNegotiation debe instalarse antes que DefaultRequest para que el tipo de contenido se aplique correctamente. Se recomienda instalar Logging al final para registrar la versión final de la solicitud después de todas las modificaciones. Experimente con el orden si los complementos se comportan inesperadamente.
Falta de manejo de excepciones en funciones suspend. Ktor lanza IOException para errores de red y ClientRequestException para estados HTTP 4xx. El bloque try-catch es obligatorio para cada llamada a get(), post() y otros métodos. Use HttpResponseValidator en el bloque HttpClient para el manejo global de errores sin duplicar try-catch en cada método.
Preguntas frecuentes
Ktor utiliza Kotlin DSL y complementos sin anotaciones ni reflexión. Retrofit está construido sobre anotaciones Java y reflexión. Ktor es multiplataforma, Retrofit solo JVM/Android. Ktor funciona nativamente con corrutinas, Retrofit añadió suspend mediante un envoltorio.
Para Android, el motor OkHttp es óptimo — proporciona compatibilidad con el ecosistema OkHttp, pool de conexiones, almacenamiento en caché y HTTP/2. Elíjalo mediante HttpClient(OkHttp) { }. La alternativa es CIOEngine, integrado en Ktor, pero es menos estable en Android.
Sí, Ktor soporta HTTP/2 a través del motor correspondiente. El motor OkHttp hereda el soporte HTTP/2 de OkHttp. DarwinEngine en iOS soporta HTTP/2 mediante URLSession. CIOEngine soporta HTTP/2 en el lado del servidor. La elección del motor determina el nivel de soporte del protocolo.
Use el complemento Auth con la configuración bearer { }. El complemento añade automáticamente el encabezado Authorization a cada solicitud y puede renovar el token en respuesta 401 mediante refreshTokens. Ejemplo: install(Auth) { bearer { loadTokens { BearerTokens(token, refreshToken) } } }.
Sí, Ktor Client funciona completamente en iOS a través de DarwinEngine, que utiliza URLSession. Todos los complementos, la serialización y las corrutinas funcionan en iOS igual que en Android. Esto convierte a Ktor en el principal cliente HTTP para proyectos Kotlin Multiplatform Mobile (KMM).
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también