diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/BasicRouteSpecs.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/BasicRouteSpecs.scala index 68bcc0afd9..15b044db49 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/BasicRouteSpecs.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/BasicRouteSpecs.scala @@ -119,6 +119,17 @@ class BasicRouteSpecs extends RoutingSpec { responseAs[String] shouldEqual "Person(john,38)" } } + "reject if case class requirements fail" in { + case class MyValidNumber(i: Int) { + require(i > 10) + } + + val abcPath = path("abc" / IntNumber).as(MyValidNumber)(echoComplete) + + Get("/abc/5") ~> abcPath ~> check { + rejection shouldBe a[ValidationRejection] + } + } } "Dynamic execution of inner routes of Directive0" should { "re-execute inner routes every time" in { diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/Directive.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/Directive.scala index 1acd651801..7bf66ba721 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/Directive.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/Directive.scala @@ -9,6 +9,7 @@ import akka.http.scaladsl.server.directives.RouteDirectives import akka.http.scaladsl.server.util._ import akka.http.scaladsl.util.FastFuture import akka.http.scaladsl.util.FastFuture._ +import akka.http.impl.util._ /** * A directive that provides a tuple of values of type `L` to create an inner route. @@ -40,7 +41,20 @@ abstract class Directive[L](implicit val ev: Tuple[L]) { * Converts this directive into one which, instead of a tuple of type ``L``, creates an * instance of type ``A`` (which is usually a case class). */ - def as[A](constructor: ConstructFromTuple[L, A]): Directive1[A] = tmap(constructor) + def as[A](constructor: ConstructFromTuple[L, A]): Directive1[A] = { + def validatedMap[R](f: L ⇒ R)(implicit tupler: Tupler[R]): Directive[tupler.Out] = + Directive[tupler.Out] { inner ⇒ + tapply { values ⇒ + ctx ⇒ + try inner(tupler(f(values)))(ctx) + catch { + case e: IllegalArgumentException ⇒ ctx.reject(ValidationRejection(e.getMessage.nullAsEmpty, Some(e))) + } + } + }(tupler.OutIsTuple) + + validatedMap(constructor) + } /** * Maps over this directive using the given function, which can produce either a tuple or any other value