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
This commit is contained in:
Sebastien Deleuze 2019-09-16 21:47:24 +02:00
parent 848804a227
commit 5a0216d657
7 changed files with 379 additions and 95 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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