htp #19678 add variadic concat route combinator
* add variadic route concatenation function * add `concat` to `~` warning bubble in docs * fix grammar of warning bubble, and clarify
This commit is contained in:
parent
09d5072f2c
commit
b3c85512a3
4 changed files with 51 additions and 4 deletions
|
|
@ -138,8 +138,8 @@ transformations, both (or either) on the request and on the response side.
|
|||
Composing Directives
|
||||
--------------------
|
||||
|
||||
.. note:: Gotcha: forgetting the ``~`` (tilde) character in between directives can often result in perfectly valid
|
||||
Scala code that compiles but lead to your composed directive only containing the up to where ``~`` is missing.
|
||||
.. note:: Gotcha: forgetting the ``~`` (tilde) character in between directives can result in perfectly valid
|
||||
Scala code that compiles but does not work as expected. What would be intended as a single expression would actually be multiple expressions, and only the final one would be used as the result of the parent directive. Alternatively, you might choose to use the ``concat`` combinator. ``concat(a, b, c)`` is the same as ``a ~ b ~ c``.
|
||||
|
||||
As you have seen from the examples presented so far the "normal" way of composing directives is nesting.
|
||||
Let's take a look at this concrete example:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
package akka.http.impl.util
|
||||
|
||||
import akka.stream.ActorMaterializer
|
||||
import akka.stream.scaladsl.{Sink, Source}
|
||||
import akka.stream.scaladsl.{ Sink, Source }
|
||||
import akka.testkit.AkkaSpec
|
||||
|
||||
import scala.concurrent.Await
|
||||
|
|
@ -34,7 +34,6 @@ class StreamUtilsSpec extends AkkaSpec {
|
|||
Await.ready(whenCompleted, 3.seconds).value shouldBe Some(Failure(ex))
|
||||
}
|
||||
|
||||
|
||||
"downstream cancels" in {
|
||||
val (newSource, whenCompleted) = StreamUtils.captureTermination(Source(List(1, 2, 3)))
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,42 @@ class BasicRouteSpecs extends RoutingSpec {
|
|||
}
|
||||
}
|
||||
|
||||
"routes created by the 'sequence' directive" should {
|
||||
"reject with zero arguments, since no routes were matched" in {
|
||||
Get() ~> {
|
||||
concat()
|
||||
} ~> check { rejections shouldEqual Seq() }
|
||||
}
|
||||
"yield the first sub route if it succeeded" in {
|
||||
Get() ~> {
|
||||
concat(
|
||||
get { complete("first") },
|
||||
get { complete("second") })
|
||||
} ~> check { responseAs[String] shouldEqual "first" }
|
||||
}
|
||||
"yield the second sub route if the first did not succeed" in {
|
||||
Get() ~> {
|
||||
concat(
|
||||
post { complete("first") },
|
||||
get { complete("second") })
|
||||
} ~> check { responseAs[String] shouldEqual "second" }
|
||||
}
|
||||
"collect rejections from both sub routes" in {
|
||||
Delete() ~> {
|
||||
concat(
|
||||
get { completeOk },
|
||||
put { completeOk })
|
||||
} ~> check { rejections shouldEqual Seq(MethodRejection(GET), MethodRejection(PUT)) }
|
||||
}
|
||||
"clear rejections that have already been 'overcome' by previous directives" in {
|
||||
Put() ~> {
|
||||
concat(
|
||||
put { parameter('yeah) { echoComplete } },
|
||||
get { completeOk })
|
||||
} ~> check { rejection shouldEqual MissingQueryParamRejection("yeah") }
|
||||
}
|
||||
}
|
||||
|
||||
"Route conjunction" should {
|
||||
val stringDirective = provide("The cat")
|
||||
val intDirective = provide(42)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package akka.http.scaladsl.server
|
||||
|
||||
import akka.http.scaladsl.server.Directives.reject
|
||||
import akka.http.scaladsl.util.FastFuture
|
||||
import akka.http.scaladsl.util.FastFuture._
|
||||
|
||||
|
|
@ -18,6 +19,17 @@ trait RouteConcatenation {
|
|||
*/
|
||||
implicit def enhanceRouteWithConcatenation(route: Route): RouteConcatenation.RouteWithConcatenation =
|
||||
new RouteConcatenation.RouteWithConcatenation(route: Route)
|
||||
|
||||
/**
|
||||
* Tries the supplied routes in sequence, returning the result of the first route that doesn't reject the request.
|
||||
* This is an alternative to direct usage of the infix ~ operator. The ~ can be prone to programmer error, because if
|
||||
* it is omitted, the program will still be syntactically correct, but will not actually attempt to match multiple
|
||||
* routes, as intended.
|
||||
*
|
||||
* @param routes subroutes to concatenate
|
||||
* @return the concatenated route
|
||||
*/
|
||||
def concat(routes: Route*): Route = routes.foldLeft[Route](reject)(_ ~ _)
|
||||
}
|
||||
|
||||
object RouteConcatenation extends RouteConcatenation {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue