or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/maven-io-ktor--ktor-client-content-negotiation

Ktor client Content Negotiation support - enables automatic serialization and deserialization of request and response bodies using various formats like JSON, XML, and others

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/io.ktor/ktor-client-content-negotiation@3.2.x

To install, run

npx @tessl/cli install tessl/maven-io-ktor--ktor-client-content-negotiation@3.2.0

0

# Ktor Client Content Negotiation

1

2

Ktor Client Content Negotiation provides automatic serialization and deserialization of request and response bodies using various formats like JSON, XML, and protobuf. It handles media type negotiation between client and server using Accept and Content-Type headers, while offering extensible converter registration mechanisms with built-in support for popular serialization libraries.

3

4

## Package Information

5

6

- **Package Name**: io.ktor:ktor-client-content-negotiation

7

- **Package Type**: maven

8

- **Language**: Kotlin

9

- **Installation**:

10

```kotlin

11

implementation("io.ktor:ktor-client-content-negotiation:3.2.0")

12

```

13

14

## Core Imports

15

16

```kotlin

17

import io.ktor.client.plugins.contentnegotiation.*

18

import io.ktor.serialization.*

19

import io.ktor.http.*

20

import io.ktor.http.content.*

21

import io.ktor.util.reflect.*

22

import io.ktor.utils.io.*

23

import io.ktor.utils.io.charsets.*

24

```

25

26

## Basic Usage

27

28

```kotlin

29

import io.ktor.client.*

30

import io.ktor.client.call.*

31

import io.ktor.client.plugins.contentnegotiation.*

32

import io.ktor.client.request.*

33

import io.ktor.serialization.kotlinx.json.*

34

35

// Configure client with content negotiation

36

val client = HttpClient {

37

install(ContentNegotiation) {

38

json() // Uses kotlinx.serialization JSON

39

}

40

}

41

42

// Automatic serialization on send

43

data class User(val name: String, val email: String)

44

val user = User("Alice", "alice@example.com")

45

val response = client.post("https://api.example.com/users") {

46

setBody(user) // Automatically serialized to JSON

47

}

48

49

// Automatic deserialization on receive

50

val createdUser: User = response.body()

51

```

52

53

## Architecture

54

55

Ktor Client Content Negotiation is built around several key components:

56

57

- **ContentNegotiation Plugin**: Main plugin that intercepts requests and responses

58

- **ContentNegotiationConfig**: Configuration class for registering content converters

59

- **ContentConverter Interface**: Defines bi-directional serialization/deserialization

60

- **ContentTypeMatcher Interface**: Determines which converter handles which content types

61

- **Type Ignoring System**: Mechanism to exclude certain types from content negotiation

62

- **Request Exclusion**: Per-request control over Accept header content types

63

64

## Capabilities

65

66

### Plugin Installation and Configuration

67

68

Install and configure the ContentNegotiation plugin with content converters and settings.

69

70

```kotlin { .api }

71

/**

72

* A plugin that serves two primary purposes:

73

* - Negotiating media types between the client and server using Accept and Content-Type headers

74

* - Serializing/deserializing content in specific formats when sending requests and receiving responses

75

*/

76

val ContentNegotiation: ClientPlugin<ContentNegotiationConfig>

77

```

78

79

### Content Converter Registration

80

81

Register content converters for specific media types with optional configuration.

82

83

```kotlin { .api }

84

/**

85

* A ContentNegotiation configuration that is used during installation

86

*/

87

class ContentNegotiationConfig : Configuration {

88

/**

89

* By default, Accept headers for registered content types will have no q value (implicit 1.0).

90

* Set this to change that behavior for per-request basis Accept content type preferences.

91

*/

92

var defaultAcceptHeaderQValue: Double?

93

94

/**

95

* Registers a contentType to a specified converter with an optional configuration script

96

*/

97

fun <T : ContentConverter> register(

98

contentType: ContentType,

99

converter: T,

100

configuration: T.() -> Unit = {}

101

)

102

103

/**

104

* Registers a contentTypeToSend and contentTypeMatcher to a specified converter

105

* with an optional configuration script for advanced content type handling

106

*/

107

fun <T : ContentConverter> register(

108

contentTypeToSend: ContentType,

109

converter: T,

110

contentTypeMatcher: ContentTypeMatcher,

111

configuration: T.() -> Unit

112

)

113

}

114

```

115

116

**Usage Examples:**

117

118

```kotlin

119

import io.ktor.client.*

120

import io.ktor.client.plugins.contentnegotiation.*

121

import io.ktor.serialization.kotlinx.json.*

122

import io.ktor.serialization.kotlinx.xml.*

123

124

val client = HttpClient {

125

install(ContentNegotiation) {

126

json() // Register JSON converter

127

xml() // Register XML converter

128

129

// Custom q-value for Accept headers

130

defaultAcceptHeaderQValue = 0.8

131

132

// Register custom converter

133

register(

134

ContentType.Application.ProtoBuf,

135

MyProtobufConverter()

136

) {

137

// Configure the converter

138

customOption = true

139

}

140

}

141

}

142

```

143

144

### Type Ignoring Configuration

145

146

Configure which types should bypass content negotiation processing.

147

148

```kotlin { .api }

149

/**

150

* Adds a type to the list of types that should be ignored by ContentNegotiation.

151

* The list contains HttpStatusCode, ByteArray, String and streaming types by default.

152

*/

153

inline fun <reified T> ContentNegotiationConfig.ignoreType()

154

155

/**

156

* Adds a type to the list of types that should be ignored by ContentNegotiation

157

*/

158

fun ContentNegotiationConfig.ignoreType(type: KClass<*>)

159

160

/**

161

* Remove type from the list of types that should be ignored by ContentNegotiation

162

*/

163

inline fun <reified T> ContentNegotiationConfig.removeIgnoredType()

164

165

/**

166

* Remove type from the list of types that should be ignored by ContentNegotiation

167

*/

168

fun ContentNegotiationConfig.removeIgnoredType(type: KClass<*>)

169

170

/**

171

* Clear all configured ignored types including defaults

172

*/

173

fun ContentNegotiationConfig.clearIgnoredTypes()

174

```

175

176

**Usage Examples:**

177

178

```kotlin

179

val client = HttpClient {

180

install(ContentNegotiation) {

181

json()

182

183

// Add custom types to ignore

184

ignoreType<MyStreamingType>()

185

ignoreType(CustomContent::class)

186

187

// Remove default ignored types if needed

188

removeIgnoredType<String>()

189

190

// Clear all and start fresh

191

clearIgnoredTypes()

192

}

193

}

194

```

195

196

### Request-Level Content Type Exclusion

197

198

Exclude specific content types from Accept headers on a per-request basis.

199

200

```kotlin { .api }

201

/**

202

* Excludes the given ContentType from the list of types that will be sent in the Accept header

203

* by the ContentNegotiation plugin. Can be used to not accept specific types for particular requests.

204

* This can be called multiple times to exclude multiple content types.

205

*/

206

fun HttpRequestBuilder.exclude(vararg contentType: ContentType)

207

```

208

209

**Usage Examples:**

210

211

```kotlin

212

import io.ktor.client.request.*

213

import io.ktor.http.*

214

215

// Exclude JSON from this specific request

216

val response = client.get("https://api.example.com/data") {

217

exclude(ContentType.Application.Json)

218

}

219

220

// Exclude multiple content types

221

val response2 = client.get("https://api.example.com/legacy") {

222

exclude(ContentType.Application.Json, ContentType.Application.Xml)

223

}

224

```

225

226

### JSON Content Type Matching

227

228

Advanced JSON content type matching for extended JSON formats.

229

230

```kotlin { .api }

231

/**

232

* Matcher that accepts all extended json content types including application/json

233

* and types ending with +json suffix

234

*/

235

object JsonContentTypeMatcher : ContentTypeMatcher {

236

/**

237

* Checks if contentType matches JSON patterns (application/json or */*+json)

238

*/

239

override fun contains(contentType: ContentType): Boolean

240

}

241

```

242

243

### Exception Handling

244

245

Handle content conversion failures and errors.

246

247

```kotlin { .api }

248

/**

249

* Exception thrown when content conversion fails

250

*/

251

class ContentConverterException(message: String) : Exception(message)

252

253

/**

254

* Exception thrown when no suitable converter found for deserialization

255

*/

256

class ContentConvertException(message: String) : Exception(message)

257

```

258

259

**Usage Examples:**

260

261

```kotlin

262

import io.ktor.client.plugins.contentnegotiation.*

263

264

try {

265

val response = client.post("https://api.example.com/data") {

266

setBody(complexObject)

267

}

268

val result: MyDataClass = response.body()

269

} catch (e: ContentConverterException) {

270

println("Failed to convert content: ${e.message}")

271

// Handle conversion error

272

}

273

```

274

275

## Types

276

277

### Core Interfaces

278

279

```kotlin { .api }

280

/**

281

* A custom content converter that could be registered in ContentNegotiation plugin for any particular content type

282

* Could provide bi-directional conversion implementation.

283

* One of the most typical examples of content converter is a JSON content converter that provides both

284

* serialization and deserialization. Implementations must override at least one method.

285

*/

286

interface ContentConverter {

287

/**

288

* Serializes a value to the specified contentType to a OutgoingContent.

289

* This function could ignore value if it is not suitable for conversion and return null so in this case

290

* other registered converters could be tried or this function could be invoked with other content types

291

* it the converted has been registered multiple times with different content types.

292

*

293

* @param charset response charset

294

* @param typeInfo response body typeInfo

295

* @param contentType to which this data converter has been registered and that matches the client's Accept header

296

* @param value to be converted

297

* @return a converted OutgoingContent value, or null if value isn't suitable for this converter

298

*/

299

suspend fun serialize(

300

contentType: ContentType,

301

charset: Charset,

302

typeInfo: TypeInfo,

303

value: Any?

304

): OutgoingContent?

305

306

/**

307

* Deserializes content to the value of type typeInfo

308

* @return a converted value (deserialized) or null if the context's subject is not suitable for this converter

309

*/

310

suspend fun deserialize(charset: Charset, typeInfo: TypeInfo, content: ByteReadChannel): Any?

311

}

312

313

/**

314

* Configuration for client and server ContentNegotiation plugin

315

*/

316

interface Configuration {

317

fun <T : ContentConverter> register(

318

contentType: ContentType,

319

converter: T,

320

configuration: T.() -> Unit = {}

321

)

322

}

323

324

/**

325

* Interface for matching content types with custom logic

326

*/

327

interface ContentTypeMatcher {

328

/**

329

* Checks if this type matches a contentType type.

330

*/

331

fun contains(contentType: ContentType): Boolean

332

}

333

```

334

335

### Platform-Specific Default Ignored Types

336

337

```kotlin { .api }

338

/**

339

* Common ignored types across all platforms:

340

* ByteArray, String, HttpStatusCode, ByteReadChannel, OutgoingContent

341

*/

342

internal val DefaultCommonIgnoredTypes: Set<KClass<*>>

343

344

/**

345

* Platform-specific ignored types (expect/actual implementation):

346

* - JVM: includes InputStream

347

* - JS/WASM: empty set

348

* - Native: empty set

349

*/

350

internal expect val DefaultIgnoredTypes: Set<KClass<*>>

351

```

352

353

### Utility Functions

354

355

```kotlin { .api }

356

/**

357

* Detect suitable charset for an application call by Accept header or fallback to defaultCharset

358

*/

359

fun Headers.suitableCharset(defaultCharset: Charset = Charsets.UTF_8): Charset

360

361

/**

362

* Detect suitable charset for an application call by Accept header or fallback to null

363

*/

364

fun Headers.suitableCharsetOrNull(defaultCharset: Charset = Charsets.UTF_8): Charset?

365

```

366

367

## Error Handling

368

369

The ContentNegotiation plugin can throw several types of exceptions:

370

371

- **ContentConverterException**: Thrown when conversion fails during request serialization

372

- **ContentConvertException**: Thrown when no suitable converter found during response deserialization

373

- **Standard HTTP exceptions**: Network-related errors from the underlying HTTP client

374

- **Serialization exceptions**: Format-specific errors from the underlying serialization libraries

375

376

Common error scenarios:

377

- No converter registered for requested content type

378

- Invalid data format during deserialization

379

- Unsupported content type in response

380

- Missing required type information

381

- Type is marked as ignored but conversion was attempted

382

383

```kotlin

384

// Handle conversion errors gracefully

385

try {

386

val result: MyData = client.get("https://api.example.com/data").body()

387

} catch (e: ContentConverterException) {

388

// Log error and use fallback

389

logger.error("Content conversion failed", e)

390

// Handle error appropriately

391

}

392

```