Content-TypeとAccept Headerをベースにしたコンテントネゴシエーション

Estimated reading time: 1 minute

この機能は、Content-TypeAcceptヘッダーに応じて自動でのコンテンツの変換を行う機能です。

This feature is defined in the class io.ktor.features.ContentNegotiation and no additional artifacts are required.

基本的な使い方

ContentNegotiation Featureを使うとカスタムのコンバーターを登録・設定することができます。

install(ContentNegotiation) {
    register(MyContentType, MyContentTypeConverter()) {
        // Optionally configure the converter...
    }
}

例えば:

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

送信時

直接扱うことができないオブジェクトでレスポンスを返したいとき、例えばカスタムのデータクラスを使うとき、 この機能はクライアントのAcceptヘッダーをチェックし、 どのContent-Typeが利用されるかと、そしてどのContentConverterが呼ばれるかを決定します。

call.respond(MyDataClass("hello", "world"))

たった今、送信時にサポートされている唯一のコンテントネゴシエーションの戦略は、クライアントのAcceptヘッダーを使うものです。 その他の戦略を実装する上では問題があります。

受信時

受信時にはリクエストのContent-Typeが使われ、どのContentConverterがリクエストを処理するのに使われるのかが決定されます。

val myDataClass = call.receive<MyDataClass>()

ContentConverterインターフェース

自身でコンバーターを書きたいのなら、ContentConverterインターフェースを実装する必要があります。

interface ContentConverter {
    suspend fun convertForSend(context: PipelineContext<Any, ApplicationCall>, contentType: ContentType, value: Any): Any?
    suspend fun convertForReceive(context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): Any?
}

例えば、GsonConverterの実装は以下のようになっています:

class GsonConverter(private val gson: Gson = Gson()) : ContentConverter {
    override suspend fun convertForSend(context: PipelineContext<Any, ApplicationCall>, contentType: ContentType, value: Any): Any? {
        return TextContent(gson.toJson(value), contentType.withCharset(context.call.suitableCharset()))
    }

    override suspend fun convertForReceive(context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): Any? {
        val request = context.subject
        val channel = request.value as? ByteReadChannel ?: return null
        val reader = channel.readRemaining().readText((context.call.request.contentCharset() ?: Charsets.UTF_8).newDecoder()).reader()
        return gson.fromJson(reader, request.type.javaObjectType)
    }
}

初めから利用可能なContentConverter

Ktorはいくつかの初めから利用可能なコンテントコンバーターを提供しています。