我是Scala的新手,目前正在尝试使用Play框架。
这是我写的代码:
def authenticate = Action (BodyParsers.parse.json) { req =>
req.body.validate[AuthenticationForm].map {form =>
UserRepository.findByCredentials(form).map { user =>
user.apiKeys.find(_.deviceId == form.deviceId).map { apiKey =>
Ok(Json.toJson(apiKey))
}.getOrElse({
// HOW DO I TRANSFORM THIS INTO MORE BEAUTIFUL CODE
val createdApiKey = ApiKeyRepository.create(new ApiKey(form.deviceId, form.deviceId))
val userToWithNewApiKey = user.copy(apiKeys = user.apiKeys.:+(createdApiKey))
UserRepository.update(userToWithNewApiKey)
Ok(Json.toJson(createdApiKey))
})
}.getOrElse {
Unauthorized
}
}.getOrElse {
BadRequest
}
}
嗯,这看起来不太好看。我们可以做得更好吗?我还不能。但是我看到了这个stackoverflow帖子:https://stackoverflow.com/a/24085333/3038183看起来很不错:)。
现在我想知道如何转换我的代码,所以它在给定的例子中看起来像。当然我已经尝试了,但我无法编译,也不知道如何在评论后处理代码(“我如何将其转换为更美丽的代码”)。 在我的情况下,我使用play.api.mvc.Result而不是上面的链接中给出的“失败”。那么我的Either [play.api.mvc.Result,?WhatHere?]应该是什么类型的?
祝你好运
编辑:我接受了特拉维斯的回答。非常感谢你。
对于任何感兴趣的人来说,感谢特拉维斯,我能写得更好看的代码:
def getApiKey(user: User, deviceId: String) : ApiKey = {
user.apiKeys.find(_.deviceId == deviceId).getOrElse {
val createdApiKey =
ApiKeyRepository.create(new ApiKey(deviceId, deviceId))
val userToWithNewApiKey =
user.copy(apiKeys = user.apiKeys.:+(createdApiKey))
UserRepository.update(userToWithNewApiKey)
createdApiKey
}
}
def authenticate = Action (BodyParsers.parse.json) { req =>
(for {
form <- req.body.validate[AuthenticationForm].asOpt.toRight(BadRequest).right
user <- UserRepository.findByCredentials(form).toRight(Unauthorized).right
} yield {
Ok(Json.toJson(getApiKey(user, form.deviceId)))
}).merge
}
答案 0 :(得分:3)
这是快速且未经测试但应该是一个不错的开始。首先,您可以使用toRight
获取Either[Status, ?]
来折叠部分嵌套。 Either
不是monadic,但它的正确投影(我们可以使用.right
获得)。一旦失败不再可能,我们使用yield
来处理结果。我稍微重写了您的apiKey
内容,以避免重复Ok(Json.toJson(key))
部分。
def authenticate = Action (BodyParsers.parse.json) { req =>
for {
form <- req.body.asOpt.toRight[Status](BadRequest).right
user <- UserRepository.findByCredentials(form).toRight[Status](
Unauthorized
).right
} yield {
val apiKey = user.apiKeys.find(_.deviceId == form.deviceId).getOrElse {
val createdApiKey =
ApiKeyRepository.create(new ApiKey(form.deviceId, form.deviceId))
val userToWithNewApiKey =
user.copy(apiKeys = user.apiKeys.:+(createdApiKey))
UserRepository.update(userToWithNewApiKey)
createdApiKey
}
Ok(Json.toJson(apiKey)): Status
}.e.merge
}
for
- 理解的最终结果(即除.e.merge
之外的所有内容)都是RightProjection[Status, Status]
。我们使用Either[Status, Status]
将其转换回普通的.e
。此时,我们不再需要跟踪失败和成功之间的区别,因此我们将整个内容转换为Status
.merge
。