Browse Source

Improve parity between Java and Kotlin router DSL

This commit adds variants with pattern + predicate to
Kotlin router DSLs, and vararg where necessary.

Closes gh-23524
pull/23656/head
Sebastien Deleuze 6 years ago
parent
commit
5a0216d657
  1. 112
      spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/CoRouterFunctionDsl.kt
  2. 172
      spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/RouterFunctionDsl.kt
  3. 21
      spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/server/CoRouterFunctionDslTests.kt
  4. 21
      spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/server/RouterFunctionDslTests.kt
  5. 112
      spring-webmvc/src/main/kotlin/org/springframework/web/servlet/function/RouterFunctionDsl.kt
  6. 16
      spring-webmvc/src/test/kotlin/org/springframework/web/servlet/function/RouterFunctionDslTests.kt
  7. 20
      src/docs/asciidoc/web/webflux-functional.adoc

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

@ -149,13 +149,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) { @@ -149,13 +149,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) {
fun String.nest(r: (CoRouterFunctionDsl.() -> Unit)) = path(this).nest(r)
/**
* Route to the given handler function if the given request predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `GET` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun GET(pattern: String, f: suspend (ServerRequest) -> ServerResponse) {
builder.GET(pattern, asHandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `GET` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun GET(pattern: String, predicate: RequestPredicate, f: suspend (ServerRequest) -> ServerResponse) {
builder.GET(pattern, predicate, asHandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `GET`
* and the given `pattern` matches against the request path.
@ -164,13 +176,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) { @@ -164,13 +176,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) {
fun GET(pattern: String): RequestPredicate = RequestPredicates.GET(pattern)
/**
* Route to the given handler function if the given request predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `HEAD` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun HEAD(pattern: String, f: suspend (ServerRequest) -> ServerResponse) {
builder.HEAD(pattern, asHandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `HEAD` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun HEAD(pattern: String, predicate: RequestPredicate, f: suspend (ServerRequest) -> ServerResponse) {
builder.HEAD(pattern, predicate, asHandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `HEAD`
* and the given `pattern` matches against the request path.
@ -179,13 +203,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) { @@ -179,13 +203,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) {
fun HEAD(pattern: String): RequestPredicate = RequestPredicates.HEAD(pattern)
/**
* Route to the given handler function if the given `POST` predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `POST` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun POST(pattern: String, f: suspend (ServerRequest) -> ServerResponse) {
builder.POST(pattern, asHandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `POST` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun POST(pattern: String, predicate: RequestPredicate, f: suspend (ServerRequest) -> ServerResponse) {
builder.POST(pattern, predicate, asHandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `POST`
* and the given `pattern` matches against the request path.
@ -194,13 +230,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) { @@ -194,13 +230,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) {
fun POST(pattern: String): RequestPredicate = RequestPredicates.POST(pattern)
/**
* Route to the given handler function if the given `PUT` predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `PUT` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun PUT(pattern: String, f: suspend (ServerRequest) -> ServerResponse) {
builder.PUT(pattern, asHandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `PUT` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun PUT(pattern: String, predicate: RequestPredicate, f: suspend (ServerRequest) -> ServerResponse) {
builder.PUT(pattern, predicate, asHandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `PUT`
* and the given `pattern` matches against the request path.
@ -209,13 +257,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) { @@ -209,13 +257,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) {
fun PUT(pattern: String): RequestPredicate = RequestPredicates.PUT(pattern)
/**
* Route to the given handler function if the given `PATCH` predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `PATCH` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun PATCH(pattern: String, f: suspend (ServerRequest) -> ServerResponse) {
builder.PATCH(pattern, asHandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `PATCH` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun PATCH(pattern: String, predicate: RequestPredicate, f: suspend (ServerRequest) -> ServerResponse) {
builder.PATCH(pattern, predicate, asHandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `PATCH`
* and the given `pattern` matches against the request path.
@ -226,13 +286,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) { @@ -226,13 +286,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) {
fun PATCH(pattern: String): RequestPredicate = RequestPredicates.PATCH(pattern)
/**
* Route to the given handler function if the given `DELETE` predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `DELETE` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun DELETE(pattern: String, f: suspend (ServerRequest) -> ServerResponse) {
builder.DELETE(pattern, asHandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `DELETE` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun DELETE(pattern: String, predicate: RequestPredicate, f: suspend (ServerRequest) -> ServerResponse) {
builder.DELETE(pattern, predicate, asHandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `DELETE`
* and the given `pattern` matches against the request path.
@ -243,13 +315,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) { @@ -243,13 +315,25 @@ class CoRouterFunctionDsl(private val init: (CoRouterFunctionDsl.() -> Unit)) {
fun DELETE(pattern: String): RequestPredicate = RequestPredicates.DELETE(pattern)
/**
* Route to the given handler function if the given OPTIONS predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `OPTIONS` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun OPTIONS(pattern: String, f: suspend (ServerRequest) -> ServerResponse) {
builder.OPTIONS(pattern, asHandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `OPTIONS` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun OPTIONS(pattern: String, predicate: RequestPredicate, f: suspend (ServerRequest) -> ServerResponse) {
builder.OPTIONS(pattern, predicate, asHandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `OPTIONS`
* and the given `pattern` matches against the request path.

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

@ -148,76 +148,136 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) { @@ -148,76 +148,136 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) {
}
/**
* Route to the given handler function if the given request predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `GET` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun GET(pattern: String, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.GET(pattern) { f(it).cast(ServerResponse::class.java) }
}
/**
* Return a {@code RequestPredicate} that matches if request's HTTP method is {@code GET}
* and the given {@code pattern} matches against the request path.
* Adds a route to the given handler function that handles all HTTP `GET` requests
* that match the given pattern and predicate.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun GET(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.GET(pattern, predicate, HandlerFunction<ServerResponse> { f(it).cast(ServerResponse::class.java) })
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `GET`
* and the given [pattern] matches against the request path.
* @see RequestPredicates.GET
*/
fun GET(pattern: String): RequestPredicate = RequestPredicates.GET(pattern)
/**
* Route to the given handler function if the given request predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `HEAD` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun HEAD(pattern: String, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.HEAD(pattern) { f(it).cast(ServerResponse::class.java) }
}
/**
* Return a {@code RequestPredicate} that matches if request's HTTP method is {@code HEAD}
* and the given {@code pattern} matches against the request path.
* Adds a route to the given handler function that handles all HTTP `HEAD` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun HEAD(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.HEAD(pattern, predicate, HandlerFunction<ServerResponse> { f(it).cast(ServerResponse::class.java) })
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `HEAD`
* and the given `pattern` matches against the request path.
* @see RequestPredicates.HEAD
*/
fun HEAD(pattern: String): RequestPredicate = RequestPredicates.HEAD(pattern)
/**
* Route to the given handler function if the given POST predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `POST` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun POST(pattern: String, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.POST(pattern) { f(it).cast(ServerResponse::class.java) }
}
/**
* Return a {@code RequestPredicate} that matches if request's HTTP method is {@code POST}
* and the given {@code pattern} matches against the request path.
* Adds a route to the given handler function that handles all HTTP `POST` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun POST(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.POST(pattern, predicate, HandlerFunction<ServerResponse> { f(it).cast(ServerResponse::class.java) })
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `POST`
* and the given `pattern` matches against the request path.
* @see RequestPredicates.POST
*/
fun POST(pattern: String): RequestPredicate = RequestPredicates.POST(pattern)
/**
* Route to the given handler function if the given PUT predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `PUT` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun PUT(pattern: String, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.PUT(pattern) { f(it).cast(ServerResponse::class.java) }
}
/**
* Return a {@code RequestPredicate} that matches if request's HTTP method is {@code PUT}
* and the given {@code pattern} matches against the request path.
* Adds a route to the given handler function that handles all HTTP `PUT` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun PUT(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.PUT(pattern, predicate, HandlerFunction<ServerResponse> { f(it).cast(ServerResponse::class.java) })
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `PUT`
* and the given `pattern` matches against the request path.
* @see RequestPredicates.PUT
*/
fun PUT(pattern: String): RequestPredicate = RequestPredicates.PUT(pattern)
/**
* Route to the given handler function if the given PATCH predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `PATCH` requests
* that match the given pattern and predicate.
* @param pattern the pattern to match to
*/
fun PATCH(pattern: String, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.PATCH(pattern) { f(it).cast(ServerResponse::class.java) }
}
/**
* Return a {@code RequestPredicate} that matches if request's HTTP method is {@code PATCH}
* and the given {@code pattern} matches against the request path.
* Adds a route to the given handler function that handles all HTTP `PATCH` requests
* that match the given pattern and predicate.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun PATCH(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.PATCH(pattern, predicate, HandlerFunction<ServerResponse> { f(it).cast(ServerResponse::class.java) })
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `PATCH`
* and the given `pattern` matches against the request path.
* @param pattern the path pattern to match against
* @return a predicate that matches if the request method is PATCH and if the given pattern
* matches against the request path
@ -225,16 +285,28 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) { @@ -225,16 +285,28 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) {
fun PATCH(pattern: String): RequestPredicate = RequestPredicates.PATCH(pattern)
/**
* Route to the given handler function if the given DELETE predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `DELETE` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun DELETE(pattern: String, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.DELETE(pattern) { f(it).cast(ServerResponse::class.java) }
}
/**
* Return a {@code RequestPredicate} that matches if request's HTTP method is {@code DELETE}
* and the given {@code pattern} matches against the request path.
* Adds a route to the given handler function that handles all HTTP `DELETE` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun DELETE(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.DELETE(pattern, predicate, HandlerFunction<ServerResponse> { f(it).cast(ServerResponse::class.java) })
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `DELETE`
* and the given `pattern` matches against the request path.
* @param pattern the path pattern to match against
* @return a predicate that matches if the request method is DELETE and if the given pattern
* matches against the request path
@ -242,16 +314,28 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) { @@ -242,16 +314,28 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) {
fun DELETE(pattern: String): RequestPredicate = RequestPredicates.DELETE(pattern)
/**
* Route to the given handler function if the given OPTIONS predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `OPTIONS` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun OPTIONS(pattern: String, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.OPTIONS(pattern) { f(it).cast(ServerResponse::class.java) }
}
/**
* Return a {@code RequestPredicate} that matches if request's HTTP method is {@code OPTIONS}
* and the given {@code pattern} matches against the request path.
* Adds a route to the given handler function that handles all HTTP `OPTIONS` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun OPTIONS(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.OPTIONS(pattern, predicate, HandlerFunction<ServerResponse> { f(it).cast(ServerResponse::class.java) })
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `OPTIONS`
* and the given `pattern` matches against the request path.
* @param pattern the path pattern to match against
* @return a predicate that matches if the request method is OPTIONS and if the given pattern
* matches against the request path
@ -267,30 +351,30 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) { @@ -267,30 +351,30 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) {
}
/**
* Return a {@code RequestPredicate} that tests if the request's
* {@linkplain ServerRequest.Headers#accept() accept} header is
* {@linkplain MediaType#isCompatibleWith(MediaType) compatible} with any of the given media types.
* Return a [RequestPredicate] that tests if the request's
* [accept][ServerRequest.Headers.accept] header is
* [compatible][MediaType.isCompatibleWith] with any of the given media types.
* @param mediaTypes the media types to match the request's accept header against
* @return a predicate that tests the request's accept header against the given media types
*/
fun accept(mediaType: MediaType): RequestPredicate = RequestPredicates.accept(mediaType)
fun accept(vararg mediaTypes: MediaType): RequestPredicate = RequestPredicates.accept(*mediaTypes)
/**
* Route to the given handler function if the given contentType predicate applies.
* @see RouterFunctions.route
*/
fun contentType(mediaType: MediaType, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.add(RouterFunctions.route(RequestPredicates.contentType(mediaType), HandlerFunction<ServerResponse> { f(it).cast(ServerResponse::class.java) }))
fun contentType(mediaTypes: MediaType, f: (ServerRequest) -> Mono<out ServerResponse>) {
builder.add(RouterFunctions.route(RequestPredicates.contentType(mediaTypes), HandlerFunction<ServerResponse> { f(it).cast(ServerResponse::class.java) }))
}
/**
* Return a {@code RequestPredicate} that tests if the request's
* {@linkplain ServerRequest.Headers#contentType() content type} is
* {@linkplain MediaType#includes(MediaType) included} by any of the given media types.
* Return a [RequestPredicate] that tests if the request's
* [content type][ServerRequest.Headers.contentType] is
* [included][MediaType.includes] by any of the given media types.
* @param mediaTypes the media types to match the request's content type against
* @return a predicate that tests the request's content type against the given media types
*/
fun contentType(mediaType: MediaType): RequestPredicate = RequestPredicates.contentType(mediaType)
fun contentType(vararg mediaTypes: MediaType): RequestPredicate = RequestPredicates.contentType(*mediaTypes)
/**
* Route to the given handler function if the given headers predicate applies.
@ -301,7 +385,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) { @@ -301,7 +385,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) {
}
/**
* Return a {@code RequestPredicate} that tests the request's headers against the given headers predicate.
* Return a [RequestPredicate] that tests the request's headers against the given headers predicate.
* @param headersPredicate a predicate that tests against the request headers
* @return a predicate that tests against the given header predicate
*/
@ -317,7 +401,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) { @@ -317,7 +401,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) {
}
/**
* Return a {@code RequestPredicate} that tests against the given HTTP method.
* Return a [RequestPredicate] that tests against the given HTTP method.
* @param httpMethod the HTTP method to match to
* @return a predicate that tests against the given HTTP method
*/
@ -332,7 +416,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) { @@ -332,7 +416,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) {
}
/**
* Return a {@code RequestPredicate} that tests the request path against the given path pattern.
* Return a [RequestPredicate] that tests the request path against the given path pattern.
* @see RequestPredicates.path
*/
fun path(pattern: String): RequestPredicate = RequestPredicates.path(pattern)
@ -346,7 +430,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) { @@ -346,7 +430,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) {
}
/**
* Return a {@code RequestPredicate} that matches if the request's path has the given extension.
* Return a [RequestPredicate] that matches if the request's path has the given extension.
* @param extension the path extension to match against, ignoring case
* @return a predicate that matches if the request's path has the given file extension
*/
@ -361,7 +445,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) { @@ -361,7 +445,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) {
}
/**
* Return a {@code RequestPredicate} that matches if the request's path matches the given
* Return a [RequestPredicate] that matches if the request's path matches the given
* predicate.
* @see RequestPredicates.pathExtension
*/
@ -377,7 +461,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) { @@ -377,7 +461,7 @@ class RouterFunctionDsl(private val init: RouterFunctionDsl.() -> Unit) {
}
/**
* Return a {@code RequestPredicate} that tests the request's query parameter of the given name
* Return a [RequestPredicate] that tests the request's query parameter of the given name
* against the given predicate.
* @param name the name of the query parameter to test against
* @param predicate predicate to test against the query parameter value

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

@ -16,10 +16,8 @@ @@ -16,10 +16,8 @@
package org.springframework.web.reactive.function.server
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.fail
import org.springframework.core.io.ClassPathResource
import org.springframework.http.HttpHeaders.*
import org.springframework.http.HttpMethod.*
@ -63,6 +61,18 @@ class CoRouterFunctionDslTests { @@ -63,6 +61,18 @@ class CoRouterFunctionDslTests {
.verifyComplete()
}
@Test
fun acceptAndPOSTWithRequestPredicate() {
val request = builder()
.method(POST)
.uri(URI("/api/bar/"))
.header(CONTENT_TYPE, APPLICATION_JSON_VALUE)
.build()
StepVerifier.create(sampleRouter().route(request))
.expectNextCount(1)
.verifyComplete()
}
@Test
fun contentType() {
val request = builder().uri(URI("/content")).header(CONTENT_TYPE, APPLICATION_OCTET_STREAM_VALUE).build()
@ -134,6 +144,7 @@ class CoRouterFunctionDslTests { @@ -134,6 +144,7 @@ class CoRouterFunctionDslTests {
(GET("/foo/") or GET("/foos/")) { req -> handle(req) }
"/api".nest {
POST("/foo/", ::handleFromClass)
POST("/bar/", contentType(APPLICATION_JSON), ::handleFromClass)
PUT("/foo/", :: handleFromClass)
PATCH("/foo/") {
ok().buildAndAwait()
@ -162,10 +173,10 @@ class CoRouterFunctionDslTests { @@ -162,10 +173,10 @@ class CoRouterFunctionDslTests {
path("/baz", ::handle)
GET("/rendering") { RenderingResponse.create("index").buildAndAwait() }
}
}
@Suppress("UNUSED_PARAMETER")
private suspend fun handleFromClass(req: ServerRequest) = ServerResponse.ok().buildAndAwait()
@Suppress("UNUSED_PARAMETER")
private suspend fun handleFromClass(req: ServerRequest) = ServerResponse.ok().buildAndAwait()
}
@Suppress("UNUSED_PARAMETER")
private suspend fun handle(req: ServerRequest) = ServerResponse.ok().buildAndAwait()

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

@ -16,10 +16,8 @@ @@ -16,10 +16,8 @@
package org.springframework.web.reactive.function.server
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.fail
import org.springframework.core.io.ClassPathResource
import org.springframework.http.HttpHeaders.*
import org.springframework.http.HttpMethod.*
@ -64,6 +62,18 @@ class RouterFunctionDslTests { @@ -64,6 +62,18 @@ class RouterFunctionDslTests {
.verifyComplete()
}
@Test
fun acceptAndPOSTWithRequestPredicate() {
val request = builder()
.method(POST)
.uri(URI("/api/bar/"))
.header(CONTENT_TYPE, APPLICATION_JSON_VALUE)
.build()
StepVerifier.create(sampleRouter().route(request))
.expectNextCount(1)
.verifyComplete()
}
@Test
fun contentType() {
val request = builder().uri(URI("/content")).header(CONTENT_TYPE, APPLICATION_OCTET_STREAM_VALUE).build()
@ -135,6 +145,7 @@ class RouterFunctionDslTests { @@ -135,6 +145,7 @@ class RouterFunctionDslTests {
(GET("/foo/") or GET("/foos/")) { req -> handle(req) }
"/api".nest {
POST("/foo/", ::handleFromClass)
POST("/bar/", contentType(APPLICATION_JSON), ::handleFromClass)
PUT("/foo/", :: handleFromClass)
PATCH("/foo/") {
ok().build()
@ -163,10 +174,10 @@ class RouterFunctionDslTests { @@ -163,10 +174,10 @@ class RouterFunctionDslTests {
path("/baz", ::handle)
GET("/rendering") { RenderingResponse.create("index").build() }
}
}
@Suppress("UNUSED_PARAMETER")
private fun handleFromClass(req: ServerRequest) = ServerResponse.ok().build()
@Suppress("UNUSED_PARAMETER")
private fun handleFromClass(req: ServerRequest) = ServerResponse.ok().build()
}
@Suppress("UNUSED_PARAMETER")
private fun handle(req: ServerRequest) = ServerResponse.ok().build()

112
spring-webmvc/src/main/kotlin/org/springframework/web/servlet/function/RouterFunctionDsl.kt

@ -145,13 +145,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) { @@ -145,13 +145,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) {
fun String.nest(r: (RouterFunctionDsl.() -> Unit)) = path(this).nest(r)
/**
* Route to the given handler function if the given request predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `GET` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun GET(pattern: String, f: (ServerRequest) -> ServerResponse) {
builder.GET(pattern, HandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `GET` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun GET(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> ServerResponse) {
builder.GET(pattern, predicate, HandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `GET`
* and the given `pattern` matches against the request path.
@ -160,13 +172,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) { @@ -160,13 +172,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) {
fun GET(pattern: String): RequestPredicate = RequestPredicates.GET(pattern)
/**
* Route to the given handler function if the given request predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `HEAD` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun HEAD(pattern: String, f: (ServerRequest) -> ServerResponse) {
builder.HEAD(pattern, HandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `HEAD` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun HEAD(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> ServerResponse) {
builder.HEAD(pattern, predicate, HandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `HEAD`
* and the given `pattern` matches against the request path.
@ -175,13 +199,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) { @@ -175,13 +199,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) {
fun HEAD(pattern: String): RequestPredicate = RequestPredicates.HEAD(pattern)
/**
* Route to the given handler function if the given `POST` predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `POST` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun POST(pattern: String, f: (ServerRequest) -> ServerResponse) {
builder.POST(pattern, HandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `POST` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun POST(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> ServerResponse) {
builder.POST(pattern, predicate, HandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `POST`
* and the given `pattern` matches against the request path.
@ -190,13 +226,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) { @@ -190,13 +226,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) {
fun POST(pattern: String): RequestPredicate = RequestPredicates.POST(pattern)
/**
* Route to the given handler function if the given `PUT` predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `PUT` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun PUT(pattern: String, f: (ServerRequest) -> ServerResponse) {
builder.PUT(pattern, HandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `PUT` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun PUT(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> ServerResponse) {
builder.PUT(pattern, predicate, HandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `PUT`
* and the given `pattern` matches against the request path.
@ -205,13 +253,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) { @@ -205,13 +253,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) {
fun PUT(pattern: String): RequestPredicate = RequestPredicates.PUT(pattern)
/**
* Route to the given handler function if the given `PATCH` predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `PATCH` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun PATCH(pattern: String, f: (ServerRequest) -> ServerResponse) {
builder.PATCH(pattern, HandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `PATCH` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun PATCH(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> ServerResponse) {
builder.PATCH(pattern, predicate, HandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `PATCH`
* and the given `pattern` matches against the request path.
@ -222,13 +282,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) { @@ -222,13 +282,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) {
fun PATCH(pattern: String): RequestPredicate = RequestPredicates.PATCH(pattern)
/**
* Route to the given handler function if the given `DELETE` predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `DELETE` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun DELETE(pattern: String, f: (ServerRequest) -> ServerResponse) {
builder.DELETE(pattern, HandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `DELETE` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun DELETE(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> ServerResponse) {
builder.DELETE(pattern, predicate, HandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `DELETE`
* and the given `pattern` matches against the request path.
@ -239,13 +311,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) { @@ -239,13 +311,25 @@ class RouterFunctionDsl(private val init: (RouterFunctionDsl.() -> Unit)) {
fun DELETE(pattern: String): RequestPredicate = RequestPredicates.DELETE(pattern)
/**
* Route to the given handler function if the given OPTIONS predicate applies.
* @see RouterFunctions.route
* Adds a route to the given handler function that handles all HTTP `OPTIONS` requests
* that match the given pattern.
* @param pattern the pattern to match to
*/
fun OPTIONS(pattern: String, f: (ServerRequest) -> ServerResponse) {
builder.OPTIONS(pattern, HandlerFunction(f))
}
/**
* Adds a route to the given handler function that handles all HTTP `OPTIONS` requests
* that match the given pattern.
* @param pattern the pattern to match to
* @param predicate additional predicate to match
* @since 5.2
*/
fun OPTIONS(pattern: String, predicate: RequestPredicate, f: (ServerRequest) -> ServerResponse) {
builder.OPTIONS(pattern, predicate, HandlerFunction(f))
}
/**
* Return a [RequestPredicate] that matches if request's HTTP method is `OPTIONS`
* and the given `pattern` matches against the request path.

16
spring-webmvc/src/test/kotlin/org/springframework/web/servlet/function/RouterFunctionDslTests.kt

@ -55,6 +55,15 @@ class RouterFunctionDslTests { @@ -55,6 +55,15 @@ class RouterFunctionDslTests {
assertThat(sampleRouter().route(request).isPresent).isTrue()
}
@Test
fun acceptAndPOSTWithRequestPredicate() {
val servletRequest = MockHttpServletRequest("POST", "/api/bar/")
servletRequest.addHeader(ACCEPT, APPLICATION_JSON_VALUE)
servletRequest.addHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
val request = DefaultServerRequest(servletRequest, emptyList())
assertThat(sampleRouter().route(request).isPresent).isTrue()
}
@Test
fun contentType() {
val servletRequest = MockHttpServletRequest("GET", "/content")
@ -120,6 +129,7 @@ class RouterFunctionDslTests { @@ -120,6 +129,7 @@ class RouterFunctionDslTests {
(GET("/foo/") or GET("/foos/")) { req -> handle(req) }
"/api".nest {
POST("/foo/", ::handleFromClass)
POST("/bar/", contentType(APPLICATION_JSON), ::handleFromClass)
PUT("/foo/", :: handleFromClass)
PATCH("/foo/") {
ok().build()
@ -148,10 +158,10 @@ class RouterFunctionDslTests { @@ -148,10 +158,10 @@ class RouterFunctionDslTests {
path("/baz", ::handle)
GET("/rendering") { RenderingResponse.create("index").build() }
}
}
@Suppress("UNUSED_PARAMETER")
private fun handleFromClass(req: ServerRequest) = ServerResponse.ok().build()
@Suppress("UNUSED_PARAMETER")
private fun handleFromClass(req: ServerRequest) = ServerResponse.ok().build()
}
@Suppress("UNUSED_PARAMETER")
private fun handle(req: ServerRequest) = ServerResponse.ok().build()

20
src/docs/asciidoc/web/webflux-functional.adoc

@ -476,9 +476,9 @@ header: @@ -476,9 +476,9 @@ header:
.Kotlin
----
val route = coRouter {
(GET("/hello-world") and accept(MediaType.TEXT_PLAIN)).invoke {
ServerResponse.ok().bodyValueAndAwait("Hello World")
}
GET("/hello-world", accept(TEXT_PLAIN)) {
ServerResponse.ok().bodyValueAndAwait("Hello World")
}
}
----
@ -553,9 +553,9 @@ RouterFunction<ServerResponse> route = route() @@ -553,9 +553,9 @@ RouterFunction<ServerResponse> route = route()
val otherRoute: RouterFunction<ServerResponse> = coRouter { }
val route = coRouter {
(GET("/person/{id}") and accept(APPLICATION_JSON)).invoke(handler::getPerson) // <1>
(GET("/person") and accept(APPLICATION_JSON)).invoke(handler::listPeople) // <2>
POST("/person").invoke(handler::createPerson) // <3>
GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson) // <1>
GET("/person", accept(APPLICATION_JSON), handler::listPeople) // <2>
POST("/person", handler::createPerson) // <3>
}.and(otherRoute) // <4>
----
<1> `GET /person/{id}` with an `Accept` header that matches JSON is routed to
@ -595,9 +595,9 @@ RouterFunction<ServerResponse> route = route() @@ -595,9 +595,9 @@ RouterFunction<ServerResponse> route = route()
----
val route = coRouter {
"/person".nest {
(GET("/{id}") and accept(APPLICATION_JSON)).invoke(handler::getPerson)
(GET("") and accept(APPLICATION_JSON)).invoke(handler::listPeople)
POST("/person").invoke(handler::createPerson)
GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
GET("", accept(APPLICATION_JSON), handler::listPeople)
POST("/person", handler::createPerson)
}
}
----
@ -622,7 +622,7 @@ We can further improve by using the `nest` method together with `accept`: @@ -622,7 +622,7 @@ We can further improve by using the `nest` method together with `accept`:
.Kotlin
----
val route = coRouter {
"/person".nest{
"/person".nest {
accept(APPLICATION_JSON).nest {
GET("/{id}", handler::getPerson)
GET("", handler::listPeople)

Loading…
Cancel
Save