Ktor 3.6.0 Help

Content negotiation and serialization in Ktor Client

The ContentNegotiation plugin serves two primary purposes:

  • Negotiating media types between the client and server, using the Accept and Content-Type headers.

  • Serializing request bodies and deserializing response bodies in supported formats. Ktor provides built-in support for JSON, XML, CBOR, and ProtoBuf.

Add dependencies

Content negotiation

To use ContentNegotiation, add the ktor-client-content-negotiation artifact to your build script:

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

Serialization

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

JSON

To serialize and deserialize JSON data, add a serialization library to your project. Ktor supports kotlinx.serialization, Gson, or Jackson.

Add the ktor-serialization-kotlinx-json artifact in your 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 your 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 your 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 and deserialize XML, add the ktor-serialization-kotlinx-xml artifact in your 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>

CBOR

To serialize and deserialize CBOR, add the ktor-serialization-kotlinx-cbor artifact in your 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 and deserialize ProtoBuf, add the ktor-serialization-kotlinx-protobuf artifact in your 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, pass it to the install function in the client configuration block:

val client = HttpClient(CIO) { install(ContentNegotiation) }

You can then configure the required JSON serializer.

Configure a serializer

JSON serializer

To register the JSON serializer in your application, call the json() function:

import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* val client = HttpClient(CIO) { install(ContentNegotiation) { json() } }

To customize JSON serialization, pass a Json configuration in the json() constructor:

val client = HttpClient(CIO) { install(ContentNegotiation) { json(Json { prettyPrint = true isLenient = true }) } }

For available configuration options, see JsonBuilder.

To register the Gson serializer in your application, call the gson() function:

import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.gson.* val client = HttpClient(CIO) { install(ContentNegotiation) { gson() } }

To customize Gson serialization, pass a configuration block to the gson() function. For available configuration options, see GsonBuilder.

To register the Jackson serializer in your application, call the jackson() function:

import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.jackson.* val client = HttpClient(CIO) { install(ContentNegotiation) { jackson() } }

To customize Jackson serialization, use the settings provided by ObjectMapper:

import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.jackson.* import com.fasterxml.jackson.databind.* import java.text.DateFormat val client = HttpClient(CIO) { install(ContentNegotiation) { jackson { enable(SerializationFeature.INDENT_OUTPUT) dateFormat = DateFormat.getDateInstance() } } }

XML serializer

To register the XML serializer in your application, call the xml() function:

import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.xml.* val client = HttpClient(CIO) { install(ContentNegotiation) { xml() } }

To customize XML serialization, pass the required options to the xml() function:

import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.xml.* import nl.adaptivity.xmlutil.* import nl.adaptivity.xmlutil.serialization.* val client = HttpClient(CIO) { install(ContentNegotiation) { xml(format = XML { xmlDeclMode = XmlDeclMode.Charset }) } }

CBOR serializer

To register the CBOR serializer in your application, call the cbor() function:

import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.cbor.* val client = HttpClient(CIO) { install(ContentNegotiation) { cbor() } }

To customize CBOR serialization, pass a Cbor configuration in the cbor() constructor:

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

For available configuration options, see CborBuilder

ProtoBuf serializer

To register the ProtoBuf serializer in your application, call the protobuf() function:

import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.protobuf.* val client = HttpClient(CIO) { install(ContentNegotiation) { protobuf() } }

To customize ProtoBuf serialization, pass a ProtoBuf configuration to the protobuf() function:

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

For available options, see ProtoBufBuilder.

Configure the Accept header

By default, the ContentNegotiation plugin adds registered content types to the Accept header of outgoing requests.

If you set an Accept header explicitly and don't want the plugin to add registered content types, set the acceptHeaderMergeStrategy property to ContentTypeMergeStrategy.SkipIfPresent:

val client = HttpClient(CIO) { install(ContentNegotiation) { register(ContentType.Application.Json, noOpJsonConverter) acceptHeaderMergeStrategy = ContentTypeMergeStrategy.SkipIfPresent } }

With SkipIfPresent, the plugin preserves an existing Accept header. If the request doesn't contain an Accept header, the plugin adds the registered content types as usual.

Send and receive data

Create a data class

The following examples use a Customer data class to represent the data sent and received by the client:

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

If you use kotlinx.serialization, annotate the class with @Serializable:

@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:

Send data

To send a class instance in a request body, assign this instance using the setBody() function and set the content type using the contentType() function.

The following example sends a Customer object as JSON:

val response: HttpResponse = client.post("http://localhost:8080/customer") { contentType(ContentType.Application.Json) setBody(Customer(3, "Jet", "Brains")) }

The ContentNegotiation plugin uses the configured serializer to convert the request body to the specified format.

To send data in another registered format, specify the corresponding content type, such as ContentType.Application.Xml or ContentType.Application.Cbor.

Receive data

When the server returns a response with a supported content type, the ContentNegotiation plugin can deserialize the response body into the expected type.

For example, to deserialize a JSON response into a Customer object, call the body() function:

val customer: Customer = client.get("http://localhost:8080/customer/3").body()
04 September 2026