Ktor 2.0 릴리스

Read this post in other languages:

Ktor 2.0이 출시되었다는 기쁜 소식을 전해 드립니다. 약 1년의 작업 끝에 마침내 결실을 맺었군요! 

Ktor 2.0에는 많은 새로운 기능이 도입되었지만, 주요 버전인 만큼 획기적인 변경 사항이 적용되었고, 일부 유지 관리 작업과 더불어 기존에 잘못된 결정을 철회하는 기회로도 삼았습니다. 대대적인 변경이 있었지만 이를 최소화하려고 노력했고 자동화된 마이그레이션에 도움이 될 수 있는 일부 지원 도구도 제공되니 염려하지 마세요. 먼저 몇 가지 새로운 기능을 살펴보고 그 밖의 내용은 나중에 자세히 알아보도록 하겠습니다.

Ktor 서버

단순화된 확장성

Ktor를 빌드할 때는 항상 확장성을 염두에 둡니다. 처음에는 기능이라고 불렀고 지금은 플러그인으로 이름이 바뀌었지만, Ktor가 제공하는 모든 기능은 플러그인 아키텍처를 사용하여 빌드됩니다(이름이 바뀐 이유가 납득되시죠?). 이때 제기된 문제는 어떤 사람들에게는 그 이면에 있는 아키텍처 모델이 난해하다는 것이었습니다. Ktor 2.0에서는 확장성 API를 대폭 간소화하여 플러그인을 훨씬 쉽게 만들 수 있도록 했습니다. 

1.x의 다음 API 코드를 살펴보세요.

companion object Feature : ApplicationFeature<ApplicationCallPipeline, CustomHeader.Configuration, CustomHeader> {
    override val key = AttributeKey<CustomHeader>("CustomPlugin")
    override fun install(pipeline: ApplicationCallPipeline, configure: Configuration.() -> Unit): CustomHeader {
       val configuration = Configuration().apply(configure)

       val feature = CustomHeader(configuration)

       pipeline.intercept(ApplicationCallPipeline.Call) {

            feature.intercept(this)
        }

       return feature
    }
}

2.0에서는 다음과 같이 바뀌었습니다.

val myCustomPlugin = createApplicationPlugin("CustomPlugin") {
    onCall {

    }

    onCallReceive {

    }

    onCallRespond {

    }
}

기존 플러그인의 대부분은 새 API를 사용하도록 변환되었으며 대부분의 상황을 포괄할 수 있을 것으로 확신합니다. 자세한 내용은 이전 API에서 API로의 ‘CustomHeader’ 플러그인 변환과 플러그인 개발 문서를 확인하세요.

향후 마켓플레이스에서 플러그인을 쉽게 게시하고 사용할 수 있는 기능 등 확장성과 관련하여 훨씬 더 많은 것이 준비될 예정입니다. 

Native 지원

이제 서버 측에서 GraalVM(이미 1.6부터 지원됨) 외에 Kotlin/Native를 지원하여, 독립형 서버 애플리케이션과 관련하여 두 가지 옵션이 제공됩니다. 

현재 Kotin/Native 지원은 CIO를 엔진으로 사용하는 것으로 제한되어 있으며 성능 개선을 위한 노력을 계속하고 있습니다. 단, 새로운 Kotlin/Native 메모리 모델을 사용할 것을 강력히 권장합니다. 

기타 서버 개선 사항

또한 무작위 포트 지원을 포함하여 Ktor 서버와 관련한 일련의 부수적인 개선이 이루어졌습니다.

fun main() {
    embeddedServer(Netty, port = 0) {
        configureRouting()
    }.start(wait = true)
}

뿐만 아니라 테스트 API 개선, Type-safe 라우팅, XML 직렬화, 플러그인용 하위 경로, 60개 이상의 버그 수정 및 기타 기능이 도입되었습니다. 

Ktor 클라이언트

간소화된 API

API의 단순화 작업을 계속하여, Ktor 클라이언트의 경우 일반적인 HTTP 요청을 처리하는 새로운 API를 도입했습니다.

val result = client.post("http://127.0.0.1:$port/") {

}
result.bodyAsText()

제네릭 post<T>, get<T> 메서드를 없앴습니다. 이제 본문(‘bodyAsText’, ‘bodyAsChannel’ 포함)뿐만 아니라 헤더에도 액세스할 수 있는 ‘HttpResponse’를 모두 반환합니다.

재시도

이제 재시도 사이의 시간 조정을 포함하여 재시도에 대한 지원이 기본 제공됩니다.

val client = HttpClient(CIO) {
    install(HttpRequestRetry) {
        maxRetries = 5
        retryIf { request, response ->
            !response.status.isSuccess()
        }
        retryOnExceptionIf { _, cause ->
            cause is NetworkError
        }
        delayMillis { retry ->
            retry * 3000L
        } // retries in 3, 6, 9, etc. seconds
    }
}

콘텐츠 협상

서버에서 콘텐츠 협상 기능을 사용해 왔다면 이것이 무엇이며 어떻게 작동하는지 이미 잘 알고 있을 것입니다. 이는 기본적으로 클라이언트와 서버가 요청하고 제공할 수 있는 다양한 유형의 콘텐츠를 협상하는 기능입니다. 이와 관련된 협상 측면은 지금까지 서버에서만 사용할 수 있었지만 이제 클라이언트에서도 가능해졌습니다!

val client = HttpClient(CIO) {
    install(ContentNegotiation) {
    }
}

이 플러그인은 ‘JsonFeature’를 효과적으로 대체했습니다. 

기타 클라이언트 개선 사항

위의 내용 외에도 클라이언트에는 ‘basic()’ 및 ‘bearer()’ 헬퍼 기능과 같은 인증을 위한 바로가기 API뿐만 아니라 요청 수준의 인터셉터, 새로운 메트릭 플러그인, XML 직렬화 및 많은 버그 수정과 기타 기능도 포함되어 있습니다.

Ktor 2.0으로 마이그레이션

Ktor와 관련된 한 가지 문제는 모듈과 패키지 이름이 일치하지 않는다는 것이었습니다. 일부에는 접두사 server가 있었고 일부에는 없었습니다. 일부는 서버와 클라이언트에서 작동했지만 접두사는 전혀 없었습니다. 또한 단일 모듈에 여러 플러그인이 있어서 검색이 번거로웠습니다. 

하지만 주요 버전으로 변경하면서 모듈 및 패키지와 관련하여 일관된 명명 규칙을 도입했습니다. 앞으로는 서버에만 관련된 모든 항목에 server 접두사가 붙게 됩니다. 클라이언트의 경우에는 client 접두사가 붙습니다. 일반 패키지에는 접두사가 붙지 않습니다. 또한 플러그인은 이제 자체 모듈에 포함됩니다. 

import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.content.*
import io.ktor.util.*
import io.ktor.utils.io.*

모듈 이름도 마찬가지입니다. 

implementation "io.ktor:ktor-server-auth:$ktor_version"
implementation "io.ktor:ktor-server-default-headers:$ktor_version"
implementation "io.ktor:ktor-server-sessions:$ktor_version"
implementation "io.ktor:ktor-server-status-pages:$ktor_version"
implementation "io.ktor:ktor-server-cors:$ktor_version"
implementation "io.ktor:ktor-server-conditional-headers:$ktor_version"

마이그레이션을 돕기 위해 매핑 문서뿐만 아니라 IntelliJ IDEA와 함께 Ktor 프로젝트의 자동 마이그레이션을 시도하는 마이그레이션 도구도 제공합니다(단, Kotlin Multiplatform 프로젝트는 현재 지원되지 않음).

Kotlin 1.6.20 지원 및 최신 문서

Kotlin의 최신 릴리스를 사용하는 분들은 Ktor 2.0이 1.6.20과 호환된다는 점을 알아두세요. 또한 모든 변경 사항에 빠르게 익숙해질 수 있도록 Ktor에 대한 문서 작업을 계속하고 있습니다. 앞으로 API 문서 개선을 위한 노력도 기울일 예정입니다. 

2.0 버전의 전체 기능 목록은 변경 로그를 확인하세요. 그리고 오늘 바로 첫 번째 Ktor 2.0을 만들어보세요

게시물 원문 작성자

Jessie Cho

Hadi Hariri