Skip to content

1.6.xから2.0.xへの移行

このガイドでは、Ktorアプリケーションを1.6.xバージョンから2.0.xへ移行するための手順について説明します。

Ktorサーバー

サーバーコードが 'io.ktor.server.*' パッケージに移動しました

サーバーとクライアントのAPIを統一し、より明確に区別するため、サーバーコードは io.ktor.server.* パッケージに移動されました (KTOR-2865)。 これにより、以下に示すように、アプリケーションの依存関係インポートを更新する必要があります。

依存関係

サブシステム1.6.x2.0.0
Locationsio.ktor:ktor-locationsio.ktor:ktor-server-locations
Webjarsio.ktor:ktor-webjarsio.ktor:ktor-server-webjars
AutoHeadResponseio.ktor:ktor-server-coreio.ktor:ktor-server-auto-head-response
StatusPagesio.ktor:ktor-server-coreio.ktor:ktor-server-status-pages
CallIdio.ktor:ktor-server-coreio.ktor:ktor-server-call-id
DoubleReceiveio.ktor:ktor-server-coreio.ktor:ktor-server-double-receive
HTML DSLio.ktor:ktor-html-builderio.ktor:ktor-server-html-builder
FreeMarkerio.ktor:ktor-freemarkerio.ktor:ktor-server-freemarker
Velocityio.ktor:ktor-velocityio.ktor:ktor-server-velocity
Mustacheio.ktor:ktor-mustacheio.ktor:ktor-server-mustache
Thymeleafio.ktor:ktor-thymeleafio.ktor:ktor-server-thymeleaf
Pebbleio.ktor:ktor-pebbleio.ktor:ktor-server-pebble
kotlinx.serializationio.ktor:ktor-serializationio.ktor:ktor-server-content-negotiation, io.ktor:ktor-serialization-kotlinx-json
Gsonio.ktor:ktor-gsonio.ktor:ktor-server-content-negotiation, io.ktor:ktor-serialization-gson
Jacksonio.ktor:ktor-jacksonio.ktor:ktor-server-content-negotiation, io.ktor:ktor-serialization-jackson
Authenticationio.ktor:ktor-authio.ktor:ktor-server-auth
JWT authenticationio.ktor:ktor-auth-jwtio.ktor:ktor-server-auth-jwt
LDAP authenticationio.ktor:ktor-auth-ldapio.ktor:ktor-server-auth-ldap
DataConversionio.ktor:ktor-server-coreio.ktor:ktor-server-data-conversion
DefaultHeadersio.ktor:ktor-server-coreio.ktor:ktor-server-default-headers
Compressionio.ktor:ktor-server-coreio.ktor:ktor-server-compression
CachingHeadersio.ktor:ktor-server-coreio.ktor:ktor-server-caching-headers
ConditionalHeadersio.ktor:ktor-server-coreio.ktor:ktor-server-conditional-headers
CORSio.ktor:ktor-server-coreio.ktor:ktor-server-cors
Forwarded headersio.ktor:ktor-server-coreio.ktor:ktor-server-forwarded-header
HSTSio.ktor:ktor-server-coreio.ktor:ktor-server-hsts
HttpsRedirectio.ktor:ktor-server-coreio.ktor:ktor-server-http-redirect
PartialContentio.ktor:ktor-server-coreio.ktor:ktor-server-partial-content
WebSocketsio.ktor:ktor-websocketsio.ktor:ktor-server-websockets
CallLoggingio.ktor:ktor-server-coreio.ktor:ktor-server-call-logging
Micrometer metricio.ktor:ktor-metrics-micrometerio.ktor:ktor-server-metrics-micrometer
Dropwizard metricsio.ktor:ktor-metricsio.ktor:ktor-server-metrics
Sessionsio.ktor:ktor-server-coreio.ktor:ktor-server-sessions

すべてのプラグインを一度に追加するには、io.ktor:ktor-server アーティファクトを使用できます。

インポート

サブシステム1.6.x2.0.0
Applicationimport io.ktor.application.*import io.ktor.server.application.*
Configurationimport io.ktor.config.*import io.ktor.server.config.*
Routingimport io.ktor.routing.*import io.ktor.server.routing.*
AutoHeadResponseimport io.ktor.features.*import io.ktor.server.plugins.autohead.*
StatusPagesimport io.ktor.features.*import io.ktor.server.plugins.statuspages.*
CallIdimport io.ktor.features.*import io.ktor.server.plugins.callid.*
DoubleReceiveimport io.ktor.features.*import io.ktor.server.plugins.doublereceive.*
Requestsimport io.ktor.request.*import io.ktor.server.request.*
Responsesimport io.ktor.response.*import io.ktor.server.response.*
Pluginsimport io.ktor.features.*import io.ktor.server.plugins.*
Locationsimport io.ktor.locations.*import io.ktor.server.locations.*
Static contentimport io.ktor.http.content.*import io.ktor.server.http.content.*
HTML DSLimport io.ktor.html.*import io.ktor.server.html.*
FreeMarkerimport io.ktor.freemarker.*import io.ktor.server.freemarker.*
Velocityimport io.ktor.velocity.*import io.ktor.server.velocity.*
Mustacheimport io.ktor.mustache.*import io.ktor.server.mustache.*
Thymeleafimport io.ktor.thymeleaf.*import io.ktor.server.thymeleaf.*
Pebbleimport io.ktor.pebble.*import io.ktor.server.pebble.*
ContentNegotiationimport io.ktor.features.*import io.ktor.server.plugins.contentnegotiation.*
kotlinx.serializationimport io.ktor.serialization.*import io.ktor.serialization.kotlinx.json.*
Gsonimport io.ktor.gson.*import io.ktor.serialization.gson.*
Jacksonimport io.ktor.jackson.*import io.ktor.serialization.jackson.*
Authenticationimport io.ktor.auth.*import io.ktor.server.auth.*
JWT authenticationimport io.ktor.auth.jwt.*import io.ktor.server.auth.jwt.*
LDAP authenticationimport io.ktor.auth.ldap.*import io.ktor.server.auth.ldap.*
Sessionsimport io.ktor.sessions.*import io.ktor.server.sessions.*
DefaultHeadersimport io.ktor.features.*import io.ktor.server.plugins.defaultheaders.*
Compressionimport io.ktor.features.*import io.ktor.server.plugins.compression.*
CachingHeadersimport io.ktor.features.*import io.ktor.server.plugins.cachingheaders.*
ConditionalHeadersimport io.ktor.features.*import io.ktor.server.plugins.conditionalheaders.*
CORSimport io.ktor.features.*import io.ktor.server.plugins.cors.*
Forwarded headersimport io.ktor.features.*import io.ktor.server.plugins.forwardedheaders.*
HSTSimport io.ktor.features.*import io.ktor.server.plugins.hsts.*
HttpsRedirectimport io.ktor.features.*import io.ktor.server.plugins.httpsredirect.*
PartialContentimport io.ktor.features.*import io.ktor.server.plugins.partialcontent.*
WebSocketsimport io.ktor.websocket.*import io.ktor.server.websocket.*
CallLoggingimport io.ktor.features.*import io.ktor.server.plugins.callloging.*
Micrometer metricimport io.ktor.metrics.micrometer.*import io.ktor.server.metrics.micrometer.*
Dropwizard metricsimport io.ktor.metrics.dropwizard.*import io.ktor.server.metrics.dropwizard.*

WebSocketsのコードが 'websockets' パッケージに移動しました

WebSocketsのコードは http-cio から websockets パッケージに移動されました。これにより、以下のようにインポートを更新する必要があります。

1.6.x2.0.0
import io.ktor.http.cio.websocket.*import io.ktor.websocket.*

この変更はクライアントにも影響することに注意してください。

FeatureがPluginに名称変更されました

Ktor 2.0.0では、リクエスト/レスポンスのパイプラインをインターセプトする機能をより適切に表現するため、FeaturePlugin に名称変更されました (KTOR-2326)。 これはKtor API全体に影響し、以下で説明するようにアプリケーションを更新する必要があります。

インポート

プラグインのインストールにはインポートの更新が必要であり、サーバーコードの移動io.ktor.server.* パッケージへの移動)にも依存します。

1.6.x2.0.0
import io.ktor.features.*import io.ktor.server.plugins.*

カスタムプラグイン

FeatureからPluginへの名称変更に伴い、カスタムプラグインに関連するAPIで以下の変更が導入されました。

  • ApplicationFeature インターフェースは BaseApplicationPlugin に名称変更されました。
  • Features パイプラインフェーズPlugins に名称変更されました。

v2.0.0以降、Ktorはカスタムプラグインを作成するための新しいAPIを提供しています。一般的に、この新しいAPIではパイプラインやフェーズなどのKtor内部の概念を理解する必要はありません。代わりに、onCallonCallReceiveonCallRespond などの様々なハンドラーを使用して、リクエストとレスポンスを処理する異なるステージにアクセスできます。パイプラインフェーズが新しいAPIのハンドラーにどのようにマッピングされるかは、こちらのセクションで確認できます:パイプラインフェーズの新しいAPIハンドラーへのマッピング

コンテンツネゴシエーションとシリアライゼーション

コンテンツネゴシエーションとシリアライゼーションのサーバーAPIは、サーバーとクライアントの間でシリアライゼーションライブラリを再利用できるようにリファクタリングされました。 主な変更点は以下の通りです。

  • ContentNegotiationktor-server-core から独立した ktor-server-content-negotiation アーティファクトに移動されました。
  • シリアライゼーションライブラリは ktor-* から、クライアントでも使用される ktor-serialization-* アーティファクトに移動されました。

以下に示すように、アプリケーションの依存関係インポートを更新する必要があります。

依存関係

サブシステム1.6.x2.0.0
ContentNegotiationio.ktor:ktor-server-coreio.ktor:ktor-server-content-negotiation
kotlinx.serializationio.ktor:ktor-serializationio.ktor:ktor-serialization-kotlinx-json
Gsonio.ktor:ktor-gsonio.ktor:ktor-serialization-gson
Jacksonio.ktor:ktor-jacksonio.ktor:ktor-serialization-jackson

インポート

サブシステム1.6.x2.0.0
kotlinx.serializationimport io.ktor.serialization.*import io.ktor.serialization.kotlinx.json.*
Gsonimport io.ktor.gson.*import io.ktor.serialization.gson.*
Jacksonimport io.ktor.jackson.*import io.ktor.serialization.jackson.*

カスタムコンバーター

ContentConverter インターフェースによって公開される関数のシグネチャが次のように変更されました。

kotlin
interface ContentConverter {
    suspend fun convertForSend(context: PipelineContext<Any, ApplicationCall>, contentType: ContentType, value: Any): Any?
    suspend fun convertForReceive(context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): Any?
}
kotlin
interface ContentConverter {
    suspend fun serialize(contentType: ContentType, charset: Charset, typeInfo: TypeInfo, value: Any): OutgoingContent?
    suspend fun deserialize(charset: Charset, typeInfo: TypeInfo, content: ByteReadChannel): Any?
}

テストAPI

v2.0.0より、Ktorサーバーはテスト用の新しいAPIを使用します。これにより KTOR-971 で説明されている様々な問題が解決されます。主な変更点は以下の通りです。

  • withTestApplication/withApplication 関数は、新しい testApplication 関数に置き換えられました。
  • testApplication 関数の内部では、既存の Ktorクライアント インスタンスを使用してサーバーにリクエストを送信し、結果を検証する必要があります。
  • 特定の機能(CookieやWebSocketsなど)をテストするには、新しいクライアントインスタンスを作成し、対応するプラグインをインストールする必要があります。

1.6.xのテストを2.0.0に移行するいくつかの例を見てみましょう。

基本的なサーバーテスト

以下のテストでは、handleRequest 関数が client.get リクエストに置き換えられています。

kotlin
@Test
fun testRootLegacyApi() {
    withTestApplication(Application::module) {
        handleRequest(HttpMethod.Get, "/").apply {
            assertEquals(HttpStatusCode.OK, response.status())
            assertEquals("Hello, world!", response.content)
        }
    }
}
kotlin
@Test
fun testRoot() = testApplication {
    val response = client.get("/")
    assertEquals(HttpStatusCode.OK, response.status)
    assertEquals("Hello, world!", response.bodyAsText())
}

x-www-form-urlencoded

以下のテストでは、handleRequest 関数が client.post リクエストに置き換えられています。

kotlin
@Test
fun testPostLegacyApi() = withTestApplication(Application::main) {
    with(handleRequest(HttpMethod.Post, "/signup"){
        addHeader(HttpHeaders.ContentType, ContentType.Application.FormUrlEncoded.toString())
        setBody(listOf("username" to "JetBrains", "email" to "[email protected]", "password" to "foobar", "confirmation" to "foobar").formUrlEncode())
    }) {
        assertEquals("The 'JetBrains' account is created", response.content)
    }
}
kotlin
@Test
fun testPost() = testApplication {
    val response = client.post("/signup") {
        header(HttpHeaders.ContentType, ContentType.Application.FormUrlEncoded.toString())
        setBody(listOf("username" to "JetBrains", "email" to "[email protected]", "password" to "foobar", "confirmation" to "foobar").formUrlEncode())
    }
    assertEquals("The 'JetBrains' account is created", response.bodyAsText())
}

multipart/form-data

v2.0.0で multipart/form-data を構築するには、クライアントの setBody 関数に MultiPartFormDataContent を渡す必要があります。

kotlin
    @Test
    fun testUploadLegacyApi() = withTestApplication(Application::main) {
        with(handleRequest(HttpMethod.Post, "/upload"){
            val boundary = "WebAppBoundary"
            val fileBytes = File("ktor_logo.png").readBytes()

            addHeader(HttpHeaders.ContentType, ContentType.MultiPart.FormData.withParameter("boundary", boundary).toString())
            setBody(boundary, listOf(
                PartData.FormItem("Ktor logo", { }, headersOf(
                    HttpHeaders.ContentDisposition,
                    ContentDisposition.Inline
                        .withParameter(ContentDisposition.Parameters.Name, "description")
                        .toString()
                )),
                PartData.FileItem({ fileBytes.inputStream().asInput() }, {}, headersOf(
                    HttpHeaders.ContentDisposition,
                    ContentDisposition.File
                        .withParameter(ContentDisposition.Parameters.Name, "image")
                        .withParameter(ContentDisposition.Parameters.FileName, "ktor_logo.png")
                        .toString()
                ))
            ))
        }) {
            assertEquals("Ktor logo is uploaded to 'uploads/ktor_logo.png'", response.content)
        }
    }
kotlin
@Test
fun testUpload() = testApplication {
    val boundary = "WebAppBoundary"
    val response = client.post("/upload") {
        setBody(
            MultiPartFormDataContent(
                formData {
                    append("description", "Ktor logo")
                    append("image", File("ktor_logo.png").readBytes(), Headers.build {
                        append(HttpHeaders.ContentType, "image/png")
                        append(HttpHeaders.ContentDisposition, "filename=\"ktor_logo.png\"")
                    })
                },
                boundary,
                ContentType.MultiPart.FormData.withParameter("boundary", boundary)
            )
        )
    }
    assertEquals("Ktor logo is uploaded to 'uploads/ktor_logo.png'", response.bodyAsText())
}

JSONデータ

v1.6.xでは、kotlinx.serialization ライブラリが提供する Json.encodeToString 関数を使用してJSONデータをシリアライズできました。 v2.0.0では、新しいクライアントインスタンスを作成し、特定の形式でコンテンツをシリアライズ/デシリアライズできるようにする ContentNegotiation プラグインをインストールする必要があります。

kotlin
@Test
fun testPostCustomerLegacyApi() = withTestApplication(Application::main) {
    with(handleRequest(HttpMethod.Post, "/customer"){
        addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
        setBody(Json.encodeToString(Customer(3, "Jet", "Brains")))
    }) {
        assertEquals("Customer stored correctly", response.content)
        assertEquals(HttpStatusCode.Created, response.status())
    }
}
kotlin
@Test
fun testPostCustomer() = testApplication {
    val client = createClient {
        install(ContentNegotiation) {
            json()
        }
    }
    val response = client.post("/customer") {
        contentType(ContentType.Application.Json)
        setBody(Customer(3, "Jet", "Brains"))
    }
    assertEquals("Customer stored correctly", response.bodyAsText())
    assertEquals(HttpStatusCode.Created, response.status)
}

テスト中のCookieの保持

v1.6.xでは、テスト時にリクエスト間でCookieを保持するために cookiesSession が使用されていました。v2.0.0では、新しいクライアントインスタンスを作成し、HttpCookies プラグインをインストールする必要があります。

kotlin
    @Test
    fun testRequestsLegacyApi() = withTestApplication(Application::main) {
        fun doRequestAndCheckResponse(path: String, expected: String) {
            handleRequest(HttpMethod.Get, path).apply {
                assertEquals(expected, response.content)
            }
        }

        cookiesSession {
            handleRequest(HttpMethod.Get, "/login") {}.apply {}
            doRequestAndCheckResponse("/user", "Session ID is 123abc. Reload count is 0.")
            doRequestAndCheckResponse("/user", "Session ID is 123abc. Reload count is 1.")
            doRequestAndCheckResponse("/user", "Session ID is 123abc. Reload count is 2.")

            handleRequest(HttpMethod.Get, "/logout").apply {}
            doRequestAndCheckResponse("/user", "Session doesn't exist or is expired.")
        }
    }
kotlin
    @Test
    fun testRequests() = testApplication {
        val client = createClient {
            install(HttpCookies)
        }

        val loginResponse = client.get("/login")
        val response1 = client.get("/user")
        assertEquals("Session ID is 123abc. Reload count is 1.", response1.bodyAsText())
        val response2 = client.get("/user")
        assertEquals("Session ID is 123abc. Reload count is 2.", response2.bodyAsText())
        val response3 = client.get("/user")
        assertEquals("Session ID is 123abc. Reload count is 3.", response3.bodyAsText())
        val logoutResponse = client.get("/logout")
        assertEquals("Session doesn't exist or is expired.", logoutResponse.bodyAsText())
    }

WebSockets

旧APIでは、WebSocketの対話をテストするために handleWebSocketConversation が使用されていました。v2.0.0では、クライアントが提供する WebSockets プラグインを使用することで、WebSocketの対話をテストできます。

kotlin
    @Test
    fun testConversationLegacyApi() {
        withTestApplication(Application::module) {
            handleWebSocketConversation("/echo") { incoming, outgoing ->
                val greetingText = (incoming.receive() as Frame.Text).readText()
                assertEquals("Please enter your name", greetingText)

                outgoing.send(Frame.Text("JetBrains"))
                val responseText = (incoming.receive() as Frame.Text).readText()
                assertEquals("Hi, JetBrains!", responseText)
            }
        }
    }
kotlin
    @Test
    fun testConversation() {
        testApplication {
            val client = createClient {
                install(WebSockets)
            }

            client.webSocket("/echo") {
                val greetingText = (incoming.receive() as? Frame.Text)?.readText() ?: ""
                assertEquals("Please enter your name", greetingText)

                send(Frame.Text("JetBrains"))
                val responseText = (incoming.receive() as Frame.Text).readText()
                assertEquals("Hi, JetBrains!", responseText)
            }
        }
    }

DoubleReceive

v2.0.0では、DoubleReceive プラグインの設定に cacheRawRequest プロパティが導入されました。これは receiveEntireContent とは逆の意味を持ちます。

  • v1.6.xでは、receiveEntireContent プロパティのデフォルトは false です。
  • v2.0.0では、cacheRawRequest のデフォルトは true です。receiveEntireContent プロパティは削除されました。

Forwarded headers

v2.0.0では、ForwardedHeaderSupport および XForwardedHeaderSupport プラグインは、それぞれ ForwardedHeaders および XForwardedHeaders に名称変更されました。

Caching headers

キャッシュオプションを定義するために使用される options 関数は、OutgoingContent に加えて、ラムダ引数として ApplicationCall を受け取るようになりました。

kotlin
install(CachingHeaders) {
    options { outgoingContent ->
        // ...
    }
}
kotlin
install(CachingHeaders) {
    options { call, outgoingContent ->
        // ...
    }
}

Conditional headers

リソースバージョンのリストを定義するために使用される version 関数は、OutgoingContent に加えて、ラムダ引数として ApplicationCall を受け取るようになりました。

kotlin
install(ConditionalHeaders) {
    version { outgoingContent ->
        // ... 
    }
}
kotlin
install(ConditionalHeaders) {
    version { call, outgoingContent ->
        // ... 
    }
}

CORS

CORS 設定で使用されるいくつかの関数が名称変更されました。

  • host -> allowHost
  • header -> allowHeader
  • method -> allowMethod
kotlin
install(CORS) {
    host("0.0.0.0:5000")
    header(HttpHeaders.ContentType)
    method(HttpMethod.Options)
}
kotlin
install(CORS) {
    allowHost("0.0.0.0:5000")
    allowHeader(HttpHeaders.ContentType)
    allowMethod(HttpMethod.Options)
}

MicrometerMetrics

v1.6.xでは、HTTPリクエストの監視に使用される Ktorメトリクス のベース名(プレフィックス)を指定するために baseName プロパティが使用されていました。 デフォルトでは ktor.http.server と等しくなっています。 v2.0.0では、baseNamemetricName に置き換えられ、そのデフォルト値は ktor.http.server.requests となりました。

Ktorクライアント

リクエストとレスポンス

v2.0.0では、リクエストの送信とレスポンスの受信に使用されるAPIが、より一貫性があり見つけやすいものに更新されました (KTOR-29)。

リクエスト関数

複数のパラメータを持つリクエスト関数は非推奨になりました。例えば、port および path パラメータは、HttpRequestBuilder によって公開される url パラメータに置き換える必要があります。

kotlin
client.get(port = 8080, path = "/customer/3")
kotlin
client.get { url(port = 8080, path = "/customer/3") }

HttpRequestBuilder では、リクエスト関数のラムダ内で追加のリクエストパラメータを指定することもできます。

リクエストボディ

リクエストボディを設定するために使用されていた HttpRequestBuilder.body プロパティは、HttpRequestBuilder.setBody 関数に置き換えられました。

kotlin
client.post("http://localhost:8080/post") {
    body = "Body content"
}
kotlin
client.post("http://localhost:8080/post") {
    setBody("Body content")
}

レスポンス

v2.0.0では、リクエスト関数(getpostputsubmitFormなど)は、特定の型のオブジェクトを受信するためのジェネリック引数を受け取らなくなりました。 現在、すべてのリクエスト関数は HttpResponse オブジェクトを返し、このオブジェクトが特定の型のインスタンスを受信するためのジェネリック引数を持つ body 関数を公開しています。 また、bodyAsTextbodyAsChannel を使用して、コンテンツを文字列やチャネルとして受信することもできます。

kotlin
val httpResponse: HttpResponse = client.get("https://ktor.io/")
val stringBody: String = httpResponse.receive()
val byteArrayBody: ByteArray = httpResponse.receive()
kotlin
val httpResponse: HttpResponse = client.get("https://ktor.io/")
val stringBody: String = httpResponse.body()
val byteArrayBody: ByteArray = httpResponse.body()

ContentNegotiation プラグインがインストールされている場合、次のように任意のオブジェクトを受信できます。

kotlin
val customer: Customer = client.get("http://localhost:8080/customer/3")
kotlin
val customer: Customer = client.get("http://localhost:8080/customer/3").body()

ストリーミングレスポンス

リクエスト関数からジェネリック引数が削除されたため、ストリーミングレスポンスを受信するには別の関数が必要になります。 これを実現するために、prepareGetpreparePost などの prepare プレフィックスが付いた関数が追加されました。

kotlin
public suspend fun HttpClient.prepareGet(builder: HttpRequestBuilder): HttpStatement
public suspend fun HttpClient.preparePost(builder: HttpRequestBuilder): HttpStatement

以下の例は、この場合のコードの変更方法を示しています。

kotlin
client.get<HttpStatement>("https://ktor.io/").execute { httpResponse ->
    val channel: ByteReadChannel = httpResponse.receive()
    while (!channel.isClosedForRead) {
        // データの読み込み
    }
}
kotlin
client.prepareGet("https://ktor.io/").execute { httpResponse ->
    val channel: ByteReadChannel = httpResponse.body()
    while (!channel.isClosedForRead) {
        // データの読み込み
    }
}

完全な例はこちらにあります:データのストリーミング

レスポンスの検証

v2.0.0では、レスポンスの検証に使用される expectSuccess プロパティがデフォルトで false に設定されています。 これにより、コードに以下の変更が必要になります。

  • デフォルトの検証を有効化し、2xx以外のレスポンスに対して例外をスローするには、expectSuccess プロパティを true に設定します。
  • handleResponseExceptionWithRequest を使用して 2xx以外の例外を処理 する場合も、明示的に expectSuccess を有効にする必要があります。

HttpResponseValidator

handleResponseException 関数は handleResponseExceptionWithRequest に置き換えられました。これにより、例外で追加情報を提供するために HttpRequest へのアクセスが可能になります。

kotlin
HttpResponseValidator {
    handleResponseException { exception ->
        // ...
    }
}
kotlin
HttpResponseValidator {
    handleResponseExceptionWithRequest { exception, request ->
        // ...
    }
}

コンテンツネゴシエーションとシリアライゼーション

Ktorクライアントはコンテンツネゴシエーションをサポートし、Ktorサーバーとシリアライゼーションライブラリを共有するようになりました。 主な変更点は以下の通りです。

  • JsonFeature は非推奨となり、ktor-client-content-negotiation アーティファクトにある ContentNegotiation に置き換えられました。
  • シリアライゼーションライブラリは ktor-client-* から ktor-serialization-* アーティファクトに移動されました。

以下に示すように、クライアントコードの依存関係インポートを更新する必要があります。

依存関係

サブシステム1.6.x2.0.0
ContentNegotiationなしio.ktor:ktor-client-content-negotiation
kotlinx.serializationio.ktor:ktor-client-serializationio.ktor:ktor-serialization-kotlinx-json
Gsonio.ktor:ktor-client-gsonio.ktor:ktor-serialization-gson
Jacksonio.ktor:ktor-client-jacksonio.ktor:ktor-serialization-jackson

インポート

サブシステム1.6.x2.0.0
ContentNegotiationなしimport io.ktor.client.plugins.contentnegotiation.*
kotlinx.serializationimport io.ktor.client.features.json.*import io.ktor.serialization.kotlinx.json.*
Gsonimport io.ktor.client.features.json.*import io.ktor.serialization.gson.*
Jacksonimport io.ktor.client.features.json.*import io.ktor.serialization.jackson.*

Bearer認証

refreshTokens 関数は、HttpResponse ラムダ引数(it)の代わりに、ラムダレシーバーthis)として RefreshTokenParams インスタンスを使用するようになりました。

kotlin
bearer {
    refreshTokens {  // it: HttpResponse
        // ...
    }
}
kotlin
bearer {
    refreshTokens { // this: RefreshTokenParams
        // ...
    }
}

RefreshTokenParams は以下のプロパティを公開しています。

  • response: レスポンスパラメータへのアクセス用
  • client: トークンをリフレッシュするためのリクエスト送信可能
  • oldTokens: loadTokens を使用して取得されたトークンへのアクセス用

HttpSend

HttpSend プラグインのAPIが以下のように変更されました。

kotlin
client[HttpSend].intercept { originalCall, request ->
    if (originalCall.something()) {
        val newCall = execute(request)
        // ...
    }
}
kotlin
client.plugin(HttpSend).intercept { request ->
    val originalCall = execute(request)
    if (originalCall.something()) {
        val newCall = execute(request)
        // ...
    }
}

v2.0.0では、プラグインへのアクセスにインデックスアクセスは利用できないことに注意してください。代わりに HttpClient.plugin 関数を使用してください。

HttpClient.get(plugin: HttpClientPlugin) 関数が削除されました

バージョン2.0.0では、クライアントプラグインを受け取る HttpClient.get 関数が削除されました。代わりに HttpClient.plugin 関数を使用してください。

kotlin
client.get(HttpSend).intercept { ... }
// または
client[HttpSend].intercept { ... }
kotlin
client.plugin(HttpSend).intercept { ... }

FeatureがPluginに名称変更されました

Ktorサーバーと同様に、クライアントAPIにおいても FeaturePlugin に名称変更されました。 これにより、以下で説明するようにアプリケーションに影響を与える可能性があります。

インポート

プラグインのインストールのためのインポートを更新します。

サブシステム1.6.x2.0.0
  • Default request
    The DefaultRequest plugin allows you to configure default parameters for all requests.
  • User agent
    undefined
  • Charsets
    undefined
  • Response validation
    Learn how to validate a response depending on its status code.
  • Timeout
    Code example: %example_name%
  • HttpCache
    The HttpCache plugin allows you to save previously fetched resources in an in-memory or persistent cache.
  • HttpSend
    Code example: %example_name%
import io.ktor.client.features.*import io.ktor.client.plugins.*
Authentication
The Auth plugin handles authentication and authorization in your client application.
import io.ktor.client.features.auth.* import io.ktor.client.features.auth.providers.* import io.ktor.client.plugins.auth.* import io.ktor.client.plugins.auth.providers.*
Cookies
The HttpCookies plugin handles cookies automatically and keep them between calls in a storage.
import io.ktor.client.features.cookies.*import io.ktor.client.plugins.cookies.*
Logging
Required dependencies: io.ktor:ktor-client-logging Code example: %example_name%
import io.ktor.client.features.logging.*import io.ktor.client.plugins.logging.*
WebSockets
The Websockets plugin allows you to create a multi-way communication session between a server and a client.
import io.ktor.client.features.websocket.*import io.ktor.client.plugins.websocket.*
Content encoding
The ContentEncoding plugin allows you to enable specified compression algorithms (such as 'gzip' and 'deflate') and configure their settings.
import io.ktor.client.features.compression.*import io.ktor.client.plugins.compression.*

カスタムプラグイン

HttpClientFeature インターフェースは HttpClientPlugin に名称変更されました。

Nativeターゲット用の新しいメモリモデル

v2.0.0では、Native ターゲットでKtorクライアントを使用するには、新しいKotlin/Nativeメモリモデルを有効にする必要があります:新しいMMを有効にする

v2.2.0以降、新しいKotlin/Nativeメモリモデルはデフォルトで有効になっています。

'Ios' エンジンが 'Darwin' に名称変更されました

Ios エンジンはiOSだけでなく、macOSやtvOSなどの他のオペレーティングシステムもターゲットとしているため、v2.0.0で Darwin に名称変更されました。これに伴い、以下の変更が発生します。

  • io.ktor:ktor-client-ios アーティファクトは io.ktor:ktor-client-darwin に名称変更されました。
  • HttpClient インスタンスを作成するには、引数として Darwin クラスを渡す必要があります。
  • IosClientEngineConfig 設定クラスは DarwinClientEngineConfig に名称変更されました。

Darwin エンジンの設定方法については、Darwin セクションを参照してください。

WebSocketsのコードが 'websockets' パッケージに移動しました

WebSocketsのコードは http-cio から websockets パッケージに移動されました。これにより、以下のようにインポートを更新する必要があります。

1.6.x2.0.0
import io.ktor.http.cio.websocket.*import io.ktor.websocket.*

デフォルトリクエスト

DefaultRequest プラグインは、HttpRequestBuilder の代わりに DefaultRequestBuilder 設定クラスを使用するようになりました。

kotlin
val client = HttpClient(CIO) {
    defaultRequest {
        // this: HttpRequestBuilder
    }
}
kotlin
val client = HttpClient(CIO) {
    defaultRequest {
        // this: DefaultRequestBuilder
    }
}