Ktor è un client HTTP asincrono e un framework server per Kotlin che supporta lo sviluppo multipiattaforma. La libreria è costruita sulle coroutine Kotlin e funziona su JVM, iOS, Android, JS e Native. Secondo il repository di Ktor su GitHub, il progetto è attivamente sviluppato dal team JetBrains. Ktor offre un'architettura modulare con un sistema di plugin per la configurazione flessibile delle connessioni HTTP.
Punti chiave
Ktor è un framework per creare client e server HTTP in Kotlin, sviluppato da JetBrains. A differenza delle librerie tradizionali, Ktor è stato progettato fin dall'inizio per lo sviluppo multipiattaforma e funziona su tutte le piattaforme supportate da Kotlin.
Ktor utilizza un approccio middleware, ispirato all'architettura di Kodein ed Express.js. Ogni richiesta attraversa un pipeline di funzioni handler che possono modificare la richiesta e la risposta. Questo offre flessibilità non disponibile nelle librerie con architettura rigida basata su annotazioni.
La versione attuale Ktor 3.0 include il supporto per Kotlin 2.0, il compilatore K2 e un nuovo motore CIO (Coroutine I/O) con prestazioni migliorate. La libreria è distribuita sotto licenza Apache 2.0 ed è disponibile per uso commerciale senza restrizioni.
Il lato client di Ktor è completamente costruito sulle coroutine Kotlin, garantendo un'esecuzione asincrona efficiente delle richieste senza blocco dei thread. Il lato server permette di creare server HTTP con routing, elaborazione delle richieste e connessioni WebSocket.
Ktor utilizza un'architettura a plugin: tutte le funzionalità aggiuntive — logging, serializzazione, autenticazione — vengono collegate tramite plugin. Questo rende la libreria modulare e permette di collegare solo i componenti necessari, riducendo le dimensioni dell'applicazione finale.
Grazie a un'API unificata su tutte le piattaforme, lo sviluppatore non deve imparare diversi client HTTP per iOS e Android. In un progetto multipiattaforma, il codice del livello di rete è completamente condiviso e l'implementazione specifica della piattaforma è nascosta dietro il motore HttpClient. Questo riduce i tempi di sviluppo e diminuisce il numero di errori legati alle differenze tra piattaforme.
Ktor fornisce una serie di funzionalità che lo rendono una scelta interessante per i progetti Kotlin moderni, specialmente quelli multipiattaforma.
Ktor funziona su JVM, Android, iOS, macOS, Windows, Linux, JavaScript e Wasm. Lo stesso codice client HTTP viene eseguito su tutte le piattaforme senza modifiche. Questo è un vantaggio chiave rispetto alle librerie legate a OkHttp o URLSession.
Le coroutine Kotlin forniscono asincronicità naturale senza callback. Ogni richiesta è una funzione suspend che può essere chiamata da qualsiasi coroutine. Ktor supporta lo streaming delle risposte tramite Flow, comodo per connessioni lunghe e WebSocket.
I plugin di Ktor vengono collegati tramite un blocco install e configurati separatamente. Plugin principali: ContentNegotiation per la serializzazione, Logging per la registrazione, Auth per l'autenticazione e WebSockets per la comunicazione bidirezionale. Ogni plugin può essere abilitato o disabilitato indipendentemente.
La gestione degli errori in Ktor si basa sulle eccezioni. La classe ClientRequestException viene lanciata per i codici 4xx, ServerResponseException per i 5xx e IOException per i guasti di rete. I timeout vengono configurati tramite il plugin HttpTimeout, che imposta il tempo di attesa per connessione, lettura e scrittura. Per i tentativi, viene utilizzato il plugin Retry con impostazioni per numero di tentativi e ritardo.
Ktor utilizza un'architettura a pipeline dove ogni richiesta attraversa una catena di handler. Il client crea una configurazione HttpClient con i plugin installati e ogni chiamata a get o post attraversa i plugin nell'ordine in cui sono stati collegati.
L'oggetto HttpClient viene creato con un motore specifico della piattaforma: CIO per JVM e Android, Darwin per iOS e macOS, OkHttp per la compatibilità Android, Js per il browser. Il motore può essere selezionato esplicitamente o lasciato alla scelta automatica. Ogni richiesta restituisce un HttpResponse contenente il corpo della risposta, le intestazioni e lo stato.
val client = HttpClient(CIO) {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
}
suspend fun fetchUsers(): List<User> {
return client.get("https://api.example.com/users").body()
}
L'installazione di Ktor viene eseguita tramite Gradle o Maven. Per i progetti multipiattaforma, le dipendenze vengono specificate nei sourceSets per ogni destinazione. Ktor è distribuito tramite Maven Central.
In build.gradle.kts, aggiungi la dipendenza ktor-client-core per il codice comune e un motore per la piattaforma specifica. La versione di Ktor viene impostata tramite una variabile in gradle.properties. Ktor 3.x richiede Kotlin 2.0+ e supporta il compilatore K2.
val ktorVersion = "3.0.3"
dependencies {
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-cio:$ktorVersion")
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
implementation("io.ktor:ktor-client-logging:$ktorVersion")
}
Per iOS, viene utilizzato il motore Darwin, che incapsula URLSession nativo. In Kotlin Multiplatform, ciò offre prestazioni massime e integrazione con i meccanismi di caching del sistema iOS. Il motore viene aggiunto come dipendenza separata nel sourceSet iOS.
Una caratteristica importante di Ktor è il supporto di diversi formati di serializzazione tramite ContentNegotiation. Oltre a JSON, il plugin supporta Protobuf, CBOR, XML e formati personalizzati. Per la serializzazione vengono utilizzate le librerie kotlinx.serialization o Jackson e lo sviluppatore può passare dall'una all'altra senza modificare il codice delle richieste.
Gli esempi seguenti mostrano scenari tipici di lavoro con il client Ktor: una richiesta GET di base, l'invio di dati e il lavoro con codice multipiattaforma.
Una semplice richiesta GET con deserializzazione automatica della risposta in una data class. Ktor utilizza il plugin ContentNegotiation con kotlinx.serialization per convertire JSON in oggetti. Il codice è conciso e type-safe.
@Serializable
data class Post(
val id: Int,
val title: String,
val body: String
)
suspend fun getPosts(): List<Post> {
val response = client.get("https://jsonplaceholder.typicode.com/posts")
return response.body()
}
Una richiesta POST in Ktor invia una data class come corpo JSON tramite il metodo post con contentType e setBody. Il plugin ContentNegotiation serializza automaticamente l'oggetto in una stringa JSON. La risposta può essere elaborata in modo sincrono o asincrono.
suspend fun createPost(): Post {
val newPost = Post(
id = 0,
title = "Nuovo post",
body = "Contenuto del post"
)
val response = client.post("https://jsonplaceholder.typicode.com/posts") {
contentType(ContentType.Application.Json)
setBody(newPost)
}
return response.body()
}
Il metodo submitFormWithBinaryData in Ktor permette di inviare file e moduli in formato multipart. Ktor divide automaticamente i dati in parti e aggiunge le intestazioni. Per tracciare il progresso, viene utilizzato onUpload, che riceve i byte dei dati inviati.
suspend fun uploadFile(fileBytes: ByteArray) {
client.submitFormWithBinaryData(
url = "https://api.example.com/upload",
formData = formData {
append("file", fileBytes, Headers.build {
append(HttpHeaders.ContentType, "image/png")
append(HttpHeaders.ContentDisposition, "filename=\"photo.png\"")
})
}
)
}
La scelta tra Ktor e Retrofit dipende dall'architettura del progetto e dai requisiti multipiattaforma. Retrofit rimane lo standard per i progetti solo Android, mentre Ktor è la scelta migliore per Kotlin Multiplatform.
Ktor fornisce anche supporto integrato per WebSocket e SSE (Server-Sent Events), rendendolo comodo per applicazioni in tempo reale. Retrofit non supporta WebSocket direttamente — è necessaria una libreria OkHttp WebSocket separata. Ktor è anche più facile da configurare per diversi ambienti grazie al suo sistema di plugin, dove ogni plugin è responsabile di una funzione.
Il plugin Auth in Ktor supporta l'autenticazione di base, i token Bearer, Digest e OAuth2. La configurazione dell'autenticazione viene eseguita in modo dichiarativo: lo sviluppatore specifica il provider, la fonte del token e l'ambito. Ktor aggiunge automaticamente le intestazioni di autenticazione alle richieste e può rinnovare il token quando scade.
Se un progetto utilizza Kotlin Multiplatform con codice condiviso su iOS e Android, Ktor è l'unica opzione che funziona su entrambe le piattaforme senza livelli aggiuntivi. Retrofit è strettamente legato a OkHttp e JVM, rendendolo inadatto per iOS.
Per i progetti solo Android, Retrofit fornisce un'API più matura, un maggior numero di convertitori e intercettori OkHttp. Ktor funziona anche in questo scenario, ma il suo ecosistema di plugin è meno esteso. Entrambe le librerie supportano le coroutine e offrono prestazioni comparabili.
| Criterio | Ktor | Retrofit |
|---|---|---|
| Multipiattaforma | iOS, Android, JVM, JS, Native | Solo JVM e Android |
| Motore HTTP | CIO, Darwin, OkHttp, Js | OkHttp |
| Convertitori | kotlinx.serialization, Jackson | Gson, Moshi, Jackson, Protobuf |
| Architettura | Pipeline con plugin | Annotazioni con generazione di codice |
| Sviluppatore | JetBrains | Square |
Domande frequenti
Ktor — un client HTTP multipiattaforma su coroutine di JetBrains. Retrofit — una libreria Android di Square basata su OkHttp. Ktor funziona su iOS, Android, JS e Native, mentre Retrofit funziona solo su JVM.
Sì, Ktor supporta iOS tramite il motore Darwin che utilizza URLSession nativo. Ciò garantisce prestazioni massime e un corretto funzionamento con la cache di sistema iOS. Il codice client rimane condiviso tra le piattaforme.
Ktor supporta i motori: CIO (JVM/Android), Darwin (iOS/macOS), OkHttp (Android), Js (browser), Jetty, Netty, Tomcat (server). Il motore può essere selezionato esplicitamente o lasciato alla selezione automatica predefinita.
Sì, Ktor ha il supporto integrato per WebSocket sia sul client che sul server. Per il client viene utilizzato il plugin WebSockets, che consente di stabilire una connessione bidirezionale e scambiare messaggi in tempo reale.
Gli errori vengono gestiti tramite try-catch attorno alle chiamate suspend. Ktor lancia ClientRequestException per i 4xx, ServerResponseException per i 5xx e IOException per gli errori di rete. Si consiglia di utilizzare il tipo Result per l'unificazione.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche