O Ktor é o framework HTTP nativo do ecossistema Kotlin, mantido pela JetBrains, e a versão 3.4.0 chegou com melhorias que impactam diretamente quem desenvolve APIs, microsserviços e aplicações em tempo real. Se você já usa Ktor para criar APIs ou está planejando migrar do Spring Boot, este artigo cobre tudo que mudou e como aproveitar na prática.
Neste guia, vamos explorar as principais novidades: geração de documentação OpenAPI diretamente do código, streaming duplex com OkHttp, compressão Zstd, o novo plugin de ciclo de vida de requisições e várias outras melhorias.
Geração de OpenAPI direto do código
Uma das features mais pedidas pela comunidade finalmente chegou ao Ktor 3.4: a capacidade de gerar documentação OpenAPI dinamicamente a partir do código de roteamento, sem precisar manter um arquivo YAML ou JSON separado.
A abordagem anterior exigia manter um arquivo openapi.yaml sincronizado manualmente com as rotas — um pesadelo de manutenção em projetos grandes. Agora, com o novo compiler plugin, a documentação vive junto do código:
import io.ktor.server.routing.*
import io.ktor.server.response.*
import io.ktor.http.*
fun Route.messageRoutes() {
get("/messages") {
val query = call.parameters["search"]?.parseQueryOrNull()
call.respond(messageTable.listMessages(query))
}.describe {
summary = "Lista todas as mensagens"
description = "Retorna uma lista paginada de mensagens com filtro opcional."
parameters {
query("search") {
description = "Termo de busca para filtrar mensagens"
required = false
}
query("page") {
description = "Número da página (começando em 0)"
required = false
}
}
responses {
HttpStatusCode.OK {
description = "Lista de mensagens retornada com sucesso"
schema = jsonSchema<List<Message>>()
}
HttpStatusCode.BadRequest {
description = "Parâmetros de busca inválidos"
}
}
}
post("/messages") {
val message = call.receive<CreateMessageRequest>()
val created = messageTable.create(message)
call.respond(HttpStatusCode.Created, created)
}.describe {
summary = "Cria uma nova mensagem"
requestBody {
schema = jsonSchema<CreateMessageRequest>()
}
responses {
HttpStatusCode.Created {
schema = jsonSchema<Message>()
}
}
}
}
A função describe é uma extension function que se encaixa naturalmente no DSL de roteamento do Ktor. A documentação OpenAPI é gerada em runtime e pode ser exposta via endpoint dedicado, facilitando integração com Swagger UI ou outros clientes.
Se você vem do Spring Boot, essa abordagem é similar ao SpringDoc, mas sem annotations — tudo via DSL Kotlin idiomático.
Streaming duplex com OkHttp
O Ktor 3.4 trouxe suporte a streaming duplex no cliente OkHttp, permitindo enviar dados no corpo da requisição e receber dados da resposta simultaneamente via HTTP/2. Isso é essencial para cenários como:
- Upload de arquivos grandes com feedback de progresso em tempo real
- Comunicação bidirecional sem WebSocket
- Streaming de dados de IA (como respostas de LLMs)
A configuração é simples:
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
val client = HttpClient(OkHttp) {
engine {
duplexStreamingEnabled = true
}
}
Com o duplex habilitado, você pode criar fluxos bidirecionais:
client.preparePost("https://api.exemplo.com/stream") {
setBody(object : OutgoingContent.WriteChannelContent() {
override suspend fun writeTo(channel: ByteWriteChannel) {
// Envia dados progressivamente
repeat(100) { i ->
channel.writeStringUtf8("chunk-$i\n")
delay(100)
}
}
})
}.execute { response ->
// Recebe dados enquanto ainda está enviando
val channel = response.bodyAsChannel()
while (!channel.isClosedForRead) {
val line = channel.readUTF8Line() ?: break
println("Recebido: $line")
}
}
Essa feature é especialmente útil se você trabalha com gRPC e Kotlin, já que o streaming bidirecional é um padrão comum em comunicação entre microsserviços.
Compressão Zstd
O Ktor 3.4 adicionou suporte nativo ao Zstd (Zstandard), o algoritmo de compressão desenvolvido pelo Facebook que oferece taxas de compressão superiores ao gzip com velocidade de descompressão significativamente maior.
Para habilitar no servidor, basta instalar o módulo dedicado:
import io.ktor.server.plugins.compression.*
fun Application.configureCompression() {
install(Compression) {
zstd {
compressionLevel = 3 // Padrão: bom equilíbrio velocidade/compressão
}
gzip {
priority = 0.9
}
deflate {
priority = 0.5
}
}
}
O Zstd brilha em cenários onde você transmite payloads JSON grandes — como listas de produtos, logs ou dados analíticos. Em benchmarks internos da JetBrains, o Zstd com nível 3 comprime 20-30% melhor que gzip com velocidade de descompressão até 5x superior.
A dependência é separada para não inflar projetos que não precisam:
// build.gradle.kts
dependencies {
implementation("io.ktor:ktor-server-compression-zstd:3.4.0")
}
Plugin HttpRequestLifecycle
O novo plugin HttpRequestLifecycle resolve um problema antigo: o que acontece com requisições em processamento quando o cliente desconecta? Antes do Ktor 3.4, a coroutine continuava executando até o final, desperdiçando recursos.
Agora, com concorrência estruturada integrada ao ciclo de vida da requisição, operações em andamento são canceladas automaticamente:
import io.ktor.server.plugins.httprequestlifecycle.*
fun Application.configureLifecycle() {
install(HttpRequestLifecycle)
routing {
get("/relatorio-pesado") {
// Se o cliente desconectar, esta coroutine é cancelada
val dados = withContext(Dispatchers.IO) {
// Consulta demorada ao banco de dados
repository.gerarRelatorioCompleto()
}
call.respond(dados)
}
}
}
Essa feature é particularmente importante para operações que consomem muitos recursos, como geração de relatórios, processamento de imagens ou consultas complexas ao banco. Se você trabalha com observabilidade em Kotlin, o cancelamento adequado também gera métricas mais precisas sobre latência real.
Melhorias em Server-Sent Events
O suporte a SSE (Server-Sent Events) que foi introduzido no Ktor 3.0 recebeu melhorias de estabilidade e desempenho no 3.4. O SSE é ideal para cenários onde o servidor precisa enviar atualizações unidirecionais ao cliente — como notificações, feeds de dados ao vivo e dashboards:
import io.ktor.server.sse.*
import io.ktor.sse.*
fun Application.configureSSE() {
install(SSE)
routing {
sse("/eventos") {
// Envia eventos a cada segundo
var contador = 0
while (true) {
send(ServerSentEvent(
data = """{"tipo": "atualizacao", "valor": ${contador++}}""",
event = "dados",
id = contador.toString()
))
delay(1000)
}
}
}
}
No lado do cliente, o Ktor também oferece suporte nativo:
val client = HttpClient(CIO)
client.sse("https://api.exemplo.com/eventos") {
incoming.collect { evento ->
println("Evento recebido: ${evento.data}")
}
}
Se você está considerando entre SSE e WebSocket, o SSE é mais simples quando a comunicação é unidirecional (servidor para cliente) e funciona melhor com proxies e load balancers tradicionais.
Migração e compatibilidade
O Ktor 3.4 é totalmente compatível com o Kotlin 2.3.20 e funciona com o Kotlin 2.4.0 Beta sem problemas. A migração a partir do Ktor 3.x anterior é direta — basta atualizar a versão no Gradle:
// build.gradle.kts
val ktor_version = "3.4.0"
dependencies {
implementation("io.ktor:ktor-server-core:$ktor_version")
implementation("io.ktor:ktor-server-netty:$ktor_version")
implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
}
Se você vem do Ktor 2.x, a migração é mais significativa devido à troca do kotlinx-io. Consulte o guia de backend com Ktor para mais detalhes sobre a arquitetura recomendada.
Conclusão
O Ktor 3.4 consolida o framework como uma opção séria para backend em Kotlin, especialmente para equipes que valorizam a abordagem idiomática do Kotlin com coroutines e DSLs. A geração de OpenAPI via código elimina uma dor antiga, o streaming duplex abre novas possibilidades para aplicações em tempo real, e o Zstd melhora a performance de transferência de dados.
Se você está avaliando frameworks para backend em Kotlin, vale conferir a comparação entre Ktor e Spring Boot para entender qual se encaixa melhor no seu cenário.
Para quem trabalha com outras linguagens no backend, é interessante comparar a abordagem do Ktor com frameworks de Go, que também prioriza simplicidade e performance, ou com o ecossistema de Python para APIs com FastAPI — cada linguagem traz suas vantagens dependendo do caso de uso.