0
# Built-in Plugins
1
2
The Ktor HTTP Client Core comes with a comprehensive set of built-in plugins that provide essential functionality for HTTP client operations. These plugins handle common cross-cutting concerns like redirects, retries, timeouts, response validation, and more.
3
4
## Core Built-in Plugins
5
6
### HttpRedirect
7
8
Automatic HTTP redirect handling plugin that follows redirect responses according to HTTP specifications.
9
10
```kotlin { .api }
11
object HttpRedirect : HttpClientPlugin<HttpRedirect.Config, HttpRedirect> {
12
class Config {
13
var checkHttpMethod: Boolean = true
14
var allowHttpsDowngrade: Boolean = false
15
var maxJumps: Int = 20
16
17
fun checkHttpMethod(block: (HttpMethod) -> Boolean)
18
fun allowHttpsDowngrade(allow: Boolean)
19
}
20
}
21
```
22
23
**Usage Example:**
24
25
```kotlin
26
val client = HttpClient {
27
install(HttpRedirect) {
28
checkHttpMethod = true
29
allowHttpsDowngrade = false
30
maxJumps = 10
31
}
32
}
33
34
// Automatically follows redirects
35
val response = client.get("https://httpbin.org/redirect/3")
36
```
37
38
### HttpRequestRetry
39
40
Request retry logic plugin that automatically retries failed requests based on configurable conditions.
41
42
```kotlin { .api }
43
object HttpRequestRetry : HttpClientPlugin<HttpRequestRetry.Config, HttpRequestRetry> {
44
class Config {
45
var maxRetries: Int = 3
46
var retryOnExceptionOrServerErrors: Boolean = true
47
var delayMillis: (retry: Int) -> Long = { retry -> retry * 1000L }
48
var modifyRequest: suspend HttpRequestBuilder.(retry: Int) -> Unit = {}
49
50
fun retryOnException(retries: Int = 3, block: suspend RetryEventData.() -> Boolean = { true })
51
fun retryOnServerErrors(maxRetries: Int = 3)
52
fun retryIf(block: suspend RetryEventData.(HttpResponse) -> Boolean)
53
fun exponentialDelay(base: Double = 2.0, maxDelayMs: Long = 60000)
54
fun constantDelay(delayMs: Long = 1000)
55
fun linearDelay(delayMs: Long = 1000)
56
}
57
58
class RetryEventData(
59
val executionCount: Int,
60
val request: HttpRequestBuilder,
61
val response: HttpResponse?,
62
val cause: Throwable?
63
)
64
}
65
```
66
67
**Usage Example:**
68
69
```kotlin
70
val client = HttpClient {
71
install(HttpRequestRetry) {
72
retryOnServerErrors(maxRetries = 3)
73
exponentialDelay()
74
75
retryIf { request, response ->
76
response.status.value >= 500
77
}
78
79
modifyRequest { retry ->
80
header("X-Retry-Count", retry.toString())
81
}
82
}
83
}
84
85
// Automatically retries on failures
86
val response = client.get("https://unstable-api.example.com/data")
87
```
88
89
### HttpTimeout
90
91
Request timeout handling plugin for configuring connection, request, and socket timeouts.
92
93
```kotlin { .api }
94
object HttpTimeout : HttpClientPlugin<HttpTimeout.Config, HttpTimeout> {
95
class Config {
96
var requestTimeoutMillis: Long? = null
97
var connectTimeoutMillis: Long? = null
98
var socketTimeoutMillis: Long? = null
99
}
100
}
101
```
102
103
**Usage Example:**
104
105
```kotlin
106
val client = HttpClient {
107
install(HttpTimeout) {
108
requestTimeoutMillis = 30000
109
connectTimeoutMillis = 5000
110
socketTimeoutMillis = 10000
111
}
112
}
113
114
// Per-request timeout override
115
val response = client.get("https://slow-api.example.com/data") {
116
timeout {
117
requestTimeoutMillis = 60000
118
}
119
}
120
```
121
122
### UserAgent
123
124
User agent header plugin for setting a consistent User-Agent header across all requests.
125
126
```kotlin { .api }
127
object UserAgent : HttpClientPlugin<UserAgent.Config, UserAgent> {
128
class Config {
129
var agent: String = "Ktor HTTP Client"
130
}
131
}
132
```
133
134
**Usage Example:**
135
136
```kotlin
137
val client = HttpClient {
138
install(UserAgent) {
139
agent = "MyApp/1.0 (https://example.com)"
140
}
141
}
142
143
// All requests will include the User-Agent header
144
val response = client.get("https://httpbin.org/user-agent")
145
```
146
147
### DefaultRequest
148
149
Default request configuration plugin for applying common settings to all requests.
150
151
```kotlin { .api }
152
object DefaultRequest : HttpClientPlugin<DefaultRequest.Config, DefaultRequest> {
153
class Config : HttpRequestBuilder() {
154
// Inherits all HttpRequestBuilder functionality
155
// for setting default URL, headers, etc.
156
}
157
}
158
```
159
160
**Usage Example:**
161
162
```kotlin
163
val client = HttpClient {
164
install(DefaultRequest) {
165
url {
166
protocol = URLProtocol.HTTPS
167
host = "api.example.com"
168
port = 443
169
}
170
header("Authorization", "Bearer $token")
171
header("Content-Type", "application/json")
172
parameter("api_version", "v1")
173
}
174
}
175
176
// All requests inherit default configuration
177
val response = client.get("/users") // Calls https://api.example.com/users?api_version=v1
178
```
179
180
### HttpCallValidator
181
182
Response validation plugin for validating responses and handling exceptions.
183
184
```kotlin { .api }
185
object HttpCallValidator : HttpClientPlugin<HttpCallValidator.Config, HttpCallValidator> {
186
class Config {
187
internal val responseValidators = mutableListOf<suspend (response: HttpResponse) -> Unit>()
188
internal val responseExceptionHandlers = mutableListOf<suspend (exception: Throwable) -> Unit>()
189
190
fun validateResponse(block: suspend (response: HttpResponse) -> Unit)
191
fun handleResponseException(block: suspend (exception: Throwable) -> Unit)
192
fun handleResponseExceptionWithRequest(
193
block: suspend (exception: Throwable, request: HttpRequest) -> Unit
194
)
195
}
196
}
197
```
198
199
**Usage Example:**
200
201
```kotlin
202
val client = HttpClient {
203
install(HttpCallValidator) {
204
validateResponse { response ->
205
val statusCode = response.status.value
206
if (statusCode >= 400) {
207
throw ClientRequestException(response, "Request failed with status $statusCode")
208
}
209
}
210
211
handleResponseException { exception ->
212
when (exception) {
213
is ClientRequestException -> {
214
println("Client error: ${exception.response.status}")
215
throw exception
216
}
217
is ServerResponseException -> {
218
println("Server error: ${exception.response.status}")
219
throw exception
220
}
221
}
222
}
223
}
224
}
225
```
226
227
### HttpPlainText
228
229
Plain text content handling plugin for automatic text serialization and deserialization.
230
231
```kotlin { .api }
232
object HttpPlainText : HttpClientPlugin<HttpPlainText.Config, HttpPlainText> {
233
class Config {
234
var charsets: MutableSet<Charset> = mutableSetOf(Charsets.UTF_8)
235
236
fun register(
237
contentType: ContentType,
238
converter: suspend (text: String) -> Any
239
)
240
241
fun register(
242
contentType: ContentType,
243
converter: suspend (charset: Charset, text: String) -> Any
244
)
245
}
246
}
247
```
248
249
**Usage Example:**
250
251
```kotlin
252
val client = HttpClient {
253
install(HttpPlainText) {
254
charsets = mutableSetOf(Charsets.UTF_8, Charsets.ISO_8859_1)
255
256
// Custom text converter for CSV
257
register(ContentType.Text.CSV) { text ->
258
text.lines().map { line -> line.split(",") }
259
}
260
}
261
}
262
263
// Automatic text conversion
264
val csvData: List<List<String>> = client.get("https://example.com/data.csv").body()
265
```
266
267
### HttpSend
268
269
Request sending pipeline plugin for intercepting and modifying the send phase of requests.
270
271
```kotlin { .api }
272
object HttpSend : HttpClientPlugin<HttpSend.Config, HttpSend> {
273
class Config {
274
internal val interceptors = mutableListOf<suspend Sender.(HttpRequestBuilder) -> HttpResponse>()
275
276
fun intercept(block: suspend Sender.(request: HttpRequestBuilder) -> HttpResponse)
277
}
278
279
interface Sender {
280
suspend fun execute(requestBuilder: HttpRequestBuilder): HttpResponse
281
}
282
}
283
```
284
285
**Usage Example:**
286
287
```kotlin
288
val client = HttpClient {
289
install(HttpSend) {
290
intercept { request ->
291
// Log request details
292
println("Sending ${request.method.value} request to ${request.url}")
293
294
// Add timestamp header
295
request.header("X-Request-Time", Clock.System.now().toString())
296
297
// Continue with the request
298
execute(request)
299
}
300
}
301
}
302
```
303
304
### DataConversion
305
306
Data conversion plugin for automatic serialization and deserialization of request/response bodies.
307
308
```kotlin { .api }
309
object DataConversion : HttpClientPlugin<DataConversion.Config, DataConversion> {
310
class Config {
311
internal val converters = mutableListOf<ContentConverter>()
312
313
fun register(
314
contentType: ContentType,
315
converter: ContentConverter,
316
configuration: ContentConverterConfiguration.() -> Unit = {}
317
)
318
}
319
320
interface ContentConverter {
321
suspend fun serialize(
322
contentType: ContentType,
323
charset: Charset,
324
typeInfo: TypeInfo,
325
value: Any
326
): OutgoingContent
327
328
suspend fun deserialize(
329
charset: Charset,
330
typeInfo: TypeInfo,
331
content: ByteReadChannel
332
): Any
333
}
334
}
335
```
336
337
**Usage Example:**
338
339
```kotlin
340
// Note: DataConversion is typically used by higher-level serialization plugins
341
// like JSON, XML, etc. Direct usage is for custom serialization formats.
342
343
val client = HttpClient {
344
install(DataConversion) {
345
register(
346
ContentType.Application.Json,
347
MyJsonConverter()
348
)
349
}
350
}
351
```
352
353
### BodyProgress
354
355
Body upload/download progress tracking plugin for monitoring transfer progress.
356
357
```kotlin { .api }
358
object BodyProgress : HttpClientPlugin<BodyProgress.Config, BodyProgress> {
359
class Config {
360
internal val sendProgressListeners = mutableListOf<ProgressListener>()
361
internal val receiveProgressListeners = mutableListOf<ProgressListener>()
362
363
fun onUpload(listener: ProgressListener)
364
fun onDownload(listener: ProgressListener)
365
}
366
367
typealias ProgressListener = (bytesSentTotal: Long, contentLength: Long?) -> Unit
368
}
369
```
370
371
**Usage Example:**
372
373
```kotlin
374
val client = HttpClient {
375
install(BodyProgress) {
376
onUpload { bytesSentTotal, contentLength ->
377
val progress = contentLength?.let { (bytesSentTotal * 100 / it).toInt() } ?: 0
378
println("Upload progress: $progress% ($bytesSentTotal bytes)")
379
}
380
381
onDownload { bytesReceivedTotal, contentLength ->
382
val progress = contentLength?.let { (bytesReceivedTotal * 100 / it).toInt() } ?: 0
383
println("Download progress: $progress% ($bytesReceivedTotal bytes)")
384
}
385
}
386
}
387
388
// Progress will be tracked for file uploads/downloads
389
val response = client.post("https://httpbin.org/post") {
390
setBody("Large file content...")
391
}
392
```
393
394
## Installation and Configuration
395
396
All built-in plugins follow the same installation pattern:
397
398
```kotlin
399
val client = HttpClient {
400
install(PluginName) {
401
// Plugin-specific configuration
402
}
403
}
404
```
405
406
Multiple plugins can be installed together:
407
408
```kotlin
409
val client = HttpClient {
410
install(HttpTimeout) {
411
requestTimeoutMillis = 30000
412
}
413
414
install(HttpRequestRetry) {
415
retryOnServerErrors(maxRetries = 3)
416
}
417
418
install(UserAgent) {
419
agent = "MyApp/1.0"
420
}
421
422
install(HttpCallValidator) {
423
validateResponse { response ->
424
if (response.status.value >= 400) {
425
throw Exception("Request failed")
426
}
427
}
428
}
429
}
430
```
431
432
## Plugin Dependencies
433
434
Some plugins work better together or have implicit dependencies:
435
436
- **HttpCallValidator** should be installed after content plugins like JSON serialization
437
- **HttpRequestRetry** works with **HttpTimeout** for comprehensive error handling
438
- **DefaultRequest** should be installed early to provide base configuration for other plugins
439
- **BodyProgress** works with any plugin that processes request/response bodies
440
441
## Best Practices
442
443
1. **Install plugins in logical order**: Configuration plugins first, then processing plugins, then validation plugins
444
2. **Use appropriate timeouts**: Configure realistic timeout values based on your use case
445
3. **Handle retries carefully**: Avoid retrying non-idempotent operations unless specifically designed for it
446
4. **Validate responses**: Always use HttpCallValidator for production applications
447
5. **Monitor progress**: Use BodyProgress for large file transfers to provide user feedback
448
6. **Set user agents**: Always identify your application with a proper User-Agent header