Ktor Serverにおけるコンテンツネゴシエーションとシリアライゼーション
必要な依存関係: io.ktor:ktor-server-content-negotiation
コード例: json-kotlinx
ContentNegotiationプラグインには主に2つの目的があります。
- クライアントとサーバー間のメディアタイプをネゴシエーションする。これには
Accept
ヘッダーとContent-Type
ヘッダーが使用されます。 - 特定のフォーマットでコンテンツをシリアライズ/デシリアライズする。Ktorは以下のフォーマットをそのままサポートしています: JSON、XML、CBOR、ProtoBuf。
クライアント側では、Ktorはコンテンツのシリアライゼーション/デシリアライゼーションのためにContentNegotiationプラグインを提供しています。
依存関係の追加
ContentNegotiation
ContentNegotiation
を使用するには、ビルドスクリプトにktor-server-content-negotiation
アーティファクトを含める必要があります:
特定のフォーマット用のシリアライザーには、追加のアーティファクトが必要となることに注意してください。たとえば、kotlinx.serializationではJSON用にktor-serialization-kotlinx-json
の依存関係が必要です。
シリアライゼーション
kotlinx.serializationコンバーターを使用する前に、セットアップセクションで説明されているように、Kotlin serializationプラグインを追加する必要があります。
JSON
JSONデータをシリアライズ/デシリアライズするには、kotlinx.serialization、Gson、Jacksonのいずれかのライブラリを選択できます。
ビルドスクリプトにktor-serialization-kotlinx-json
アーティファクトを追加します:
ビルドスクリプトにktor-serialization-gson
アーティファクトを追加します:
ビルドスクリプトにktor-serialization-jackson
アーティファクトを追加します:
XML
XMLをシリアライズ/デシリアライズするには、ビルドスクリプトにktor-serialization-kotlinx-xml
を追加します:
XMLシリアライゼーションは
jsNode
ターゲットでサポートされていませんのでご注意ください。
CBOR
CBORをシリアライズ/デシリアライズするには、ビルドスクリプトにktor-serialization-kotlinx-cbor
を追加します:
ProtoBuf
ProtoBufをシリアライズ/デシリアライズするには、ビルドスクリプトにktor-serialization-kotlinx-protobuf
を追加します:
ContentNegotiationのインストール
アプリケーションにインストールするには、指定された
install
関数にContentNegotiation
プラグインを渡します。 以下のコードスニペットは、ContentNegotiation
をインストールする方法を示しています... - ...
embeddedServer
関数呼び出し内。 - ...
Application
クラスの拡張関数である明示的に定義されたmodule
内。
シリアライザーの設定
Ktorは以下のフォーマットをそのままサポートしています: JSON、XML、CBOR。独自のカスタムシリアライザーを実装することもできます。
JSONシリアライザー
アプリケーションでJSONシリアライザーを登録するには、json
メソッドを呼び出します:
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.json.*
install(ContentNegotiation) {
json()
}
json
メソッドでは、JsonBuilderによって提供されるシリアライゼーション設定を調整することもできます。例:
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
})
アプリケーションでGsonシリアライザーを登録するには、gson
メソッドを呼び出します:
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.gson.*
install(ContentNegotiation) {
gson()
}
gson
メソッドでは、GsonBuilderによって提供されるシリアライゼーション設定を調整することもできます。例:
install(ContentNegotiation) {
gson {
registerTypeAdapter(LocalDate::class.java, LocalDateAdapter())
setDateFormat(DateFormat.LONG, DateFormat.SHORT)
setPrettyPrinting()
}
アプリケーションでJacksonシリアライザーを登録するには、jackson
メソッドを呼び出します:
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.jackson.*
install(ContentNegotiation) {
jackson()
}
jackson
メソッドでは、ObjectMapperによって提供されるシリアライゼーション設定を調整することもできます。例:
install(ContentNegotiation) {
jackson {
configure(SerializationFeature.INDENT_OUTPUT, true)
setDefaultPrettyPrinter(DefaultPrettyPrinter().apply {
indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance)
indentObjectsWith(DefaultIndenter(" ", "
"))
})
registerModule(JavaTimeModule()) // support java.time.* types
}
}
XMLシリアライザー
アプリケーションでXMLシリアライザーを登録するには、xml
メソッドを呼び出します:
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.xml.*
install(ContentNegotiation) {
xml()
}
xml
メソッドでは、XMLシリアライゼーション設定にアクセスすることもできます。例:
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.xml.*
import nl.adaptivity.xmlutil.*
import nl.adaptivity.xmlutil.serialization.*
install(ContentNegotiation) {
xml(format = XML {
xmlDeclMode = XmlDeclMode.Charset
})
}
CBORシリアライザー
アプリケーションでCBORシリアライザーを登録するには、cbor
メソッドを呼び出します:
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.cbor.*
install(ContentNegotiation) {
cbor()
}
cbor
メソッドでは、CborBuilderによって提供されるCBORシリアライゼーション設定にアクセスすることもできます。例:
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.cbor.*
import kotlinx.serialization.cbor.*
install(ContentNegotiation) {
cbor(Cbor {
ignoreUnknownKeys = true
})
}
ProtoBufシリアライザー
アプリケーションでProtoBufシリアライザーを登録するには、protobuf
メソッドを呼び出します:
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.protobuf.*
install(ContentNegotiation) {
protobuf()
}
protobuf
メソッドでは、ProtoBufBuilderによって提供されるProtoBufシリアライゼーション設定にアクセスすることもできます。例:
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.protobuf.*
import kotlinx.serialization.protobuf.*
install(ContentNegotiation) {
protobuf(ProtoBuf {
encodeDefaults = true
})
}
カスタムシリアライザー
指定されたContent-Type
にカスタムシリアライザーを登録するには、register
メソッドを呼び出す必要があります。以下の例では、application/json
およびapplication/xml
データをデシリアライズするために2つのカスタムシリアライザーが登録されています:
install(ContentNegotiation) {
register(ContentType.Application.Json, CustomJsonConverter())
register(ContentType.Application.Xml, CustomXmlConverter())
}
データの受信と送信
データクラスの作成
受信したデータをオブジェクトにデシリアライズするには、データクラスを作成する必要があります。例:
@Serializable
kotlinx.serializationを使用する場合、このクラスに@Serializable
アノテーションが付いていることを確認してください:
import kotlinx.serialization.*
import io.ktor.server.util.getValue
@Serializable
以下の型のシリアライゼーション/デシリアライゼーションは、kotlinx.serializationライブラリによってサポートされています:
データの受信
リクエストのコンテンツを受信して変換するには、データクラスをパラメータとして受け取るreceive
メソッドを呼び出します:
post("/customer") {
val customer = call.receive<Customer>()
customerStorage.add(customer)
call.respondText("Customer stored correctly", status = HttpStatusCode.Created)
リクエストのContent-Type
は、リクエストを処理するためのシリアライザーを選択するために使用されます。以下の例は、JSONまたはXMLデータを含むHTTPクライアントリクエストが、サーバー側でCustomer
オブジェクトに変換される様子を示しています:
POST http://0.0.0.0:8080/customer
Content-Type: application/json
{
"id": 3,
"firstName": "Jet",
"lastName": "Brains"
}
POST http://0.0.0.0:8080/customer
Content-Type: application/xml
<Customer id="3" firstName="Jet" lastName="Brains"/>
完全な例は、json-kotlinxで確認できます。
データの送信
レスポンスでデータオブジェクトを渡すには、respond
メソッドを使用できます:
routing {
get("/customer/{id}") {
val id: Int by call.parameters
val customer: Customer = customerStorage.find { it.id == id }!!
call.respond(customer)
この場合、KtorはAccept
ヘッダーを使用して必要なシリアライザーを選択します。完全な例は、json-kotlinxで確認できます。
カスタムシリアライザーの実装
Ktorでは、データのシリアライゼーション/デシリアライゼーションのために独自のシリアライザーを作成できます。これを行うには、ContentConverterインターフェースを実装する必要があります:
interface ContentConverter {
suspend fun serialize(contentType: ContentType, charset: Charset, typeInfo: TypeInfo, value: Any): OutgoingContent?
suspend fun deserialize(charset: Charset, typeInfo: TypeInfo, content: ByteReadChannel): Any?
}
実装例として、GsonConverterクラスを参照してください。