从 Map(Play 框架 request.body.asFormUrlEncoded)转换为 case class,反之亦然,样板更少(与无类型世界交互)

Convert from Map (Play framework request.body.asFormUrlEncoded) to case class, and vice versa, with less boilerplate (interacting with untyped world)

这是一个具体的例子,虽然我在更一般的情况下也遇到过这个问题。

我正在通过自定义斜杠命令在 Play 2.3 网络应用程序和 Slack 之间进行集成。 (注意:Slack 有关于自定义斜杠命令 API 格式的文档,但我不相信我可以直接深入 link 它们以用于注销 reader。)

Slack 将(当用户适当调用时)POST 以标准格式 URL 已知格式的编码正文发送到我的端点。他们的官方例子是:

token=KpADMkoKxZJRGKTG8kJoWXGC
team_id=T0001
team_domain=example
channel_id=C2147483705
channel_name=test
user_id=U2147483697
user_name=Steve
command=/weather
text=94070

在我的应用程序中,我正在用案例 class 对这个请求建模。

case class SlashCommand(
  token: String,
  teamId: String,
  teamDomain: String,
  channelId: String,
  channelName: String,
  userId: String,
  userName: String,
  command: String,
  text: String
)

顺便问一下,除了让每个字段成为 String 之外,还有什么方法可以更好地实施类型约束吗?

我无法从 URL 编码形式的 Play 框架表示形式转换为大小写 class。这是我目前拥有的代码,我认为它可以正常工作,但我觉得它过于重复。

object SlashCommand {

  def parseFromMap(in: Map[String, String]): Option[SlashCommand] = {
    for {
      token <- in.get("token")
      teamId <- in.get("team_id")
      teamDomain <- in.get("team_domain")
      channelId <- in.get("channel_id")
      channelName <- in.get("channel_name")
      userId <- in.get("user_id")
      userName <- in.get("user_name")
      command <- in.get("command")
      text <- in.get("text")
    } yield SlashCommand(
      token,
      teamId,
      teamDomain,
      channelId,
      channelName,
      userId,
      userName,
      command,
      text
    )
  }

  def parseFromRequest(req: Request[AnyContent]): Option[SlashCommand] = {
    req.body.asFormUrlEncoded.map { m =>
      m.mapValues(_.last)
    }.flatMap(parseFromMap)
  }

}

我希望排除的重复部分是:

有什么方法可以减少这些转换中的重复并提高可读性吗?

此外,我可能很快就需要反向操作,即将大小写 class 转换为 Map and/or 形式 URL 编码 and/or JSON。有什么减少重复的方法吗?

提前致谢!

编辑:我一直在进一步考虑这个问题,我认为我可以使用 Play 框架表单处理来做一些事情。

play Forms API 处理从 RequestMap[String, String]JsValue 到您喜欢的类型的绑定(使用 Form.bindForm.bindFromRequest) 并且有一种描述约束的声明式方式。所以你的想法编辑对我来说是正确的!

有关 Play 文档中的表单 API 的更多信息: https://www.playframework.com/documentation/2.3.x/ScalaForms