0
# Routing and HTTP Method Handling
1
2
URL routing system with DSL for defining routes, handling different HTTP methods, extracting path parameters, and organizing complex routing hierarchies with middleware support.
3
4
## Capabilities
5
6
### Route Definition
7
8
Core routing classes for building routing trees and handling HTTP requests with path matching and parameter extraction.
9
10
```kotlin { .api }
11
/**
12
* Represents a route in the routing tree
13
*/
14
class Route(
15
val parent: Route?,
16
val selector: RouteSelector,
17
val developmentMode: Boolean = false,
18
val environment: ApplicationEnvironment
19
) : ApplicationCallPipeline() {
20
/** Child routes */
21
val children: List<Route>
22
/** Route handlers */
23
val handlers: List<PipelineInterceptor<Unit, ApplicationCall>>
24
25
/** Create child route with selector */
26
fun createChild(selector: RouteSelector): Route
27
/** Install handler for this route */
28
fun handle(body: PipelineInterceptor<Unit, ApplicationCall>)
29
}
30
31
/**
32
* Root routing node
33
*/
34
class Routing(
35
private val application: Application
36
) : Route(parent = null, selector = RootRouteSelector, environment = application.environment)
37
38
/**
39
* DSL builder for constructing routing trees
40
*/
41
class RoutingBuilder : Route
42
```
43
44
### HTTP Method Handlers
45
46
DSL functions for handling different HTTP methods with path patterns and request processing.
47
48
```kotlin { .api }
49
/**
50
* Handle GET requests
51
* @param path - URL path pattern (supports parameters like {id})
52
* @param body - Request handler function
53
*/
54
fun Route.get(path: String, body: RoutingHandler): Route
55
fun Route.get(body: RoutingHandler): Route
56
57
/**
58
* Handle POST requests
59
* @param path - URL path pattern
60
* @param body - Request handler function
61
*/
62
fun Route.post(path: String, body: RoutingHandler): Route
63
fun Route.post(body: RoutingHandler): Route
64
65
/**
66
* Handle PUT requests
67
* @param path - URL path pattern
68
* @param body - Request handler function
69
*/
70
fun Route.put(path: String, body: RoutingHandler): Route
71
fun Route.put(body: RoutingHandler): Route
72
73
/**
74
* Handle DELETE requests
75
* @param path - URL path pattern
76
* @param body - Request handler function
77
*/
78
fun Route.delete(path: String, body: RoutingHandler): Route
79
fun Route.delete(body: RoutingHandler): Route
80
81
/**
82
* Handle PATCH requests
83
* @param path - URL path pattern
84
* @param body - Request handler function
85
*/
86
fun Route.patch(path: String, body: RoutingHandler): Route
87
fun Route.patch(body: RoutingHandler): Route
88
89
/**
90
* Handle HEAD requests
91
* @param path - URL path pattern
92
* @param body - Request handler function
93
*/
94
fun Route.head(path: String, body: RoutingHandler): Route
95
fun Route.head(body: RoutingHandler): Route
96
97
/**
98
* Handle OPTIONS requests
99
* @param path - URL path pattern
100
* @param body - Request handler function
101
*/
102
fun Route.options(path: String, body: RoutingHandler): Route
103
fun Route.options(body: RoutingHandler): Route
104
105
/**
106
* Handle requests for specific HTTP method
107
* @param method - HTTP method to handle
108
* @param path - URL path pattern
109
* @param body - Request handler function
110
*/
111
fun Route.method(method: HttpMethod, path: String, body: RoutingHandler): Route
112
fun Route.method(method: HttpMethod, body: RoutingHandler): Route
113
114
/**
115
* Type alias for routing handler functions
116
*/
117
typealias RoutingHandler = suspend RoutingContext.() -> Unit
118
119
/**
120
* Context for routing handlers
121
*/
122
class RoutingContext(
123
val call: RoutingCall
124
)
125
```
126
127
### Route Building and Nesting
128
129
Functions for creating nested routes and organizing routing hierarchies with shared middleware and path prefixes.
130
131
```kotlin { .api }
132
/**
133
* Create nested routes with path prefix
134
* @param path - Path prefix for nested routes
135
* @param build - Function to configure nested routes
136
*/
137
fun Route.route(path: String, build: Route.() -> Unit): Route
138
139
/**
140
* Install and configure routing for application
141
* @param configuration - Function to configure routing tree
142
*/
143
fun Application.routing(configuration: Routing.() -> Unit): Routing
144
145
/**
146
* Create route group without path prefix
147
* @param build - Function to configure route group
148
*/
149
fun Route.route(build: Route.() -> Unit): Route
150
```
151
152
### Route Selectors
153
154
Classes for matching routes based on different criteria including HTTP methods, path segments, and parameters.
155
156
```kotlin { .api }
157
/**
158
* Base class for route selection criteria
159
*/
160
abstract class RouteSelector {
161
/** Evaluate selector against current request */
162
abstract fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation
163
/** Build string representation */
164
abstract fun toString(): String
165
}
166
167
/**
168
* Selector for HTTP methods
169
*/
170
data class HttpMethodRouteSelector(val method: HttpMethod) : RouteSelector
171
172
/**
173
* Selector for exact path segments
174
*/
175
data class PathSegmentRouteSelector(val value: String, val optional: Boolean = false) : RouteSelector
176
177
/**
178
* Selector for path parameters (e.g., {id})
179
*/
180
data class ParameterRouteSelector(val name: String, val optional: Boolean = false) : RouteSelector
181
182
/**
183
* Selector for wildcard path segments
184
*/
185
data class WildcardRouteSelector(val name: String) : RouteSelector
186
187
/**
188
* Selector for trailing path segments
189
*/
190
object TailcardRouteSelector : RouteSelector
191
192
/**
193
* Root route selector
194
*/
195
object RootRouteSelector : RouteSelector
196
```
197
198
### Route Resolution
199
200
System for resolving incoming requests to appropriate route handlers with parameter extraction.
201
202
```kotlin { .api }
203
/**
204
* Context for route resolution
205
*/
206
class RoutingResolveContext(
207
val routing: Route,
208
val call: ApplicationCall,
209
val parameters: MutableMap<String, String> = mutableMapOf()
210
) {
211
/** Segments from request path */
212
val segments: List<String>
213
/** Current segment index during resolution */
214
var segmentIndex: Int
215
}
216
217
/**
218
* Result of route resolution
219
*/
220
sealed class RoutingResolveResult {
221
/** Successful route resolution */
222
class Success(val route: Route, val parameters: Map<String, String>) : RoutingResolveResult()
223
/** Route not found */
224
object Failure : RoutingResolveResult()
225
}
226
227
/**
228
* Evaluation result for route selector
229
*/
230
sealed class RouteSelectorEvaluation {
231
/** Selector matches */
232
object Success : RouteSelectorEvaluation()
233
/** Selector doesn't match */
234
object Failure : RouteSelectorEvaluation()
235
/** Selector matches with consumed segments */
236
class SuccessWithConsume(val segmentCount: Int) : RouteSelectorEvaluation()
237
}
238
```
239
240
### Route Middleware
241
242
Support for middleware that applies to specific routes or route groups with proper scoping.
243
244
```kotlin { .api }
245
/**
246
* Install interceptor for route and all child routes
247
* @param phase - Pipeline phase to install interceptor
248
* @param block - Interceptor function
249
*/
250
fun Route.intercept(phase: PipelinePhase, block: PipelineInterceptor<Unit, ApplicationCall>)
251
252
/**
253
* Install route-scoped plugin
254
* @param plugin - Plugin to install
255
* @param configuration - Plugin configuration
256
*/
257
fun <TConfiguration : Any> Route.install(
258
plugin: RouteScopedPlugin<TConfiguration, *>,
259
configuration: TConfiguration.() -> Unit = {}
260
)
261
```
262
263
### Parameter Extraction
264
265
Utilities for extracting and converting path parameters from matched routes.
266
267
```kotlin { .api }
268
/**
269
* Parameter collection for route parameters
270
*/
271
interface Parameters {
272
/** Get parameter value by name */
273
operator fun get(name: String): String?
274
/** Get all values for parameter name */
275
fun getAll(name: String): List<String>?
276
/** Get all parameter names */
277
fun names(): Set<String>
278
/** Check if parameter exists */
279
fun contains(name: String): Boolean
280
/** Check if parameter has specific value */
281
fun contains(name: String, value: String): Boolean
282
}
283
284
/** Access route parameters from application call */
285
val ApplicationCall.parameters: Parameters
286
287
/** Utility functions for parameter conversion */
288
fun Parameters.getOrFail(name: String): String =
289
get(name) ?: throw ParameterConversionException(name, "String", "Parameter $name not found")
290
291
fun Parameters.getInt(name: String): Int? = get(name)?.toIntOrNull()
292
fun Parameters.getIntOrFail(name: String): Int =
293
getInt(name) ?: throw ParameterConversionException(name, "Int", "Cannot convert to Int")
294
295
fun Parameters.getLong(name: String): Long? = get(name)?.toLongOrNull()
296
fun Parameters.getLongOrFail(name: String): Long =
297
getLong(name) ?: throw ParameterConversionException(name, "Long", "Cannot convert to Long")
298
299
fun Parameters.getBoolean(name: String): Boolean? = get(name)?.toBooleanStrictOrNull()
300
fun Parameters.getBooleanOrFail(name: String): Boolean =
301
getBoolean(name) ?: throw ParameterConversionException(name, "Boolean", "Cannot convert to Boolean")
302
```
303
304
**Usage Examples:**
305
306
```kotlin
307
import io.ktor.server.application.*
308
import io.ktor.server.response.*
309
import io.ktor.server.routing.*
310
import io.ktor.server.request.*
311
312
// Basic routing with HTTP methods
313
fun Application.basicRouting() {
314
routing {
315
get("/") {
316
call.respondText("Welcome!")
317
}
318
319
post("/users") {
320
val user = call.receive<User>()
321
// Create user
322
call.respond(HttpStatusCode.Created)
323
}
324
325
get("/health") {
326
call.respondText("OK")
327
}
328
}
329
}
330
331
// Path parameters and nested routes
332
fun Application.parameterRouting() {
333
routing {
334
route("/api/v1") {
335
route("/users") {
336
get {
337
// GET /api/v1/users - list all users
338
call.respondText("All users")
339
}
340
341
get("/{id}") {
342
val userId = call.parameters["id"]?.toIntOrNull()
343
?: throw BadRequestException("Invalid user ID")
344
// GET /api/v1/users/123
345
call.respondText("User $userId")
346
}
347
348
put("/{id}") {
349
val userId = call.parameters.getIntOrFail("id")
350
val user = call.receive<User>()
351
// PUT /api/v1/users/123 - update user
352
call.respond(user)
353
}
354
355
delete("/{id}") {
356
val userId = call.parameters.getIntOrFail("id")
357
// DELETE /api/v1/users/123
358
call.respond(HttpStatusCode.NoContent)
359
}
360
361
// Nested resource routes
362
route("/{userId}/posts") {
363
get {
364
val userId = call.parameters.getIntOrFail("userId")
365
// GET /api/v1/users/123/posts
366
call.respondText("Posts for user $userId")
367
}
368
369
post {
370
val userId = call.parameters.getIntOrFail("userId")
371
val post = call.receive<Post>()
372
// POST /api/v1/users/123/posts
373
call.respond(HttpStatusCode.Created, post)
374
}
375
}
376
}
377
}
378
}
379
}
380
381
// Wildcard and optional parameters
382
fun Application.wildcardRouting() {
383
routing {
384
// Wildcard parameter captures single segment
385
get("/files/{filename}") {
386
val filename = call.parameters["filename"]!!
387
call.respondText("Requested file: $filename")
388
}
389
390
// Tailcard captures remaining path segments
391
get("/static/{...}") {
392
val path = call.request.uri.removePrefix("/static/")
393
// Serve static files
394
call.respondText("Static path: $path")
395
}
396
397
// Optional parameters with defaults
398
get("/search") {
399
val query = call.request.queryParameters["q"] ?: ""
400
val page = call.request.queryParameters.getInt("page") ?: 1
401
val limit = call.request.queryParameters.getInt("limit") ?: 10
402
403
call.respondText("Search: $query, Page: $page, Limit: $limit")
404
}
405
}
406
}
407
408
// Route middleware and interceptors
409
fun Application.middlewareRouting() {
410
routing {
411
// Global interceptor for all routes
412
intercept(ApplicationCallPipeline.Setup) {
413
call.response.headers.append("X-Server", "Ktor")
414
}
415
416
route("/admin") {
417
// Authentication middleware for admin routes
418
intercept(ApplicationCallPipeline.Plugins) {
419
val token = call.request.headers["Authorization"]
420
if (token?.startsWith("Bearer ") != true) {
421
call.respond(HttpStatusCode.Unauthorized)
422
return@intercept finish()
423
}
424
// Validate token
425
}
426
427
get("/dashboard") {
428
call.respondText("Admin Dashboard")
429
}
430
431
get("/users") {
432
call.respondText("Admin Users")
433
}
434
}
435
436
route("/api") {
437
// CORS middleware for API routes
438
intercept(ApplicationCallPipeline.Setup) {
439
call.response.headers.append("Access-Control-Allow-Origin", "*")
440
}
441
442
get("/data") {
443
call.respond(mapOf("message" to "API data"))
444
}
445
}
446
}
447
}
448
449
data class User(val id: Int, val name: String, val email: String)
450
data class Post(val id: Int, val title: String, val content: String)
451
```