0
# Form Handling
1
2
Support for URL-encoded forms and multipart form data with file uploads, providing type-safe form submission capabilities.
3
4
## Capabilities
5
6
### FormDataContent Class
7
8
URL-encoded form content for simple form submissions.
9
10
```kotlin { .api }
11
/**
12
* URL-encoded form content implementation
13
*/
14
class FormDataContent(val formData: Parameters) : OutgoingContent.ByteArrayContent() {
15
/** Form parameters */
16
val formData: Parameters
17
18
/** Content length in bytes */
19
override val contentLength: Long
20
21
/** Content type (application/x-www-form-urlencoded) */
22
override val contentType: ContentType
23
24
/**
25
* Get form data as byte array
26
*/
27
override fun bytes(): ByteArray
28
}
29
```
30
31
**Usage Examples:**
32
33
```kotlin
34
import io.ktor.client.request.forms.*
35
import io.ktor.http.*
36
37
// Create form data
38
val formData = FormDataContent(Parameters.build {
39
append("username", "john_doe")
40
append("password", "secret123")
41
append("remember", "true")
42
})
43
44
// Send form data
45
val response = client.post("https://api.example.com/login") {
46
setBody(formData)
47
}
48
```
49
50
### MultiPartFormDataContent Class
51
52
Multipart form data content for complex forms with file uploads.
53
54
```kotlin { .api }
55
/**
56
* Multipart form data content implementation
57
*/
58
class MultiPartFormDataContent(
59
parts: List<PartData>,
60
boundary: String,
61
contentType: ContentType = ContentType.MultiPart.FormData.withParameter("boundary", boundary)
62
) : OutgoingContent.WriteChannelContent() {
63
/** Multipart boundary string */
64
val boundary: String
65
66
/** Content type (multipart/form-data) */
67
override val contentType: ContentType
68
69
/** Content length if determinable */
70
override val contentLength: Long?
71
72
/**
73
* Write multipart content to channel
74
*/
75
override suspend fun writeTo(channel: ByteWriteChannel)
76
}
77
```
78
79
### Form Submission Functions
80
81
Convenience functions for submitting forms with various content types.
82
83
```kotlin { .api }
84
/**
85
* Submit URL-encoded form
86
*/
87
suspend fun HttpClient.submitForm(
88
formParameters: Parameters,
89
encodeInQuery: Boolean = false,
90
block: HttpRequestBuilder.() -> Unit = {}
91
): HttpResponse
92
93
/**
94
* Submit URL-encoded form with URL
95
*/
96
suspend fun HttpClient.submitForm(
97
url: String,
98
formParameters: Parameters,
99
encodeInQuery: Boolean = false,
100
block: HttpRequestBuilder.() -> Unit = {}
101
): HttpResponse
102
103
/**
104
* Submit multipart form with binary data
105
*/
106
suspend fun HttpClient.submitFormWithBinaryData(
107
formData: List<PartData>,
108
block: HttpRequestBuilder.() -> Unit = {}
109
): HttpResponse
110
111
/**
112
* Submit multipart form with binary data and URL
113
*/
114
suspend fun HttpClient.submitFormWithBinaryData(
115
url: String,
116
formData: List<PartData>,
117
block: HttpRequestBuilder.() -> Unit = {}
118
): HttpResponse
119
```
120
121
**Usage Examples:**
122
123
```kotlin
124
// Simple form submission
125
val loginParams = Parameters.build {
126
append("username", "alice")
127
append("password", "secret")
128
}
129
130
val loginResponse = client.submitForm(
131
url = "https://api.example.com/login",
132
formParameters = loginParams
133
) {
134
headers["User-Agent"] = "MyApp/1.0"
135
}
136
137
// Form data in query string
138
val searchResponse = client.submitForm(
139
url = "https://api.example.com/search",
140
formParameters = Parameters.build {
141
append("q", "kotlin")
142
append("limit", "10")
143
},
144
encodeInQuery = true // Use GET with query parameters
145
)
146
147
// Multipart form with file upload
148
val uploadData = listOf(
149
PartData.FormItem("title", "My Document"),
150
PartData.FormItem("description", "Important document"),
151
PartData.FileItem(
152
provider = { ByteReadChannel(fileBytes) },
153
dispose = {},
154
partHeaders = headersOf(
155
HttpHeaders.ContentDisposition,
156
"form-data; name=\"file\"; filename=\"document.pdf\""
157
)
158
)
159
)
160
161
val uploadResponse = client.submitFormWithBinaryData(
162
url = "https://api.example.com/upload",
163
formData = uploadData
164
) {
165
headers["Authorization"] = "Bearer $token"
166
}
167
```
168
169
### Prepared Form Functions
170
171
Functions for creating reusable prepared form requests.
172
173
```kotlin { .api }
174
/**
175
* Prepare URL-encoded form submission
176
*/
177
suspend fun HttpClient.prepareForm(
178
formParameters: Parameters,
179
encodeInQuery: Boolean = false,
180
block: HttpRequestBuilder.() -> Unit = {}
181
): HttpStatement
182
183
/**
184
* Prepare URL-encoded form submission with URL
185
*/
186
suspend fun HttpClient.prepareForm(
187
url: String,
188
formParameters: Parameters,
189
encodeInQuery: Boolean = false,
190
block: HttpRequestBuilder.() -> Unit = {}
191
): HttpStatement
192
193
/**
194
* Prepare multipart form submission
195
*/
196
suspend fun HttpClient.prepareFormWithBinaryData(
197
formData: List<PartData>,
198
block: HttpRequestBuilder.() -> Unit = {}
199
): HttpStatement
200
201
/**
202
* Prepare multipart form submission with URL
203
*/
204
suspend fun HttpClient.prepareFormWithBinaryData(
205
url: String,
206
formData: List<PartData>,
207
block: HttpRequestBuilder.() -> Unit = {}
208
): HttpStatement
209
```
210
211
**Usage Examples:**
212
213
```kotlin
214
// Prepare reusable form
215
val loginForm = client.prepareForm(
216
url = "https://api.example.com/login",
217
formParameters = Parameters.build {
218
append("username", "placeholder")
219
append("password", "placeholder")
220
}
221
)
222
223
// Use prepared form multiple times
224
val response1 = loginForm.execute { response ->
225
// Custom response handling
226
response.bodyAsText()
227
}
228
229
val response2 = loginForm.execute()
230
```
231
232
### PartData Classes
233
234
Classes representing different types of form parts in multipart forms.
235
236
```kotlin { .api }
237
/**
238
* Base class for multipart form parts
239
*/
240
sealed class PartData {
241
abstract val headers: Headers
242
abstract val name: String?
243
244
/**
245
* Simple form field
246
*/
247
data class FormItem(
248
override val name: String,
249
val value: String,
250
override val headers: Headers = Headers.Empty
251
) : PartData()
252
253
/**
254
* Binary file part
255
*/
256
data class BinaryItem(
257
override val name: String?,
258
val contentType: ContentType?,
259
override val headers: Headers = Headers.Empty,
260
val provider: () -> ByteReadChannel
261
) : PartData()
262
263
/**
264
* File upload part
265
*/
266
data class FileItem(
267
override val name: String?,
268
val originalFileName: String?,
269
override val headers: Headers = Headers.Empty,
270
val provider: () -> ByteReadChannel,
271
val dispose: () -> Unit = {}
272
) : PartData()
273
274
/**
275
* Binary channel part
276
*/
277
data class BinaryChannelItem(
278
override val name: String?,
279
val contentType: ContentType?,
280
override val headers: Headers = Headers.Empty,
281
val provider: () -> ByteReadChannel
282
) : PartData()
283
}
284
```
285
286
**Usage Examples:**
287
288
```kotlin
289
import io.ktor.http.content.*
290
import io.ktor.utils.io.*
291
import java.io.File
292
293
// Create different types of form parts
294
val formParts = listOf(
295
// Simple text field
296
PartData.FormItem("username", "alice"),
297
298
// File upload from File object (JVM)
299
PartData.FileItem(
300
provider = { file.readChannel() },
301
dispose = {},
302
partHeaders = headersOf(
303
HttpHeaders.ContentDisposition,
304
"form-data; name=\"avatar\"; filename=\"avatar.jpg\""
305
)
306
),
307
308
// Binary data
309
PartData.BinaryItem(
310
name = "data",
311
contentType = ContentType.Application.OctetStream,
312
provider = { ByteReadChannel(binaryData) }
313
),
314
315
// Binary channel
316
PartData.BinaryChannelItem(
317
name = "stream",
318
contentType = ContentType.Text.Plain,
319
provider = { dataChannel }
320
)
321
)
322
323
// Submit multipart form
324
val response = client.submitFormWithBinaryData(
325
url = "https://api.example.com/upload",
326
formData = formParts
327
)
328
```
329
330
### Form Building DSL
331
332
DSL for building form data with type safety.
333
334
```kotlin { .api }
335
/**
336
* Build form parameters using DSL
337
*/
338
fun formParameters(block: ParametersBuilder.() -> Unit): Parameters =
339
ParametersBuilder().apply(block).build()
340
341
/**
342
* Build multipart form data using DSL
343
*/
344
fun multiPartFormData(block: MultiPartFormDataContent.Builder.() -> Unit): MultiPartFormDataContent
345
```
346
347
**Usage Examples:**
348
349
```kotlin
350
// Form parameters DSL
351
val params = formParameters {
352
append("name", "John Doe")
353
append("email", "john@example.com")
354
append("subscribe", "true")
355
appendAll("interests", listOf("kotlin", "web", "mobile"))
356
}
357
358
val response = client.submitForm(
359
url = "https://api.example.com/register",
360
formParameters = params
361
)
362
363
// Multipart form DSL
364
val multipart = multiPartFormData {
365
// Add text fields
366
append("title", "My Upload")
367
append("description", "File description")
368
369
// Add file
370
append("file", fileBytes, Headers.build {
371
append(HttpHeaders.ContentDisposition, "filename=document.pdf")
372
append(HttpHeaders.ContentType, "application/pdf")
373
})
374
}
375
376
val uploadResponse = client.post("https://api.example.com/upload") {
377
setBody(multipart)
378
}
379
```