Spencer Gibb
7 years ago
7 changed files with 226 additions and 4 deletions
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
/* |
||||
* Copyright 2013-2017 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.cloud.gateway.route.builder |
||||
|
||||
import org.springframework.cloud.gateway.route.RouteLocator |
||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder.RouteSpec |
||||
import java.util.function.Predicate |
||||
|
||||
/** |
||||
* A Kotlin based DSL to configure a [RouteLocator] |
||||
* |
||||
* Example: |
||||
* ``` |
||||
* @Autowired |
||||
* lateinit var builder: RouteLocatorBuilder |
||||
* |
||||
* val routeLocator = builder.routes { |
||||
* route(id = "test") { |
||||
* host("**.abc.org") and path("/image/png") |
||||
* filters { |
||||
* add(addResponseHeader("X-TestHeader", "foobar")) |
||||
* } |
||||
* uri("http://httpbin.org:80") |
||||
* } |
||||
* } |
||||
* ``` |
||||
* |
||||
* @author Biju Kunjummen |
||||
* @author Spencer Gibb |
||||
*/ |
||||
fun RouteLocatorBuilder.routes(routeLocator: RouteLocatorDsl.() -> Unit): RouteLocator { |
||||
return RouteLocatorDsl(this).apply(routeLocator).build() |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Provider for [RouteLocator] DSL functionality |
||||
*/ |
||||
class RouteLocatorDsl(val builder: RouteLocatorBuilder) { |
||||
private val routes = builder.routes() |
||||
|
||||
/** |
||||
* DSL to add a route to the [RouteLocator] |
||||
* |
||||
* @see [Route.Builder] |
||||
*/ |
||||
fun route(id: String? = null, order: Int = 0, uri: String? = null, init: PredicateSpec.() -> Unit) { |
||||
val predicateSpec = if (id == null) { |
||||
RouteSpec(routes).randomId() |
||||
} else { |
||||
RouteSpec(routes).id(id) |
||||
} |
||||
predicateSpec.order(order) |
||||
predicateSpec.apply(init) |
||||
if (uri != null) { |
||||
predicateSpec.uri(uri) |
||||
} |
||||
} |
||||
|
||||
fun build(): RouteLocator { |
||||
return routes.build() |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Extension method to add filters {} block to dsl |
||||
*/ |
||||
fun PredicateSpec.filters(init: GatewayFilterSpec.() -> Unit) { |
||||
val booleanSpec = createBooleanSpec() |
||||
booleanSpec.apply(init) |
||||
} |
||||
|
||||
|
||||
/** |
||||
* A helper to return a composed [Predicate] that tests against this [Predicate] AND the [other] predicate |
||||
*/ |
||||
infix fun BooleanSpec.and(other: BooleanSpec) = |
||||
this.routeBuilder.predicate(this.predicate.and(other.predicate)) |
||||
|
||||
/** |
||||
* A helper to return a composed [Predicate] that tests against this [Predicate] OR the [other] predicate |
||||
*/ |
||||
infix fun BooleanSpec.or(other: BooleanSpec) = |
||||
this.routeBuilder.predicate(this.predicate.or(other.predicate)) |
||||
|
||||
|
@ -0,0 +1,109 @@
@@ -0,0 +1,109 @@
|
||||
/* |
||||
* Copyright 2013-2017 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.cloud.gateway.route.builder |
||||
|
||||
import org.junit.Test |
||||
import org.junit.runner.RunWith |
||||
import org.springframework.beans.factory.annotation.Autowired |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration |
||||
import org.springframework.boot.test.context.SpringBootTest |
||||
import org.springframework.context.annotation.Configuration |
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest |
||||
import org.springframework.mock.web.server.MockServerWebExchange |
||||
import org.springframework.test.context.junit4.SpringRunner |
||||
import org.springframework.web.server.ServerWebExchange |
||||
import reactor.test.StepVerifier |
||||
import java.net.URI |
||||
|
||||
@RunWith(SpringRunner::class) |
||||
@SpringBootTest(classes = arrayOf(Config::class)) |
||||
class RouteDslTests { |
||||
|
||||
@Autowired |
||||
lateinit var builder: RouteLocatorBuilder |
||||
|
||||
@Test |
||||
fun sampleRouteDsl() { |
||||
val routeLocator = builder.routes { |
||||
route(id = "test") { |
||||
host("**.abc.org") and path("/image/png") |
||||
filters { |
||||
addResponseHeader("X-TestHeader", "foobar") |
||||
} |
||||
uri("http://httpbin.org:80") |
||||
} |
||||
|
||||
route(id = "test2") { |
||||
path("/image/webp") or path("/image/anotherone") |
||||
filters { |
||||
addResponseHeader("X-AnotherHeader", "baz") |
||||
addResponseHeader("X-AnotherHeader-2", "baz-2") |
||||
} |
||||
uri("https://httpbin.org:443") |
||||
} |
||||
} |
||||
|
||||
StepVerifier |
||||
.create(routeLocator.routes) |
||||
.expectNextMatches({ r -> |
||||
r.id == "test" && r.filters.size == 1 && r.uri == URI.create("http://httpbin.org:80") |
||||
}) |
||||
.expectNextMatches({ r -> |
||||
r.id == "test2" && r.filters.size == 2 && r.uri == URI.create("https://httpbin.org:443") |
||||
}) |
||||
.expectComplete() |
||||
.verify() |
||||
|
||||
val sampleExchange: ServerWebExchange = MockServerWebExchange.from(MockServerHttpRequest.get("/image/webp") |
||||
.header("Host", "test.abc.org").build()) |
||||
|
||||
val filteredRoutes = routeLocator.routes.filter({ r -> r.predicate.test(sampleExchange) }) |
||||
|
||||
StepVerifier.create(filteredRoutes) |
||||
.expectNextMatches({ r -> |
||||
r.id == "test2" && r.filters.size == 2 && r.uri == URI.create("https://httpbin.org:443") |
||||
}) |
||||
.expectComplete() |
||||
.verify() |
||||
} |
||||
|
||||
@Test |
||||
fun dslWithFunctionParameters() { |
||||
val routerLocator = builder.routes { |
||||
route(id = "test", order = 10, uri = "http://httpbin.org") { |
||||
host("**.abc.org") |
||||
} |
||||
} |
||||
|
||||
StepVerifier.create(routerLocator.routes) |
||||
.expectNextMatches({ r -> |
||||
r.id == "test" && |
||||
r.uri == URI.create("http://httpbin.org") && |
||||
r.order == 10 && |
||||
r.id == "test" && |
||||
r.predicate.test(MockServerWebExchange |
||||
.from(MockServerHttpRequest |
||||
.get("/someuri").header("Host", "test.abc.org"))) |
||||
}) |
||||
.expectComplete() |
||||
.verify() |
||||
} |
||||
} |
||||
|
||||
@Configuration |
||||
@EnableAutoConfiguration |
||||
open class Config {} |
Loading…
Reference in new issue