2

我是 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?] 应该是什么类型?

此致

编辑:我接受了特拉维斯的回答。非常感谢。

对于任何对这里感兴趣的人来说,我可以编写更好看的代码,这要感谢 Travis:

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
}
4

1 回答 1

3

这是快速且未经测试的,但应该是一个不错的开始。首先,您可以使用toRightto get折叠一些嵌套Either[Status, ?]Either不是一元的,而是它的正确投影(我们可以使用.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-comprehension(即除 之外的所有内容)的最终结果.e.mergeRightProjection[Status, Status]. 我们将其转换回普通的旧Either[Status, Status]版本.e。此时我们不再需要跟踪失败和成功之间的区别,因此我们将整个事情转换为Statuswith .merge

于 2015-04-21T17:45:11.447 回答