diff --git a/zio-http/src/main/scala/zio/http/Route.scala b/zio-http/src/main/scala/zio/http/Route.scala index ec1994e453..4592f923c7 100644 --- a/zio-http/src/main/scala/zio/http/Route.scala +++ b/zio-http/src/main/scala/zio/http/Route.scala @@ -216,6 +216,13 @@ sealed trait Route[-Env, +Err] { self => */ def routePattern: RoutePattern[_] + /** + * Applies the route to the specified request. The route must be defined for + * the request, or else this method will fail fatally. + */ + final def run(request: Request)(implicit trace: Trace): ZIO[Env, Either[Err, Response], Response] = + Routes(self).run(request) + /** * Returns a route that automatically translates all failures into responses, * using best-effort heuristics to determine the appropriate HTTP status code, diff --git a/zio-http/src/main/scala/zio/http/Routes.scala b/zio-http/src/main/scala/zio/http/Routes.scala index d6e60d0ca1..a13d4f8117 100644 --- a/zio-http/src/main/scala/zio/http/Routes.scala +++ b/zio-http/src/main/scala/zio/http/Routes.scala @@ -127,6 +127,40 @@ final class Routes[-Env, +Err] private (val routes: Chunk[zio.http.Route[Env, Er def provideEnvironment(env: ZEnvironment[Env]): Routes[Any, Err] = new Routes(routes.map(_.provideEnvironment(env))) + def run(request: Request)(implicit trace: Trace): ZIO[Env, Either[Err, Response], Response] = { + + class RouteFailure[+Err](val err: Cause[Err]) extends Throwable(null, null, true, false) { + override def getMessage: String = err.unified.headOption.fold("")(_.message) + + override def getStackTrace(): Array[StackTraceElement] = + err.unified.headOption.fold[Chunk[StackTraceElement]](Chunk.empty)(_.trace).toArray + + override def getCause(): Throwable = + err.find { case Cause.Die(throwable, _) => throwable } + .orElse(err.find { case Cause.Fail(value: Throwable, _) => value }) + .orNull + + def fillSuppressed()(implicit unsafe: Unsafe): Unit = + if (getSuppressed().length == 0) { + err.unified.iterator.drop(1).foreach(unified => addSuppressed(unified.toThrowable)) + } + + override def toString = + err.prettyPrint + } + var routeFailure: RouteFailure[Err] = null + + handleErrorCauseZIO { cause => + routeFailure = new RouteFailure(cause) + ZIO.refailCause(Cause.die(routeFailure)) + } + .apply(request) + .mapErrorCause { + case Cause.Die(value: RouteFailure[_], _) if value == routeFailure => routeFailure.err.map(Left(_)) + case cause => cause.map(Right(_)) + } + } + /** * Returns new routes that automatically translate all failures into * responses, using best-effort heuristics to determine the appropriate HTTP