Scala Future:将 Future[Vector[T]] 转换为 Future[Result]
Scala Future: Transform Future[Vector[T]] to Future[Result]
我有一个方法可以创建类型为 Vector
的 Future
,然后我想从中创建适当的 HTTP 响应。
到目前为止,我已经尝试使用 Futures API 中的 transform
和 transformWith
方法来实现这一点,主要是因为它们的参数具有 Try[T]
签名,并且我分得清成功与失败
我们假设这是生成 Future
类型 Vector
的方法
def aCoupleOfFutures: Future[Vector[String]] = ???
使用这种方法可以注意到 Try
结构的重复使用
val foo:Future[Result] = aCoupleOfFutures.transform {
case Success(strings) => Try(Created(json.Json.toJson(strings)))
case Failure(e) => Try(BadRequest(e.getMessage))
}
使用这种方法可以注意到 Future.successful
嵌套的重复使用。
val foo:Future[Result] = aCoupleOfFutures.transformWith {
case Success(strings) => Future.successful(Created(json.Json.toJson(strings)))
case Failure(e) => Future.successful(BadRequest(e.getMessage))
}
使用这种方法,当服务产生异常时,我无法 return 所需的 BadRequest
。由于重载的 transform
方法的签名是 (def transform[S](s: T => S, f: Throwable => Throwable)
)
val foo:Future[Result] = aCoupleOfFutures.transform (
options => Created(json.Json.toJson(options)),
exc => exc
)
所以我的问题是:我可以有类似下面的东西吗:
val result:Future[Result] = aCoupleOfFutures. someKindOfTransform {
case Success(options) => Created(json.Json.toJson(options))
case Failure(e) => BadRequest(e.getMessage)
}
最简单的选择似乎是将其分成 map
和 recover
步骤:
val result = aCoupleOfFutures
.map(options => Created(json.Json.toJson(options)))
.recover{ case exc => BadRequest(exc.getMessage)}
你是对的,似乎没有一个单一的转换方法可以做你想做的事 - 最接近的签名似乎是 onComplete
,但是 returns Unit
因此不允许您生成 return 值。也就是说,将两者分开并不一定是坏事,因为您通常希望在所有控制器中抽象出 error-handling 逻辑。
折叠操作在这里会有用-
def fold[U](fa: Throwable => U, fb: T => U): U
这是一个终端操作,您想将所有结果或异常转换为Result
。 try/either/option 上的折叠操作会将处于任何状态的整个事物转换为类型 U
.
val result = aCoupleOfFutures
.transform(
tryResult =>
Success(
tryResult.fold(th => BadRequest(th.getMessage), options => Created(json.Json.toJson(options)))
)
)
我有一个方法可以创建类型为 Vector
的 Future
,然后我想从中创建适当的 HTTP 响应。
到目前为止,我已经尝试使用 Futures API 中的 transform
和 transformWith
方法来实现这一点,主要是因为它们的参数具有 Try[T]
签名,并且我分得清成功与失败
我们假设这是生成 Future
类型 Vector
def aCoupleOfFutures: Future[Vector[String]] = ???
使用这种方法可以注意到 Try
结构的重复使用
val foo:Future[Result] = aCoupleOfFutures.transform {
case Success(strings) => Try(Created(json.Json.toJson(strings)))
case Failure(e) => Try(BadRequest(e.getMessage))
}
使用这种方法可以注意到 Future.successful
嵌套的重复使用。
val foo:Future[Result] = aCoupleOfFutures.transformWith {
case Success(strings) => Future.successful(Created(json.Json.toJson(strings)))
case Failure(e) => Future.successful(BadRequest(e.getMessage))
}
使用这种方法,当服务产生异常时,我无法 return 所需的 BadRequest
。由于重载的 transform
方法的签名是 (def transform[S](s: T => S, f: Throwable => Throwable)
)
val foo:Future[Result] = aCoupleOfFutures.transform (
options => Created(json.Json.toJson(options)),
exc => exc
)
所以我的问题是:我可以有类似下面的东西吗:
val result:Future[Result] = aCoupleOfFutures. someKindOfTransform {
case Success(options) => Created(json.Json.toJson(options))
case Failure(e) => BadRequest(e.getMessage)
}
最简单的选择似乎是将其分成 map
和 recover
步骤:
val result = aCoupleOfFutures
.map(options => Created(json.Json.toJson(options)))
.recover{ case exc => BadRequest(exc.getMessage)}
你是对的,似乎没有一个单一的转换方法可以做你想做的事 - 最接近的签名似乎是 onComplete
,但是 returns Unit
因此不允许您生成 return 值。也就是说,将两者分开并不一定是坏事,因为您通常希望在所有控制器中抽象出 error-handling 逻辑。
折叠操作在这里会有用-
def fold[U](fa: Throwable => U, fb: T => U): U
这是一个终端操作,您想将所有结果或异常转换为Result
。 try/either/option 上的折叠操作会将处于任何状态的整个事物转换为类型 U
.
val result = aCoupleOfFutures
.transform(
tryResult =>
Success(
tryResult.fold(th => BadRequest(th.getMessage), options => Created(json.Json.toJson(options)))
)
)