Ktor 2.3.9 Help

Content negotiation and serialization

The ContentNegotiation plugin serves two primary purposes:

  • Negotiating media types between the client and server. For this, it uses the Accept and Content-Type headers.

  • Serializing/deserializing the content in a specific format. Ktor supports the following formats out-of-the-box: JSON, XML, CBOR, and ProtoBuf.

Add dependencies

ContentNegotiation

To use ContentNegotiation, you need to include the ktor-server-content-negotiation artifact in the build script:

implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
implementation "io.ktor:ktor-server-content-negotiation:$ktor_version"
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-server-content-negotiation-jvm</artifactId> <version>${ktor_version}</version> </dependency>

Note that serializers for specific formats require additional artifacts. For example, kotlinx.serialization requires the ktor-serialization-kotlinx-json dependency for JSON.

Serialization

Before using kotlinx.serialization converters, you need to add the Kotlin serialization plugin as described in the Setup section.

JSON

To serialize/deserialize JSON data, you can choose one of the following libraries: kotlinx.serialization, Gson, or Jackson.

Add the ktor-serialization-kotlinx-json artifact in the build script:

implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
implementation "io.ktor:ktor-serialization-kotlinx-json:$ktor_version"
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-serialization-kotlinx-json-jvm</artifactId> <version>${ktor_version}</version> </dependency>

Add the ktor-serialization-gson artifact in the build script:

implementation("io.ktor:ktor-serialization-gson:$ktor_version")
implementation "io.ktor:ktor-serialization-gson:$ktor_version"
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-serialization-gson-jvm</artifactId> <version>${ktor_version}</version> </dependency>

Add the ktor-serialization-jackson artifact in the build script:

implementation("io.ktor:ktor-serialization-jackson:$ktor_version")
implementation "io.ktor:ktor-serialization-jackson:$ktor_version"
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-serialization-jackson-jvm</artifactId> <version>${ktor_version}</version> </dependency>

XML

To serialize/deserialize XML, add the ktor-serialization-kotlinx-xml in the build script:

implementation("io.ktor:ktor-serialization-kotlinx-xml:$ktor_version")
implementation "io.ktor:ktor-serialization-kotlinx-xml:$ktor_version"
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-serialization-kotlinx-xml-jvm</artifactId> <version>${ktor_version}</version> </dependency>

Note that XML serialization is supported on JVM only.

CBOR

To serialize/deserialize CBOR, add the ktor-serialization-kotlinx-cbor in the build script:

implementation("io.ktor:ktor-serialization-kotlinx-cbor:$ktor_version")
implementation "io.ktor:ktor-serialization-kotlinx-cbor:$ktor_version"
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-serialization-kotlinx-cbor-jvm</artifactId> <version>${ktor_version}</version> </dependency>

ProtoBuf

To serialize/deserialize ProtoBuf, add the ktor-serialization-kotlinx-protobuf in the build script:

implementation("io.ktor:ktor-serialization-kotlinx-protobuf:$ktor_version")
implementation "io.ktor:ktor-serialization-kotlinx-protobuf:$ktor_version"
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-serialization-kotlinx-protobuf-jvm</artifactId> <version>${ktor_version}</version> </dependency>

Install ContentNegotiation

To install the ContentNegotiation plugin to the application, pass it to the install function in the specified module. The code snippets below show how to install ContentNegotiation...

  • ... inside the embeddedServer function call.

  • ... inside the explicitly defined module, which is an extension function of the Application class.

import io.ktor.server.application.* import io.ktor.server.plugins.contentnegotiation.* // ... fun main() { embeddedServer(Netty, port = 8080) { install(ContentNegotiation) // ... }.start(wait = true) }
import io.ktor.server.application.* import io.ktor.server.plugins.contentnegotiation.* // ... fun Application.module() { install(ContentNegotiation) // ... }

Configure a serializer

Ktor supports the following formats out-of-the-box: JSON, XML, CBOR. You can also implement your own custom serializer.

JSON serializer

To register the JSON serializer in your application, call the json method:

import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* install(ContentNegotiation) { json() }

The json method also allows you to adjust serialization settings provided by JsonBuilder, for example:

install(ContentNegotiation) { json(Json { prettyPrint = true isLenient = true }) }

To register the Gson serializer in your application, call the gson method:

import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.gson.* install(ContentNegotiation) { gson() }

The gson method also allows you to adjust serialization settings provided by GsonBuilder, for example:

install(ContentNegotiation) { gson { setDateFormat(DateFormat.LONG) setPrettyPrinting() } }

To register the Jackson serializer in your application, call the jackson method:

import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.jackson.* install(ContentNegotiation) { jackson() }

The jackson method also allows you to adjust serialization settings provided by ObjectMapper, for example:

install(ContentNegotiation) { jackson { configure(SerializationFeature.INDENT_OUTPUT, true) setDefaultPrettyPrinter(DefaultPrettyPrinter().apply { indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance) indentObjectsWith(DefaultIndenter(" ", "\n")) }) registerModule(JavaTimeModule()) // support java.time.* types } }

XML serializer

To register the XML serializer in your application, call the xml method:

import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.xml.* install(ContentNegotiation) { xml() }

The xml method also allows you to access XML serialization settings, for example:

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 serializer

To register the CBOR serializer in your application, call the cbor method:

import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.cbor.* install(ContentNegotiation) { cbor() }

The cbor method also allows you to access CBOR serialization settings provided by CborBuilder, for example:

import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.cbor.* import kotlinx.serialization.cbor.* install(ContentNegotiation) { cbor(Cbor { ignoreUnknownKeys = true }) }

ProtoBuf serializer

To register the ProtoBuf serializer in your application, call the protobuf method:

import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.protobuf.* install(ContentNegotiation) { protobuf() }

The protobuf method also allows you to access ProtoBuf serialization settings provided by ProtoBufBuilder, for example:

import io.ktor.server.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.protobuf.* import kotlinx.serialization.protobuf.* install(ContentNegotiation) { protobuf(ProtoBuf { encodeDefaults = true }) }

Custom serializer

To register a custom serializer for a specified Content-Type, you need to call the register method. In the example below, two custom serializer are registered to deserialize application/json and application/xml data:

install(ContentNegotiation) { register(ContentType.Application.Json, CustomJsonConverter()) register(ContentType.Application.Xml, CustomXmlConverter()) }

Receive and send data

Create a data class

To deserialize received data into an object, you need to create a data class, for example:

data class Customer(val id: Int, val firstName: String, val lastName: String)

If you use kotlinx.serialization, make sure that this class has the @Serializable annotation:

import kotlinx.serialization.* @Serializable data class Customer(val id: Int, val firstName: String, val lastName: String)

Serializing/deserializing of the following types is supported by the kotlinx.serialization library:

Receive data

To receive and convert a content for a request, call the receive method that accepts a data class as a parameter:

post("/customer") { val customer = call.receive<Customer>() customerStorage.add(customer) call.respondText("Customer stored correctly", status = HttpStatusCode.Created) }

The Content-Type of the request will be used to choose a serializer for processing the request. The example below shows a sample HTTP client request containing JSON or XML data that is converted to a Customer object on the server side:

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"/>

You can find the full example here: json-kotlinx.

Send data

To pass a data object in a response, you can use the respond method:

get("/customer/{id}") { val id = call.parameters["id"] val customer: Customer = customerStorage.find { it.id == id!!.toInt() }!! call.respond(customer) }

In this case, Ktor uses the Accept header to choose the required serializer. You can find the full example here: json-kotlinx.

Implement a custom serializer

In Ktor, you can write your own serializer for serializing/deserializing data. To do this, you need to implement the ContentConverter interface:

interface ContentConverter { suspend fun serialize(contentType: ContentType, charset: Charset, typeInfo: TypeInfo, value: Any): OutgoingContent? suspend fun deserialize(charset: Charset, typeInfo: TypeInfo, content: ByteReadChannel): Any? }

Take a look at the GsonConverter class as an implementation example.

Last modified: 19 April 2023