Ral*_*lph 7 monads scala playframework
我正在尝试为以下URL编写Play Framework异步Action:
POST /users/:userId/items
Run Code Online (Sandbox Code Playgroud)
我的数据库调用的所有返回Future[...],其中...是Option[A]对find的方法和Option[Id]用于创建方法.
我想在尝试创建新项目之前检查userId是否存在.我有一个方法Users.findById(userId)返回一个Future[Option[User]].结果是Some(User)如果用户存在,None如果不存在.Items.create()也返回一个Future[Option[itemId]].
我正在尝试使用for以下方法撰写:
for {
user <- Users.findById(userId)
if user.isDefined
} yield {
Items.create(...) map { itemId => Ok(itemId) } getOrElse NotFound
}
Run Code Online (Sandbox Code Playgroud)
Ok(itemId)如果项目成功创建,我想返回.我不知道如何处理错误案例.NotFound如果userId无效或无法创建项目(可能是某个字段与数据库中已存在的唯一值冲突),我想返回.
我不确定for结构后要放什么.我试过了getOrElse,但是没有编译,因为Future没有getOrElse方法.
理想情况下,我可以处理包含几个要检查的ID的URL,例如:
PUT /users/:userId/foo/:fooId/bar/:barId
Run Code Online (Sandbox Code Playgroud)
并确认userId,fooId和barId正在做的更新之前都有效.所有这些电话的(Users.findById,Foo.findById,和Bar.findById)将返回Future[Option[A]].
它是双嵌套(Future的Option),似乎每一次抢人.如果你能先把东西弄平,事情会变得容易多了.
在这种情况下,Future已经有一种表示错误条件的方法,它可以包装一个Exception以及一个成功值,这是你可以使用的东西......
// making this a Singleton avoids the cost of building a stack trace,
// which only happens when an Exception is constructed (not when it's thrown)
object NotFoundException extends RuntimeException("Empty Option")
// The map operation will trap any thrown exception and fail the Future
def squish[T](x: Future[Option[T]]) =
x map { _.getOrElse(throw NotFoundException) }
Run Code Online (Sandbox Code Playgroud)
现在,在理解中使用这些压扁的结果要容易得多:
val result = for {
user <- squish(Users findById userId)
itemId <- squish(Items.create(user, ...))
} yield {
Ok(itemId)
} recover {
case NotFoundException => NotFound
}
Run Code Online (Sandbox Code Playgroud)
当然,这将评估未来.这毕竟是异步编程:)
除了NotFoundException仍然会暴露的任何例外情况.