这是一个具体的例子,尽管我在更一般的情况下遇到过这个问题。
我正在研究 Play 2.3 Web 应用程序和 Slack 之间的集成通过自定义斜杠命令。 (注意:Slack 有关于自定义斜杠命令 API 格式的文档,但我不相信我可以为未登录的读者直接深层链接它们。)
Slack 将(当用户适当调用时)使用已知格式的标准形式 URL 编码正文 POST 到我的端点。他们的官方示例是:
token=KpADMkoKxZJRGKTG8kJoWXGC
team_id=T0001
team_domain=example
channel_id=C2147483705
channel_name=test
user_id=U2147483697
user_name=Steve
command=/weather
text=94070
在我的应用程序中,我使用案例类对该请求进行建模。
case class SlashCommand(
token: String,
teamId: String,
teamDomain: String,
channelId: String,
channelName: String,
userId: String,
userName: String,
command: String,
text: String
)
顺便问一下,除了将每个字段设置为 String
之外,还有其他方法可以更好地实现类型约束吗?
我在从 Play 框架表示形式的 URL 编码转换为案例类时遇到问题。这是我目前拥有的代码,我相信它可以正常工作,但我觉得它过于重复。
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)
}
}
我理想中想要排除的有些重复的部分是:
- 显式
for
与显式get
s - 显式构建案例类
- 将
Request[AnyContent]
手动转换为Map[String, Option[String]
到Map[String, String]
是否有任何方法可以减少这些转换中的重复并提高可读性?
此外,我可能很快就需要相反的操作,即从案例类到 Map
和/或表单 URL 编码和/或 JSON 的转换。有什么方法可以减少重复吗?
提前致谢!
编辑:我一直在进一步思考这个问题,我认为我可以使用 Play 框架表单处理来处理前向案例做一些事情。
最佳答案
play Forms API 处理从 Request
、Map[String, String]
或 JsValue
到您喜欢的类型的绑定(bind)(使用 Form.bind
和 Form.bindFromRequest
),并且有一种声明式的方式来描述约束。所以你的想法编辑对我来说听起来很正确!
Play 文档中有关表单 API 的更多信息: https://www.playframework.com/documentation/2.3.x/ScalaForms
关于scala - 从 Map (Play 框架 request.body.asFormUrlEncoded) 转换为 case 类,反之亦然,使用更少的样板文件(与非类型化世界交互),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29227106/