or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

content-serialization.mdindex.mdplugin-configuration.mdraw-websocket-operations.mdsession-operations.mdwebsocket-connections.md

content-serialization.mddocs/

0

# Content Serialization

1

2

Ktor Client WebSockets provides automatic serialization and deserialization of objects through WebSocket frames using Ktor's content conversion system.

3

4

## Serialization Functions

5

6

### sendSerialized() - Send Serialized Objects

7

8

Send objects as WebSocket frames with automatic serialization:

9

10

```kotlin { .api }

11

suspend fun DefaultClientWebSocketSession.sendSerialized(

12

data: Any?,

13

typeInfo: TypeInfo

14

)

15

16

suspend inline fun <reified T> DefaultClientWebSocketSession.sendSerialized(

17

data: T

18

)

19

```

20

21

**Parameters:**

22

- **data**: Object to serialize and send

23

- **typeInfo**: Type information for serialization (manual variant only)

24

25

**Usage:**

26

```kotlin

27

import io.ktor.client.plugins.websocket.*

28

import kotlinx.serialization.*

29

30

@Serializable

31

data class Message(val text: String, val timestamp: Long)

32

33

client.webSocket("ws://example.com/api") {

34

val message = Message("Hello World", System.currentTimeMillis())

35

36

// Send with reified type (recommended)

37

sendSerialized(message)

38

39

// Send with explicit TypeInfo

40

sendSerialized(message, typeInfo<Message>())

41

}

42

```

43

44

### receiveDeserialized() - Receive and Deserialize Objects

45

46

Receive WebSocket frames and automatically deserialize to objects:

47

48

```kotlin { .api }

49

suspend fun <T> DefaultClientWebSocketSession.receiveDeserialized(

50

typeInfo: TypeInfo

51

): T

52

53

suspend inline fun <reified T> DefaultClientWebSocketSession.receiveDeserialized(): T

54

```

55

56

**Parameters:**

57

- **typeInfo**: Type information for deserialization (manual variant only)

58

59

**Returns:**

60

- Deserialized object of type T

61

62

**Usage:**

63

```kotlin

64

client.webSocket("ws://example.com/api") {

65

// Receive with reified type (recommended)

66

val message = receiveDeserialized<Message>()

67

println("Received: ${message.text} at ${message.timestamp}")

68

69

// Receive with explicit TypeInfo

70

val message2 = receiveDeserialized<Message>(typeInfo<Message>())

71

println("Received: ${message2.text}")

72

}

73

```

74

75

## Content Converter Configuration

76

77

Content serialization requires a WebSocket content converter to be configured in the WebSockets plugin:

78

79

```kotlin { .api }

80

var WebSockets.Config.contentConverter: WebsocketContentConverter?

81

```

82

83

### JSON Serialization Setup

84

85

Using kotlinx.serialization with JSON:

86

87

```kotlin

88

import io.ktor.client.*

89

import io.ktor.client.plugins.websocket.*

90

import io.ktor.serialization.kotlinx.*

91

import kotlinx.serialization.json.*

92

93

val client = HttpClient {

94

install(WebSockets) {

95

contentConverter = KotlinxWebsocketSerializationConverter(Json {

96

prettyPrint = true

97

isLenient = true

98

ignoreUnknownKeys = true

99

})

100

}

101

}

102

```

103

104

### Custom Content Converter

105

106

Implement custom serialization logic:

107

108

```kotlin

109

import io.ktor.websocket.*

110

import io.ktor.util.*

111

import io.ktor.util.reflect.*

112

113

class MyWebSocketConverter : WebsocketContentConverter {

114

override suspend fun serialize(

115

charset: Charset,

116

typeInfo: TypeInfo,

117

value: Any?

118

): Frame {

119

// Custom serialization logic

120

val serialized = mySerialize(value)

121

return Frame.Text(serialized)

122

}

123

124

override suspend fun deserialize(

125

charset: Charset,

126

typeInfo: TypeInfo,

127

content: Frame

128

): Any? {

129

// Custom deserialization logic

130

return when (content) {

131

is Frame.Text -> myDeserialize(content.readText(), typeInfo)

132

is Frame.Binary -> myDeserializeBinary(content.data, typeInfo)

133

else -> throw WebSocketException("Unsupported frame type for deserialization")

134

}

135

}

136

137

override fun isApplicable(frame: Frame): Boolean {

138

return frame is Frame.Text || frame is Frame.Binary

139

}

140

}

141

142

// Install custom converter

143

val client = HttpClient {

144

install(WebSockets) {

145

contentConverter = MyWebSocketConverter()

146

}

147

}

148

```

149

150

## Serialization Examples

151

152

### Basic Object Serialization

153

154

```kotlin

155

import kotlinx.serialization.*

156

157

@Serializable

158

data class ChatMessage(

159

val user: String,

160

val message: String,

161

val timestamp: Long = System.currentTimeMillis()

162

)

163

164

client.webSocket("ws://chat.example.com/room/general") {

165

// Send chat message

166

val chatMsg = ChatMessage("alice", "Hello everyone!")

167

sendSerialized(chatMsg)

168

169

// Receive chat messages

170

for (frame in incoming) {

171

when (frame) {

172

is Frame.Text -> {

173

try {

174

val received = receiveDeserialized<ChatMessage>()

175

println("${received.user}: ${received.message}")

176

} catch (e: Exception) {

177

println("Failed to deserialize: ${frame.readText()}")

178

}

179

}

180

is Frame.Close -> break

181

else -> { /* Handle other frame types */ }

182

}

183

}

184

}

185

```

186

187

### Complex Data Structures

188

189

```kotlin

190

@Serializable

191

data class GameState(

192

val players: List<Player>,

193

val currentTurn: String,

194

val board: Map<String, String>,

195

val settings: GameSettings

196

)

197

198

@Serializable

199

data class Player(val id: String, val name: String, val score: Int)

200

201

@Serializable

202

data class GameSettings(val maxPlayers: Int, val timeLimit: Long)

203

204

client.webSocket("ws://game.example.com/session/123") {

205

// Send complex game state

206

val gameState = GameState(

207

players = listOf(

208

Player("p1", "Alice", 100),

209

Player("p2", "Bob", 85)

210

),

211

currentTurn = "p1",

212

board = mapOf("a1" to "X", "b2" to "O"),

213

settings = GameSettings(maxPlayers = 4, timeLimit = 300_000)

214

)

215

sendSerialized(gameState)

216

217

// Receive updated game state

218

val updatedState = receiveDeserialized<GameState>()

219

println("Game updated: ${updatedState.players.size} players")

220

}

221

```

222

223

### Mixed Content Communication

224

225

Combine serialized objects with raw frames:

226

227

```kotlin

228

client.webSocket("ws://api.example.com/mixed") {

229

// Send serialized object

230

sendSerialized(ChatMessage("system", "User connected"))

231

232

// Send raw text frame

233

send("Raw status message")

234

235

// Receive mixed content

236

for (frame in incoming) {

237

when (frame) {

238

is Frame.Text -> {

239

val text = frame.readText()

240

241

// Try to deserialize as known type

242

try {

243

val message = receiveDeserialized<ChatMessage>()

244

println("Structured: ${message.user} - ${message.message}")

245

} catch (e: Exception) {

246

// Handle as raw text

247

println("Raw: $text")

248

}

249

}

250

is Frame.Close -> break

251

else -> { /* Handle other frames */ }

252

}

253

}

254

}

255

```

256

257

## Error Handling

258

259

### Serialization Errors

260

261

Handle serialization failures gracefully:

262

263

```kotlin

264

client.webSocket("ws://example.com/api") {

265

try {

266

val message = Message("test", System.currentTimeMillis())

267

sendSerialized(message)

268

} catch (e: SerializationException) {

269

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

270

// Fallback to raw frame

271

send("Serialization failed - sending raw text")

272

} catch (e: Exception) {

273

println("Unexpected error during serialization: ${e.message}")

274

}

275

}

276

```

277

278

### Deserialization Errors

279

280

Handle deserialization failures:

281

282

```kotlin

283

client.webSocket("ws://example.com/api") {

284

for (frame in incoming) {

285

when (frame) {

286

is Frame.Text -> {

287

try {

288

val message = receiveDeserialized<Message>()

289

processMessage(message)

290

} catch (e: SerializationException) {

291

println("Failed to deserialize frame: ${e.message}")

292

// Handle as raw text

293

val rawText = frame.readText()

294

processRawMessage(rawText)

295

} catch (e: Exception) {

296

println("Unexpected deserialization error: ${e.message}")

297

}

298

}

299

is Frame.Close -> break

300

else -> { /* Handle other frame types */ }

301

}

302

}

303

}

304

```

305

306

### Missing Content Converter

307

308

Handle cases where no content converter is configured:

309

310

```kotlin

311

client.webSocket("ws://example.com/api") {

312

if (converter != null) {

313

// Use serialization

314

sendSerialized(MyData("test"))

315

val response = receiveDeserialized<MyResponse>()

316

} else {

317

// Fall back to raw frames

318

send("Raw message without serialization")

319

val frame = incoming.receive()

320

if (frame is Frame.Text) {

321

val response = frame.readText()

322

println("Raw response: $response")

323

}

324

}

325

}

326

```

327

328

## Binary Serialization

329

330

Handle binary data serialization:

331

332

```kotlin

333

@Serializable

334

data class BinaryMessage(

335

val header: String,

336

val payload: ByteArray

337

) {

338

override fun equals(other: Any?): Boolean {

339

if (this === other) return true

340

if (other !is BinaryMessage) return false

341

if (header != other.header) return false

342

if (!payload.contentEquals(other.payload)) return false

343

return true

344

}

345

346

override fun hashCode(): Int {

347

var result = header.hashCode()

348

result = 31 * result + payload.contentHashCode()

349

return result

350

}

351

}

352

353

// Configure for binary serialization

354

val client = HttpClient {

355

install(WebSockets) {

356

contentConverter = KotlinxWebsocketSerializationConverter(

357

ProtoBuf // or other binary format

358

)

359

}

360

}

361

362

client.webSocket("ws://example.com/binary") {

363

// Send binary message

364

val binaryMsg = BinaryMessage("header", byteArrayOf(1, 2, 3, 4))

365

sendSerialized(binaryMsg)

366

367

// Receive binary message

368

val received = receiveDeserialized<BinaryMessage>()

369

println("Header: ${received.header}, Payload size: ${received.payload.size}")

370

}

371

```

372

373

## Performance Considerations

374

375

### Chunked Serialization

376

377

For large objects, consider chunking:

378

379

```kotlin

380

@Serializable

381

data class LargeDataSet(val items: List<DataItem>)

382

383

client.webSocket("ws://example.com/large-data") {

384

val largeData = generateLargeDataSet()

385

386

// Check frame size limits

387

if (maxFrameSize < estimateSerializedSize(largeData)) {

388

// Chunk the data

389

largeData.items.chunked(100).forEach { chunk ->

390

sendSerialized(DataChunk(chunk))

391

}

392

sendSerialized(EndOfData())

393

} else {

394

// Send as single frame

395

sendSerialized(largeData)

396

}

397

}

398

```

399

400

### Streaming Serialization

401

402

For continuous data streams:

403

404

```kotlin

405

client.webSocket("ws://example.com/stream") {

406

// Stream data as individual serialized frames

407

generateDataStream().collect { dataPoint ->

408

sendSerialized(dataPoint)

409

410

// Optional: Add throttling

411

delay(10) // 100 FPS max

412

}

413

}

414

```

415

416

## Content Type Handling

417

418

Different serialization formats can be configured:

419

420

```kotlin

421

// JSON serialization

422

install(WebSockets) {

423

contentConverter = KotlinxWebsocketSerializationConverter(Json)

424

}

425

426

// Protocol Buffers serialization

427

install(WebSockets) {

428

contentConverter = KotlinxWebsocketSerializationConverter(ProtoBuf)

429

}

430

431

// CBOR serialization

432

install(WebSockets) {

433

contentConverter = KotlinxWebsocketSerializationConverter(Cbor)

434

}

435

436

// XML serialization

437

install(WebSockets) {

438

contentConverter = KotlinxWebsocketSerializationConverter(XML)

439

}

440

```