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.x | 2.0.0 |
|---|---|---|
| Locations | io.ktor:ktor-locations | io.ktor:ktor-server-locations |
| Webjars | io.ktor:ktor-webjars | io.ktor:ktor-server-webjars |
| AutoHeadResponse | io.ktor:ktor-server-core | io.ktor:ktor-server-auto-head-response |
| StatusPages | io.ktor:ktor-server-core | io.ktor:ktor-server-status-pages |
| CallId | io.ktor:ktor-server-core | io.ktor:ktor-server-call-id |
| DoubleReceive | io.ktor:ktor-server-core | io.ktor:ktor-server-double-receive |
| HTML DSL | io.ktor:ktor-html-builder | io.ktor:ktor-server-html-builder |
| FreeMarker | io.ktor:ktor-freemarker | io.ktor:ktor-server-freemarker |
| Velocity | io.ktor:ktor-velocity | io.ktor:ktor-server-velocity |
| Mustache | io.ktor:ktor-mustache | io.ktor:ktor-server-mustache |
| Thymeleaf | io.ktor:ktor-thymeleaf | io.ktor:ktor-server-thymeleaf |
| Pebble | io.ktor:ktor-pebble | io.ktor:ktor-server-pebble |
| kotlinx.serialization | io.ktor:ktor-serialization | io.ktor:ktor-server-content-negotiation, io.ktor:ktor-serialization-kotlinx-json |
| Gson | io.ktor:ktor-gson | io.ktor:ktor-server-content-negotiation, io.ktor:ktor-serialization-gson |
| Jackson | io.ktor:ktor-jackson | io.ktor:ktor-server-content-negotiation, io.ktor:ktor-serialization-jackson |
| Authentication | io.ktor:ktor-auth | io.ktor:ktor-server-auth |
| JWT authentication | io.ktor:ktor-auth-jwt | io.ktor:ktor-server-auth-jwt |
| LDAP authentication | io.ktor:ktor-auth-ldap | io.ktor:ktor-server-auth-ldap |
| DataConversion | io.ktor:ktor-server-core | io.ktor:ktor-server-data-conversion |
| DefaultHeaders | io.ktor:ktor-server-core | io.ktor:ktor-server-default-headers |
| Compression | io.ktor:ktor-server-core | io.ktor:ktor-server-compression |
| CachingHeaders | io.ktor:ktor-server-core | io.ktor:ktor-server-caching-headers |
| ConditionalHeaders | io.ktor:ktor-server-core | io.ktor:ktor-server-conditional-headers |
| CORS | io.ktor:ktor-server-core | io.ktor:ktor-server-cors |
| Forwarded headers | io.ktor:ktor-server-core | io.ktor:ktor-server-forwarded-header |
| HSTS | io.ktor:ktor-server-core | io.ktor:ktor-server-hsts |
| HttpsRedirect | io.ktor:ktor-server-core | io.ktor:ktor-server-http-redirect |
| PartialContent | io.ktor:ktor-server-core | io.ktor:ktor-server-partial-content |
| WebSockets | io.ktor:ktor-websockets | io.ktor:ktor-server-websockets |
| CallLogging | io.ktor:ktor-server-core | io.ktor:ktor-server-call-logging |
| Micrometer metric | io.ktor:ktor-metrics-micrometer | io.ktor:ktor-server-metrics-micrometer |
| Dropwizard metrics | io.ktor:ktor-metrics | io.ktor:ktor-server-metrics |
| Sessions | io.ktor:ktor-server-core | io.ktor:ktor-server-sessions |
すべてのプラグインを一度に追加するには、
io.ktor:ktor-serverアーティファクトを使用できます。
インポート
| サブシステム | 1.6.x | 2.0.0 |
|---|---|---|
| Application | import io.ktor.application.* | import io.ktor.server.application.* |
| Configuration | import io.ktor.config.* | import io.ktor.server.config.* |
| Routing | import io.ktor.routing.* | import io.ktor.server.routing.* |
| AutoHeadResponse | import io.ktor.features.* | import io.ktor.server.plugins.autohead.* |
| StatusPages | import io.ktor.features.* | import io.ktor.server.plugins.statuspages.* |
| CallId | import io.ktor.features.* | import io.ktor.server.plugins.callid.* |
| DoubleReceive | import io.ktor.features.* | import io.ktor.server.plugins.doublereceive.* |
| Requests | import io.ktor.request.* | import io.ktor.server.request.* |
| Responses | import io.ktor.response.* | import io.ktor.server.response.* |
| Plugins | import io.ktor.features.* | import io.ktor.server.plugins.* |
| Locations | import io.ktor.locations.* | import io.ktor.server.locations.* |
| Static content | import io.ktor.http.content.* | import io.ktor.server.http.content.* |
| HTML DSL | import io.ktor.html.* | import io.ktor.server.html.* |
| FreeMarker | import io.ktor.freemarker.* | import io.ktor.server.freemarker.* |
| Velocity | import io.ktor.velocity.* | import io.ktor.server.velocity.* |
| Mustache | import io.ktor.mustache.* | import io.ktor.server.mustache.* |
| Thymeleaf | import io.ktor.thymeleaf.* | import io.ktor.server.thymeleaf.* |
| Pebble | import io.ktor.pebble.* | import io.ktor.server.pebble.* |
| ContentNegotiation | import io.ktor.features.* | import io.ktor.server.plugins.contentnegotiation.* |
| kotlinx.serialization | import io.ktor.serialization.* | import io.ktor.serialization.kotlinx.json.* |
| Gson | import io.ktor.gson.* | import io.ktor.serialization.gson.* |
| Jackson | import io.ktor.jackson.* | import io.ktor.serialization.jackson.* |
| Authentication | import io.ktor.auth.* | import io.ktor.server.auth.* |
| JWT authentication | import io.ktor.auth.jwt.* | import io.ktor.server.auth.jwt.* |
| LDAP authentication | import io.ktor.auth.ldap.* | import io.ktor.server.auth.ldap.* |
| Sessions | import io.ktor.sessions.* | import io.ktor.server.sessions.* |
| DefaultHeaders | import io.ktor.features.* | import io.ktor.server.plugins.defaultheaders.* |
| Compression | import io.ktor.features.* | import io.ktor.server.plugins.compression.* |
| CachingHeaders | import io.ktor.features.* | import io.ktor.server.plugins.cachingheaders.* |
| ConditionalHeaders | import io.ktor.features.* | import io.ktor.server.plugins.conditionalheaders.* |
| CORS | import io.ktor.features.* | import io.ktor.server.plugins.cors.* |
| Forwarded headers | import io.ktor.features.* | import io.ktor.server.plugins.forwardedheaders.* |
| HSTS | import io.ktor.features.* | import io.ktor.server.plugins.hsts.* |
| HttpsRedirect | import io.ktor.features.* | import io.ktor.server.plugins.httpsredirect.* |
| PartialContent | import io.ktor.features.* | import io.ktor.server.plugins.partialcontent.* |
| WebSockets | import io.ktor.websocket.* | import io.ktor.server.websocket.* |
| CallLogging | import io.ktor.features.* | import io.ktor.server.plugins.callloging.* |
| Micrometer metric | import io.ktor.metrics.micrometer.* | import io.ktor.server.metrics.micrometer.* |
| Dropwizard metrics | import io.ktor.metrics.dropwizard.* | import io.ktor.server.metrics.dropwizard.* |
WebSocketsのコードが 'websockets' パッケージに移動しました
WebSocketsのコードは http-cio から websockets パッケージに移動されました。これにより、以下のようにインポートを更新する必要があります。
| 1.6.x | 2.0.0 |
|---|---|
import io.ktor.http.cio.websocket.* | import io.ktor.websocket.* |
この変更はクライアントにも影響することに注意してください。
FeatureがPluginに名称変更されました
Ktor 2.0.0では、リクエスト/レスポンスのパイプラインをインターセプトする機能をより適切に表現するため、Feature は Plugin に名称変更されました (KTOR-2326)。 これはKtor API全体に影響し、以下で説明するようにアプリケーションを更新する必要があります。
インポート
プラグインのインストールにはインポートの更新が必要であり、サーバーコードの移動(io.ktor.server.* パッケージへの移動)にも依存します。
| 1.6.x | 2.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内部の概念を理解する必要はありません。代わりに、
onCall、onCallReceive、onCallRespondなどの様々なハンドラーを使用して、リクエストとレスポンスを処理する異なるステージにアクセスできます。パイプラインフェーズが新しいAPIのハンドラーにどのようにマッピングされるかは、こちらのセクションで確認できます:パイプラインフェーズの新しいAPIハンドラーへのマッピング。
コンテンツネゴシエーションとシリアライゼーション
コンテンツネゴシエーションとシリアライゼーションのサーバーAPIは、サーバーとクライアントの間でシリアライゼーションライブラリを再利用できるようにリファクタリングされました。 主な変更点は以下の通りです。
ContentNegotiationはktor-server-coreから独立したktor-server-content-negotiationアーティファクトに移動されました。- シリアライゼーションライブラリは
ktor-*から、クライアントでも使用されるktor-serialization-*アーティファクトに移動されました。
以下に示すように、アプリケーションの依存関係とインポートを更新する必要があります。
依存関係
| サブシステム | 1.6.x | 2.0.0 |
|---|---|---|
| ContentNegotiation | io.ktor:ktor-server-core | io.ktor:ktor-server-content-negotiation |
| kotlinx.serialization | io.ktor:ktor-serialization | io.ktor:ktor-serialization-kotlinx-json |
| Gson | io.ktor:ktor-gson | io.ktor:ktor-serialization-gson |
| Jackson | io.ktor:ktor-jackson | io.ktor:ktor-serialization-jackson |
インポート
| サブシステム | 1.6.x | 2.0.0 |
|---|---|---|
| kotlinx.serialization | import io.ktor.serialization.* | import io.ktor.serialization.kotlinx.json.* |
| Gson | import io.ktor.gson.* | import io.ktor.serialization.gson.* |
| Jackson | import io.ktor.jackson.* | import io.ktor.serialization.jackson.* |
カスタムコンバーター
ContentConverter インターフェースによって公開される関数のシグネチャが次のように変更されました。
interface ContentConverter {
suspend fun convertForSend(context: PipelineContext<Any, ApplicationCall>, contentType: ContentType, value: Any): Any?
suspend fun convertForReceive(context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): Any?
}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 リクエストに置き換えられています。
@Test
fun testRootLegacyApi() {
withTestApplication(Application::module) {
handleRequest(HttpMethod.Get, "/").apply {
assertEquals(HttpStatusCode.OK, response.status())
assertEquals("Hello, world!", response.content)
}
}
}@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 リクエストに置き換えられています。
@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)
}
}@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 を渡す必要があります。
@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)
}
}@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 プラグインをインストールする必要があります。
@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())
}
}@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 プラグインをインストールする必要があります。
@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.")
}
} @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の対話をテストできます。
@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)
}
}
} @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 を受け取るようになりました。
install(CachingHeaders) {
options { outgoingContent ->
// ...
}
}install(CachingHeaders) {
options { call, outgoingContent ->
// ...
}
}Conditional headers
リソースバージョンのリストを定義するために使用される version 関数は、OutgoingContent に加えて、ラムダ引数として ApplicationCall を受け取るようになりました。
install(ConditionalHeaders) {
version { outgoingContent ->
// ...
}
}install(ConditionalHeaders) {
version { call, outgoingContent ->
// ...
}
}CORS
CORS 設定で使用されるいくつかの関数が名称変更されました。
host->allowHostheader->allowHeadermethod->allowMethod
install(CORS) {
host("0.0.0.0:5000")
header(HttpHeaders.ContentType)
method(HttpMethod.Options)
}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では、baseName は metricName に置き換えられ、そのデフォルト値は ktor.http.server.requests となりました。
Ktorクライアント
リクエストとレスポンス
v2.0.0では、リクエストの送信とレスポンスの受信に使用されるAPIが、より一貫性があり見つけやすいものに更新されました (KTOR-29)。
リクエスト関数
複数のパラメータを持つリクエスト関数は非推奨になりました。例えば、port および path パラメータは、HttpRequestBuilder によって公開される url パラメータに置き換える必要があります。
client.get(port = 8080, path = "/customer/3")client.get { url(port = 8080, path = "/customer/3") }HttpRequestBuilder では、リクエスト関数のラムダ内で追加のリクエストパラメータを指定することもできます。
リクエストボディ
リクエストボディを設定するために使用されていた HttpRequestBuilder.body プロパティは、HttpRequestBuilder.setBody 関数に置き換えられました。
client.post("http://localhost:8080/post") {
body = "Body content"
}client.post("http://localhost:8080/post") {
setBody("Body content")
}レスポンス
v2.0.0では、リクエスト関数(get、post、put、submitFormなど)は、特定の型のオブジェクトを受信するためのジェネリック引数を受け取らなくなりました。 現在、すべてのリクエスト関数は HttpResponse オブジェクトを返し、このオブジェクトが特定の型のインスタンスを受信するためのジェネリック引数を持つ body 関数を公開しています。 また、bodyAsText や bodyAsChannel を使用して、コンテンツを文字列やチャネルとして受信することもできます。
val httpResponse: HttpResponse = client.get("https://ktor.io/")
val stringBody: String = httpResponse.receive()
val byteArrayBody: ByteArray = httpResponse.receive()val httpResponse: HttpResponse = client.get("https://ktor.io/")
val stringBody: String = httpResponse.body()
val byteArrayBody: ByteArray = httpResponse.body()ContentNegotiation プラグインがインストールされている場合、次のように任意のオブジェクトを受信できます。
val customer: Customer = client.get("http://localhost:8080/customer/3")val customer: Customer = client.get("http://localhost:8080/customer/3").body()ストリーミングレスポンス
リクエスト関数からジェネリック引数が削除されたため、ストリーミングレスポンスを受信するには別の関数が必要になります。 これを実現するために、prepareGet や preparePost などの prepare プレフィックスが付いた関数が追加されました。
public suspend fun HttpClient.prepareGet(builder: HttpRequestBuilder): HttpStatement
public suspend fun HttpClient.preparePost(builder: HttpRequestBuilder): HttpStatement以下の例は、この場合のコードの変更方法を示しています。
client.get<HttpStatement>("https://ktor.io/").execute { httpResponse ->
val channel: ByteReadChannel = httpResponse.receive()
while (!channel.isClosedForRead) {
// データの読み込み
}
}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 へのアクセスが可能になります。
HttpResponseValidator {
handleResponseException { exception ->
// ...
}
}HttpResponseValidator {
handleResponseExceptionWithRequest { exception, request ->
// ...
}
}コンテンツネゴシエーションとシリアライゼーション
Ktorクライアントはコンテンツネゴシエーションをサポートし、Ktorサーバーとシリアライゼーションライブラリを共有するようになりました。 主な変更点は以下の通りです。
JsonFeatureは非推奨となり、ktor-client-content-negotiationアーティファクトにあるContentNegotiationに置き換えられました。- シリアライゼーションライブラリは
ktor-client-*からktor-serialization-*アーティファクトに移動されました。
以下に示すように、クライアントコードの依存関係とインポートを更新する必要があります。
依存関係
| サブシステム | 1.6.x | 2.0.0 |
|---|---|---|
ContentNegotiation | なし | io.ktor:ktor-client-content-negotiation |
| kotlinx.serialization | io.ktor:ktor-client-serialization | io.ktor:ktor-serialization-kotlinx-json |
| Gson | io.ktor:ktor-client-gson | io.ktor:ktor-serialization-gson |
| Jackson | io.ktor:ktor-client-jackson | io.ktor:ktor-serialization-jackson |
インポート
| サブシステム | 1.6.x | 2.0.0 |
|---|---|---|
ContentNegotiation | なし | import io.ktor.client.plugins.contentnegotiation.* |
| kotlinx.serialization | import io.ktor.client.features.json.* | import io.ktor.serialization.kotlinx.json.* |
| Gson | import io.ktor.client.features.json.* | import io.ktor.serialization.gson.* |
| Jackson | import io.ktor.client.features.json.* | import io.ktor.serialization.jackson.* |
Bearer認証
refreshTokens 関数は、HttpResponse ラムダ引数(it)の代わりに、ラムダレシーバー(this)として RefreshTokenParams インスタンスを使用するようになりました。
bearer {
refreshTokens { // it: HttpResponse
// ...
}
}bearer {
refreshTokens { // this: RefreshTokenParams
// ...
}
}RefreshTokenParams は以下のプロパティを公開しています。
response: レスポンスパラメータへのアクセス用client: トークンをリフレッシュするためのリクエスト送信可能oldTokens:loadTokensを使用して取得されたトークンへのアクセス用
HttpSend
HttpSend プラグインのAPIが以下のように変更されました。
client[HttpSend].intercept { originalCall, request ->
if (originalCall.something()) {
val newCall = execute(request)
// ...
}
}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 関数を使用してください。
client.get(HttpSend).intercept { ... }
// または
client[HttpSend].intercept { ... }client.plugin(HttpSend).intercept { ... }FeatureがPluginに名称変更されました
Ktorサーバーと同様に、クライアントAPIにおいても Feature は Plugin に名称変更されました。 これにより、以下で説明するようにアプリケーションに影響を与える可能性があります。
インポート
プラグインのインストールのためのインポートを更新します。
| サブシステム | 1.6.x | 2.0.0 |
| 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.x | 2.0.0 |
|---|---|
import io.ktor.http.cio.websocket.* | import io.ktor.websocket.* |
デフォルトリクエスト
DefaultRequest プラグインは、HttpRequestBuilder の代わりに DefaultRequestBuilder 設定クラスを使用するようになりました。
val client = HttpClient(CIO) {
defaultRequest {
// this: HttpRequestBuilder
}
}val client = HttpClient(CIO) {
defaultRequest {
// this: DefaultRequestBuilder
}
}