Skip to content

Commit 710702a

Browse files
committed
Polish Kotlin routing DSL
- typealias to replace types like RouterDsl.() -> Unit by Routes - String.invoke() as path("/foo") shortcut - String.route() as pathPrefix("/foo").route() shortcut - Avoid requiring PathPredicates.* import Issue: SPR-15292
1 parent a936ece commit 710702a

File tree

2 files changed

+65
-20
lines changed

2 files changed

+65
-20
lines changed

spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/RouterFunctionExtensions.kt

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,24 @@ package org.springframework.web.reactive.function.server
1919
import org.springframework.core.io.Resource
2020
import org.springframework.http.HttpMethod
2121
import org.springframework.http.MediaType
22+
import org.springframework.web.reactive.function.server.RequestPredicates.pathPrefix
2223
import reactor.core.publisher.Mono
2324

2425
/**
2526
* Provide a routing DSL for [RouterFunctions] and [RouterFunction] in order to be able to
2627
* write idiomatic Kotlin code as below:
2728
*
2829
* ```kotlin
29-
* import org.springframework.web.reactive.function.server.RequestPredicates.*
30-
* ...
3130
*
3231
* @Controller
3332
* class FooController : RouterFunction<ServerResponse> {
3433
*
3534
* override fun route(req: ServerRequest) = route(req) {
36-
* html().apply {
35+
* accept(TEXT_HTML).apply {
3736
* (GET("/user/") or GET("/users/")) { findAllView() }
3837
* GET("/user/{login}", this@FooController::findViewById)
3938
* }
40-
* json().apply {
39+
* accept(APPLICATION_JSON).apply {
4140
* (GET("/api/user/") or GET("/api/users/")) { findAll() }
4241
* POST("/api/user/", this@FooController::create)
4342
* }
@@ -52,24 +51,39 @@ import reactor.core.publisher.Mono
5251
*
5352
* @since 5.0
5453
* @see <a href="https://youtrack.jetbrains.com/issue/KT-15667">Kotlin issue about supporting ::foo for member functions</a>
55-
* @author Sebastien Deleuze
54+
* @author Sebastien De leuze
5655
* @author Yevhenii Melnyk
5756
*/
58-
fun RouterFunction<*>.route(request: ServerRequest, configure: Routes.() -> Unit) =
59-
Routes().apply(configure).invoke(request)
6057

61-
class Routes {
58+
typealias Routes = RouterDsl.() -> Unit
59+
60+
fun RouterFunction<*>.route(request: ServerRequest, configure: Routes) =
61+
RouterDsl().apply(configure).invoke(request)
62+
63+
class RouterDsl {
6264

6365
val routes = mutableListOf<RouterFunction<ServerResponse>>()
6466

67+
infix fun RequestPredicate.and(other: String): RequestPredicate = this.and(pathPrefix(other))
68+
69+
infix fun RequestPredicate.or(other: String): RequestPredicate = this.or(pathPrefix(other))
70+
71+
infix fun String.and(other: RequestPredicate): RequestPredicate = pathPrefix(this).and(other)
72+
73+
infix fun String.or(other: RequestPredicate): RequestPredicate = pathPrefix(this).or(other)
74+
6575
infix fun RequestPredicate.and(other: RequestPredicate): RequestPredicate = this.and(other)
6676

6777
infix fun RequestPredicate.or(other: RequestPredicate): RequestPredicate = this.or(other)
6878

6979
operator fun RequestPredicate.not(): RequestPredicate = this.negate()
7080

71-
fun RequestPredicate.route(r: Routes.() -> Unit) {
72-
routes += RouterFunctions.nest(this, Routes().apply(r).router())
81+
fun RequestPredicate.route(r: Routes) {
82+
routes += RouterFunctions.nest(this, RouterDsl().apply(r).router())
83+
}
84+
85+
fun String.route(r: Routes) {
86+
routes += RouterFunctions.nest(pathPrefix(this), RouterDsl().apply(r).router())
7387
}
7488

7589
operator fun RequestPredicate.invoke(f: (ServerRequest) -> Mono<ServerResponse>) {
@@ -80,62 +94,98 @@ class Routes {
8094
routes += RouterFunctions.route(RequestPredicates.GET(pattern), HandlerFunction { f(it) })
8195
}
8296

97+
fun GET(pattern: String) = RequestPredicates.GET(pattern)
98+
8399
fun HEAD(pattern: String, f: (ServerRequest) -> Mono<ServerResponse>) {
84100
routes += RouterFunctions.route(RequestPredicates.HEAD(pattern), HandlerFunction { f(it) })
85101
}
86102

103+
fun HEAD(pattern: String) = RequestPredicates.HEAD(pattern)
104+
87105
fun POST(pattern: String, f: (ServerRequest) -> Mono<ServerResponse>) {
88106
routes += RouterFunctions.route(RequestPredicates.POST(pattern), HandlerFunction { f(it) })
89107
}
90108

109+
fun POST(pattern: String) = RequestPredicates.POST(pattern)
110+
91111
fun PUT(pattern: String, f: (ServerRequest) -> Mono<ServerResponse>) {
92112
routes += RouterFunctions.route(RequestPredicates.PUT(pattern), HandlerFunction { f(it) })
93113
}
94114

115+
fun PUT(pattern: String) = RequestPredicates.PUT(pattern)
116+
95117
fun PATCH(pattern: String, f: (ServerRequest) -> Mono<ServerResponse>) {
96118
routes += RouterFunctions.route(RequestPredicates.PATCH(pattern), HandlerFunction { f(it) })
97119
}
98120

121+
fun PATCH(pattern: String) = RequestPredicates.PATCH(pattern)
122+
99123
fun DELETE(pattern: String, f: (ServerRequest) -> Mono<ServerResponse>) {
100124
routes += RouterFunctions.route(RequestPredicates.DELETE(pattern), HandlerFunction { f(it) })
101125
}
102126

127+
fun DELETE(pattern: String) = RequestPredicates.DELETE(pattern)
128+
129+
103130
fun OPTIONS(pattern: String, f: (ServerRequest) -> Mono<ServerResponse>) {
104131
routes += RouterFunctions.route(RequestPredicates.OPTIONS(pattern), HandlerFunction { f(it) })
105132
}
106133

134+
fun OPTIONS(pattern: String) = RequestPredicates.OPTIONS(pattern)
135+
107136
fun accept(mediaType: MediaType, f: (ServerRequest) -> Mono<ServerResponse>) {
108137
routes += RouterFunctions.route(RequestPredicates.accept(mediaType), HandlerFunction { f(it) })
109138
}
110139

140+
fun accept(mediaType: MediaType) = RequestPredicates.accept(mediaType)
141+
111142
fun contentType(mediaType: MediaType, f: (ServerRequest) -> Mono<ServerResponse>) {
112143
routes += RouterFunctions.route(RequestPredicates.contentType(mediaType), HandlerFunction { f(it) })
113144
}
114145

146+
fun contentType(mediaType: MediaType) = RequestPredicates.contentType(mediaType)
147+
115148
fun headers(headerPredicate: (ServerRequest.Headers) -> Boolean, f: (ServerRequest) -> Mono<ServerResponse>) {
116149
routes += RouterFunctions.route(RequestPredicates.headers(headerPredicate), HandlerFunction { f(it) })
117150
}
118151

152+
fun headers(headerPredicate: (ServerRequest.Headers) -> Boolean) = RequestPredicates.headers(headerPredicate)
153+
119154
fun method(httpMethod: HttpMethod, f: (ServerRequest) -> Mono<ServerResponse>) {
120155
routes += RouterFunctions.route(RequestPredicates.method(httpMethod), HandlerFunction { f(it) })
121156
}
122157

158+
fun method(httpMethod: HttpMethod) = RequestPredicates.method(httpMethod)
159+
123160
fun path(pattern: String, f: (ServerRequest) -> Mono<ServerResponse>) {
124161
routes += RouterFunctions.route(RequestPredicates.path(pattern), HandlerFunction { f(it) })
125162
}
126163

164+
fun path(pattern: String) = RequestPredicates.path(pattern)
165+
127166
fun pathExtension(extension: String, f: (ServerRequest) -> Mono<ServerResponse>) {
128167
routes += RouterFunctions.route(RequestPredicates.pathExtension(extension), HandlerFunction { f(it) })
129168
}
130169

170+
fun pathExtension(extension: String) = RequestPredicates.pathExtension(extension)
171+
131172
fun pathExtension(predicate: (String) -> Boolean, f: (ServerRequest) -> Mono<ServerResponse>) {
132173
routes += RouterFunctions.route(RequestPredicates.pathExtension(predicate), HandlerFunction { f(it) })
133174
}
134175

176+
fun pathExtension(predicate: (String) -> Boolean) = RequestPredicates.pathExtension(predicate)
177+
178+
135179
fun queryParam(name: String, predicate: (String) -> Boolean, f: (ServerRequest) -> Mono<ServerResponse>) {
136180
routes += RouterFunctions.route(RequestPredicates.queryParam(name, predicate), HandlerFunction { f(it) })
137181
}
138182

183+
fun queryParam(name: String, predicate: (String) -> Boolean) = RequestPredicates.queryParam(name, predicate)
184+
185+
operator fun String.invoke(f: (ServerRequest) -> Mono<ServerResponse>) {
186+
routes += RouterFunctions.route(RequestPredicates.path(this), HandlerFunction { f(it) })
187+
}
188+
139189
fun resources(path: String, location: Resource) {
140190
routes += RouterFunctions.resources(path, location)
141191
}

spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/server/RouterFunctionExtensionsTests.kt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,10 @@ package org.springframework.web.reactive.function.server
1818

1919
import org.junit.Test
2020
import org.springframework.core.io.ClassPathResource
21-
import org.springframework.http.HttpHeaders.ACCEPT
22-
import org.springframework.http.HttpHeaders.CONTENT_TYPE
23-
import org.springframework.http.HttpMethod
24-
import org.springframework.http.HttpMethod.PATCH
25-
import org.springframework.http.HttpMethod.POST
21+
import org.springframework.http.HttpHeaders.*
22+
import org.springframework.http.HttpMethod.*
2623
import org.springframework.http.MediaType.*
2724
import org.springframework.web.reactive.function.server.MockServerRequest.builder
28-
import org.springframework.web.reactive.function.server.RequestPredicates.*
2925
import org.springframework.web.reactive.function.server.ServerResponse.ok
3026
import reactor.core.publisher.Mono
3127
import reactor.test.StepVerifier
@@ -112,14 +108,14 @@ class RouterFunctionExtensionsTests {
112108

113109
override fun route(req: ServerRequest) = route(req) {
114110
(GET("/foo/") or GET("/foos/")) { handle(req) }
115-
(pathPrefix("/api") and accept(APPLICATION_JSON)).route {
111+
"/api".route {
116112
POST("/foo/") { handleFromClass(req) }
117113
PUT("/foo/") { handleFromClass(req) }
118-
DELETE("/foo/") { handleFromClass(req) }
114+
"/foo/" { handleFromClass(req) }
119115
}
120116
accept(APPLICATION_ATOM_XML, ::handle)
121117
contentType(APPLICATION_OCTET_STREAM) { handle(req) }
122-
method(HttpMethod.PATCH) { handle(req) }
118+
method(PATCH) { handle(req) }
123119
headers({ it.accept().contains(APPLICATION_JSON) }).route {
124120
GET("/api/foo/", ::handle)
125121
}
@@ -142,4 +138,3 @@ class RouterFunctionExtensionsTests {
142138
}
143139

144140
fun handle(req: ServerRequest) = ok().build()
145-

0 commit comments

Comments
 (0)