如果这是一个XY问题,我很抱歉。如何在编译时以编程方式创建验证合同?
TL;博士:
我想有[Request.type, Response.type]
类型的编译时间图,所以我可以有效地说,如果我发送消息Request
,一个CLI应,在编译时,知道如何反序列化其预期的Response
,而不管它直到运行时才知道发送了什么类型的请求。
太长;仍然阅读:
我有一个CLI与HTTP服务器通信,并根据发送到HTTP服务器的消息类型,我想验证JSON响应对案例。
举例来说,如果我发送HTTP服务器的AddFoo
消息,我可能要验证JSON响应可以反序列化到AddedFoo
等
我目前的解决方案是相当哈克。使用play-json,我试图使用从config.mode
(即,发布到CLI的命令)到预期响应的隐含Reads
的映射来解析JSON响应。
我的代码看起来是这样的:
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]
)。
当然,我的方法是不正确的......这是传统上的做法吗?如果方法正确(请不要),是否可以优化?
你的意思是,在*运行时*过去了,发出HTTP请求时,意思? –
我只会尝试在类型都扩展一些密封特征或抽象类的时候这样做,因为只有类匹配才能帮助您在此之后进行排序。 –
@MichaelZajac所有的请求都会扩展'MyBaseRequest',所有的响应都会扩展'MyBaseResponse'。我发现这是一个相当顽皮的问题......我认为这将是一个众所周知的模式。 :) – erip