Ktor 1.3が最近リリースされましたので、このブログ投稿でその詳細をお伝えします。

13release-01

Ktorはサーバーエンジンとフレキシブルな非同期HTTPクライアントの2つの部分から構成されています。 今回のリリースでは、主にHTTPクライアントに注力しています。 このリリースの完全な変更ログはこちらで確認できます。

クライアントはJVM、JS、Android、iOSに対応したマルチプラットフォームなライブラリであり、クロスプラットフォームモバイルアプリケーションでよく使用されています。 次のリリースでは、サーバーエンジンもマルチプラットフォーム対応にすることをメインゴールにしています。

それ以外の項目としては、以下を計画しています。

  • kotlinx.serializationライブラリとの統合の改善。
  • CIO(コルーチンベースのI/Oクライアントエンジン)をKotlin/Native上でサポートを実現し、HttpClientで使用されるデフォルトのマルチプラットフォームエンジンにします。

現在Ktor(ServerかHttpClientのいずれか)をお使いの方、または以前お試しになったことのある方は、以下のアンケートへのご協力をお願いします。

アンケートに参加する

あなたの体験を教えていただければ幸いです。

それではKtor 1.3のリリースで提供されるものを詳しくご紹介します。

HttpClient

HttpStatementのご紹介

Ktorの旧バージョンでは、HttpResponseを明示的にcloseする必要がありました。 しかし、これはしばしば混乱の元となっていました。 私たちは単純なサンプルでさえも、HttpResponseのclose漏れが原因でメモリリークが発生する事例を多数目の当たりにしてきました。 この状況を改善するため、Ktor 1.3では互換性のない変更を行いました。HttpResponseは今後、Closeableインターフェースを実装しません。 そのため、1.3.0 Ktorのリリースは旧バージョンのKtor 1.2.Xとは後方互換性がありません

HttpResponseがデフォルトでメモリ内に格納されるようになったため、もうcloseする必要はありません。

fun main(): Unit = runBlocking {
    val client = HttpClient()
    val url = "http://kotlinlang.org/"
    val response = client.get<HttpResponse>(url)
    val text = response.readText()
    println(text)
    // no longer need to 'close' the response
}

ストリーミングや大きなレスポンスを処理したい場合は新しいHttpStatementクラスを使用してください。 HttpStatementは、明示的にexecuteメソッドが呼び出されない限りネットワーク要求を実行しません。

val statement = client.request<HttpStatement>("$TEST_SERVER/content/stream")
// ...
statement.execute { response: HttpResponse ->
    // working with the response
}

例えば、データをチャンク単位で読み込むことができます。

client.get<HttpStatement>(url).execute { response ->
    val channel = response.receive<ByteReadChannel>()
    while (!channel.isClosedForRead) {
        val packet = channel.readRemaining(size)
        println(packet.readText())
    }
}

プロキシの構成

HttpClientがexperimental supportとしてプロキシに対応しました。 プロキシ経由でリクエストを送信したい場合、対応するパラメータでプロキシのアドレスを設定できます。

HttpClient { 
    engine { 
        proxy = ProxyBuilder.http("http://proxy-host:3128")
    }
}

ただし、プラットフォーム上の制約のため、JVMとNativeのターゲット(WatchOSを除く)のみに対応しており、JavaScriptには対応していませんのでご注意ください。 各種プラットフォームでのプロキシの構成方法に関する詳細は、こちらをご覧ください。

iOSエンジンでのNSURLSessionの利用

iOSエンジンでNSURLSessionを構成するオプションが提供されるようになりました。

HttpClient(Ios) {
    engine {
        configureSession {
            networkServiceType = NSURLNetworkServiceTypeBackground
        }
    }
}

NSURLSessionはiOSでHTTP / HTTPSプロトコルを処理するデフォルトのAPIですので、これを使ってiOSに関するすべての設定を微調整することができます。

JSON関連の処理に対する改善

以下の変更はHttpClientとServerの両方でサポートされていますが、現在はexperimental扱いです。

JSONでコレクションのシリアル化を単純化

Ktorの旧バージョンでは、コレクションをシリアル化する際に補助型を登録する必要がありました。 今回のリリースではこの手続きが単純化され、JsonFeatureが追加設定なしでコレクション型を処理するようになりました。 また、setMappersetListMapperregisterなどの関連する関数はすべて非推奨になりました。

もう、JsonFeatureList<User>を登録する必要はありません。

install(JsonFeature)
// ...
val list = client.get<List<User>>("https://example/json/users")

同じことはJSONをサーバー上で処理する場合にも当てはまります。コンテンツを受信する際に、必要な汎用引数を使ってコレクション型を指定できます。

install(ContentNegotiation) {
    register(ContentType.Application.Json, SerializationConverter())
}

routing {
    post("/entity") {
        val receivedList = call.receive<List<MyEntity>>()
        // process the list
    }
}

kotlinx.serialization DSL

Ktorがkotlinx.serialization DSLを使ってJSONのbodyを構築できるようになりました。

client.post<String>("http://localhost:9090") {
    contentType(ContentType.Application.Json)
    body = json {
        "key1" to 123
        "map" to json {
            "key2" to "abc"
        }
    }
}

クライアントでこれを使用するには、JsonFeatureをインストールしてからktor-client-serializationの依存関係を追加してください。 サーバーではSerializationConverterを使用してください。

移行手順

Ktorアプリケーションを新バージョンに移行するには、以下の手順を実行する必要があります。

  • HttpResponseの使用箇所をすべて更新します(単純にcloseの呼び出しを削除し、必要に応じてHttpStatementを使用します)。
  • import文を更新します。 kotlinx.ioの依存物が削除されたため、import文を次のように置換する必要があります。
  • import kotlinx.io. -> import io.ktor.utils.io.
  • import kotlinx.coroutines.io. -> import io.ktor.utils.io.

1.2.xとはバイナリ互換ではないため、外部のKtorの機能を使用する場合はそれらを最新バージョンに対してコンパイルしなおす必要があります。 また、5.4.1以降のGradleメタデータバージョンを使用していることを確認してください。

最後までお読みいただき、ありがとうございました。また、アンケートへのご協力もお願いします!

アンケートに参加する