如果这是一个 XY 问题,我提前道歉。
tl;博士:
我想要一个类型的编译时映射,[Request.type, Response.type]
这样我就可以有效地说如果我发送 message Request
,CLI 应该在编译时知道如何反序列化它的 expected Response
,而不管它不知道什么类型的请求会一直发送到运行时。
太长; 仍然阅读:
我有一个与 HTTP 服务器通信的 CLI,根据发送到 HTTP 服务器的消息类型,我想根据案例验证 JSON 响应。
例如,如果我向 HTTP 服务器发送一条AddFoo
消息,我可能想验证 JSON 响应是否可以反序列化为AddedFoo
等。
我目前的解决方案非常hacky。使用 play-json,我尝试使用从config.mode
(即,发出给 CLI 的命令)到预期响应的映射来解析 JSON 响应Reads
。
我的代码看起来像这样:
val modeToResponseReads: Map[String, Reads[_]] = Map(
Modes.ADD_FOO -> AddedFoo.addedFooReads,
Modes.ADD_BOO -> AddedBoo.addedBooReads,
Modes.GET_WOO -> GetWooResponse.getWooReads,
)
parser.parse(args, MyConfig()) match {
case Some(config) => try {
val exec = new MyHttpExecutor(remoteUri, config)
val res = Await.result(exec.getResponse, 100.seconds)
// passing `Reads` to `as` because JsValue#as[T] cannot be
// applied at runtime -- only compile-time.
val _ = Json.parse(res.json.toString)
.as(modeToResponseReads(config.mode))
exec.actorSystem.terminate()
exec.wsClient.close()
} catch {
case t: Throwable => logger.error(t.getMessage)
}
case None => {
logger.error("Bad arguments.")
sys.exit(1)
}
}
虽然这很有效,但随着消息数量的增加,它变得越来越难以维护。此外,我发现这种模式需要在需要进行某种类型的验证或转换(例如,Future[Any]
转换为Future[AddedFoo]
)的任何地方复制。
当然我的方法不是正确的方法......传统上这是如何完成的?如果是正确的方法(请不要),是否可以进行优化?