0
# Response Handling
1
2
Comprehensive HTTP response processing including body extraction, status handling, streaming support, and type-safe response parsing.
3
4
## Capabilities
5
6
### Response Body Extraction
7
8
Extract response bodies in various formats with type safety and charset handling.
9
10
```kotlin { .api }
11
/**
12
* Get response body as text with optional charset
13
* @param charset Character encoding (default: UTF-8)
14
* @returns Response body as String
15
*/
16
suspend fun HttpResponse.bodyAsText(charset: Charset = Charsets.UTF_8): String
17
18
/**
19
* Get response body as ByteReadChannel for streaming
20
* @returns ByteReadChannel for reading response data
21
*/
22
suspend fun HttpResponse.bodyAsChannel(): ByteReadChannel
23
24
/**
25
* Get response body as ByteArray
26
* @returns Complete response body as byte array
27
*/
28
suspend fun HttpResponse.readBytes(): ByteArray
29
30
/**
31
* Get typed response body using content negotiation
32
* @returns Deserialized response body of type T
33
*/
34
suspend inline fun <reified T> HttpResponse.body(): T
35
36
/**
37
* Get typed response body with explicit TypeInfo
38
* @param typeInfo Type information for deserialization
39
* @returns Deserialized response body
40
*/
41
suspend fun <T> HttpResponse.body(typeInfo: TypeInfo): T
42
```
43
44
**Usage Examples:**
45
46
```kotlin
47
val client = HttpClient()
48
49
// Get response as text
50
val response = client.get("https://api.example.com/users")
51
val jsonText = response.bodyAsText()
52
53
// Get response as bytes
54
val imageResponse = client.get("https://example.com/image.jpg")
55
val imageBytes = imageResponse.readBytes()
56
57
// Get typed response (requires content negotiation plugin)
58
val usersResponse = client.get("https://api.example.com/users")
59
val users: List<User> = usersResponse.body()
60
61
// Streaming response
62
val largeFileResponse = client.get("https://example.com/largefile.zip")
63
val channel = largeFileResponse.bodyAsChannel()
64
while (!channel.isClosedForRead) {
65
val chunk = channel.readBuffer()
66
// Process chunk
67
}
68
```
69
70
### HttpResponse Interface
71
72
Core response interface providing access to status, headers, and metadata.
73
74
```kotlin { .api }
75
/**
76
* HTTP response representation
77
*/
78
interface HttpResponse {
79
/** HTTP status code and message */
80
val status: HttpStatusCode
81
82
/** Response headers */
83
val headers: Headers
84
85
/** Associated HTTP call */
86
val call: HttpClientCall
87
88
/** HTTP protocol version */
89
val version: HttpProtocolVersion
90
91
/** Request timestamp */
92
val requestTime: GMTDate
93
94
/** Response timestamp */
95
val responseTime: GMTDate
96
97
/** Response content */
98
val content: ByteReadChannel
99
}
100
101
/**
102
* Default implementation of HttpResponse
103
*/
104
class DefaultHttpResponse(
105
override val call: HttpClientCall,
106
override val status: HttpStatusCode,
107
override val version: HttpProtocolVersion,
108
override val requestTime: GMTDate,
109
override val responseTime: GMTDate,
110
override val content: ByteReadChannel,
111
override val headers: Headers
112
) : HttpResponse
113
```
114
115
**Usage Examples:**
116
117
```kotlin
118
val response = client.get("https://api.example.com/users")
119
120
// Check status
121
when (response.status.value) {
122
in 200..299 -> println("Success: ${response.status}")
123
in 400..499 -> println("Client error: ${response.status}")
124
in 500..599 -> println("Server error: ${response.status}")
125
}
126
127
// Access headers
128
val contentType = response.headers["Content-Type"]
129
val contentLength = response.headers["Content-Length"]?.toLong()
130
131
// Check protocol version
132
if (response.version == HttpProtocolVersion.HTTP_2_0) {
133
println("Using HTTP/2")
134
}
135
136
// Check timing
137
val duration = response.responseTime - response.requestTime
138
println("Request took ${duration}ms")
139
```
140
141
### HttpStatement Class
142
143
Prepared HTTP statement for lazy execution and advanced response handling.
144
145
```kotlin { .api }
146
/**
147
* Prepared HTTP statement ready for execution
148
*/
149
class HttpStatement {
150
/** The prepared request builder */
151
val builder: HttpRequestBuilder
152
153
/** The client that will execute this statement */
154
val client: HttpClient
155
156
/**
157
* Execute the statement and return the response
158
* @returns HttpResponse
159
*/
160
suspend fun execute(): HttpResponse
161
162
/**
163
* Execute the statement with custom response handling
164
* @param block Response processing block
165
* @returns Result of the processing block
166
*/
167
suspend fun <T> execute(block: suspend (HttpResponse) -> T): T
168
}
169
```
170
171
**Usage Examples:**
172
173
```kotlin
174
// Prepare statement
175
val statement = client.prepareGet("https://api.example.com/users")
176
177
// Execute multiple times
178
val response1 = statement.execute()
179
val response2 = statement.execute()
180
181
// Execute with custom handling
182
val userCount = statement.execute { response ->
183
val users: List<User> = response.body()
184
users.size
185
}
186
187
// Execute with resource management
188
val result = statement.execute { response ->
189
response.bodyAsChannel().use { channel ->
190
// Process streaming data
191
var totalBytes = 0L
192
while (!channel.isClosedForRead) {
193
val buffer = channel.readBuffer()
194
totalBytes += buffer.remaining
195
}
196
totalBytes
197
}
198
}
199
```
200
201
### Response Pipeline Processing
202
203
Access to response processing pipeline for advanced scenarios.
204
205
```kotlin { .api }
206
/**
207
* Response processing pipeline
208
*/
209
class HttpResponsePipeline {
210
/** Receive phase for initial response processing */
211
val Receive: PipelinePhase
212
213
/** Parse phase for content transformation */
214
val Parse: PipelinePhase
215
216
/** Transform phase for final processing */
217
val Transform: PipelinePhase
218
219
/**
220
* Execute the pipeline with response data
221
* @param context Pipeline context
222
* @param subject Initial subject
223
* @returns Processed result
224
*/
225
suspend fun execute(context: HttpResponseContainer, subject: Any): Any
226
}
227
228
/**
229
* Response container for pipeline processing
230
*/
231
data class HttpResponseContainer(
232
val expectedType: TypeInfo,
233
val response: HttpResponse
234
)
235
```
236
237
### Content Type and Encoding
238
239
Functions for handling content types and character encodings.
240
241
```kotlin { .api }
242
/**
243
* Get content type from response headers
244
* @returns ContentType object or null
245
*/
246
fun HttpResponse.contentType(): ContentType?
247
248
/**
249
* Get charset from content type header
250
* @returns Charset object or default
251
*/
252
fun HttpResponse.charset(): Charset
253
254
/**
255
* Check if response has specific content type
256
* @param contentType Expected content type
257
* @returns True if content type matches
258
*/
259
fun HttpResponse.contentType(contentType: ContentType): Boolean
260
```
261
262
**Usage Examples:**
263
264
```kotlin
265
val response = client.get("https://api.example.com/data")
266
267
// Check content type
268
val contentType = response.contentType()
269
when {
270
contentType?.match(ContentType.Application.Json) == true -> {
271
val jsonData = response.bodyAsText()
272
// Process JSON
273
}
274
contentType?.match(ContentType.Text.Html) == true -> {
275
val htmlContent = response.bodyAsText()
276
// Process HTML
277
}
278
contentType?.match(ContentType.Application.OctetStream) == true -> {
279
val binaryData = response.readBytes()
280
// Process binary data
281
}
282
}
283
284
// Handle charset
285
val charset = response.charset()
286
val text = response.bodyAsText(charset)
287
```
288
289
### Response Validation
290
291
Response validation and error handling utilities.
292
293
```kotlin { .api }
294
/**
295
* Check if response is successful (2xx status code)
296
* @returns True if status code is 2xx
297
*/
298
fun HttpResponse.isSuccessful(): Boolean
299
300
/**
301
* Throw exception if response is not successful
302
* @throws ResponseException for non-2xx status codes
303
*/
304
suspend fun HttpResponse.ensureSuccess()
305
306
/**
307
* Get response body as text only if successful, null otherwise
308
* @returns Response body text or null
309
*/
310
suspend fun HttpResponse.bodyAsTextOrNull(): String?
311
```
312
313
**Usage Examples:**
314
315
```kotlin
316
val response = client.get("https://api.example.com/users")
317
318
// Check success
319
if (response.isSuccessful()) {
320
val data = response.bodyAsText()
321
// Process successful response
322
} else {
323
println("Request failed with status: ${response.status}")
324
}
325
326
// Ensure success (throws exception if not successful)
327
try {
328
response.ensureSuccess()
329
val data = response.bodyAsText()
330
} catch (e: ResponseException) {
331
println("Request failed: ${e.message}")
332
}
333
334
// Safe body extraction
335
val safeData = response.bodyAsTextOrNull()
336
if (safeData != null) {
337
// Process data
338
}
339
```
340
341
## Types
342
343
### Response Types
344
345
```kotlin { .api }
346
/**
347
* HTTP status code representation
348
*/
349
data class HttpStatusCode(
350
val value: Int,
351
val description: String
352
) {
353
companion object {
354
// 2xx Success
355
val OK: HttpStatusCode
356
val Created: HttpStatusCode
357
val Accepted: HttpStatusCode
358
val NoContent: HttpStatusCode
359
360
// 3xx Redirection
361
val MovedPermanently: HttpStatusCode
362
val Found: HttpStatusCode
363
val NotModified: HttpStatusCode
364
365
// 4xx Client Error
366
val BadRequest: HttpStatusCode
367
val Unauthorized: HttpStatusCode
368
val Forbidden: HttpStatusCode
369
val NotFound: HttpStatusCode
370
371
// 5xx Server Error
372
val InternalServerError: HttpStatusCode
373
val BadGateway: HttpStatusCode
374
val ServiceUnavailable: HttpStatusCode
375
}
376
}
377
378
/**
379
* HTTP protocol version
380
*/
381
enum class HttpProtocolVersion(val name: String, val major: Int, val minor: Int) {
382
HTTP_1_0("HTTP/1.0", 1, 0),
383
HTTP_1_1("HTTP/1.1", 1, 1),
384
HTTP_2_0("HTTP/2.0", 2, 0),
385
SPDY_3("SPDY/3.1", 3, 1),
386
QUIC("QUIC", 1, 0)
387
}
388
389
/**
390
* GMT date representation for timestamps
391
*/
392
data class GMTDate(
393
val timestamp: Long,
394
val seconds: Int,
395
val minutes: Int,
396
val hours: Int,
397
val dayOfMonth: Int,
398
val month: Month,
399
val year: Int,
400
val dayOfWeek: DayOfWeek,
401
val dayOfYear: Int
402
) {
403
companion object {
404
fun start(): GMTDate
405
fun parse(date: String): GMTDate
406
}
407
}
408
```
409
410
### Content Types
411
412
```kotlin { .api }
413
/**
414
* Content type representation
415
*/
416
data class ContentType(
417
val contentType: String,
418
val contentSubtype: String,
419
val parameters: List<HeaderValueParam> = emptyList()
420
) {
421
companion object {
422
object Application {
423
val Json: ContentType
424
val Xml: ContentType
425
val OctetStream: ContentType
426
val FormUrlEncoded: ContentType
427
val Pdf: ContentType
428
}
429
430
object Text {
431
val Plain: ContentType
432
val Html: ContentType
433
val CSS: ContentType
434
val JavaScript: ContentType
435
}
436
437
object Image {
438
val JPEG: ContentType
439
val PNG: ContentType
440
val GIF: ContentType
441
val SVG: ContentType
442
}
443
444
object Audio {
445
val MPEG: ContentType
446
val OGG: ContentType
447
}
448
449
object Video {
450
val MPEG: ContentType
451
val MP4: ContentType
452
}
453
}
454
455
fun match(pattern: ContentType): Boolean
456
fun match(contentType: String): Boolean
457
fun withParameter(name: String, value: String): ContentType
458
}
459
460
/**
461
* Character set enumeration
462
*/
463
object Charsets {
464
val UTF_8: Charset
465
val UTF_16: Charset
466
val ISO_8859_1: Charset
467
val US_ASCII: Charset
468
}
469
```
470
471
### Exception Types
472
473
```kotlin { .api }
474
/**
475
* Base exception for HTTP response errors
476
*/
477
open class ResponseException(
478
response: HttpResponse,
479
cachedResponseText: String
480
) : Exception(cachedResponseText) {
481
val response: HttpResponse
482
}
483
484
/**
485
* Exception for client errors (4xx status codes)
486
*/
487
class ClientRequestException(
488
response: HttpResponse,
489
cachedResponseText: String
490
) : ResponseException(response, cachedResponseText)
491
492
/**
493
* Exception for server errors (5xx status codes)
494
*/
495
class ServerResponseException(
496
response: HttpResponse,
497
cachedResponseText: String
498
) : ResponseException(response, cachedResponseText)
499
500
/**
501
* Exception for redirect errors
502
*/
503
class RedirectResponseException(
504
response: HttpResponse,
505
cachedResponseText: String
506
) : ResponseException(response, cachedResponseText)
507
```