我正在实现一个Scala / Play API(apiA),它消耗了我无法控制的API(apiB)。ApiB返回JSON响应,在某些情况下,JSON响应已嵌入字符串中。例:
{
"name":"some_name",
"scores": "[[10,15]]",
"data": "{\"attr1\":\"value1\",\"attr2\":\"value3\"}"
}
ApiA需要name
在将所有数据传递给客户端之前访问的值,并且应将其作为适当的JSON提供给客户端。我正在考虑将原始响应解析为
case class Response(name: String, scores: JsValue, data: JsValue)
要么
case class Response(name: String, scores: Seq[Seq[Int]], data: Map[String, String])
到目前为止,只要不是包含JSON的字符串scores
,data
将其解析为哪种类型都没有关系。
现在,如果JSON响应格式正确,那么编写格式/读取/写入将很简单,但是我在解决如何在解析为最终类型之前将内容转换为JSON时颇为犹豫。
任何帮助,将不胜感激。
case class Response(name: String, scores: Seq[Seq[Int]], data: Map[String, String])
import play.api.libs.json._
val stringified = Reads[JsValue] {
_.validate[String].flatMap { raw =>
try {
JsSuccess(Json.parse(raw))
} catch {
case cause =>
JsError(cause.getMessage)
}
}
}
implicit val respReads = Reads[Response] { js =>
for {
name <- (js \ "name").validate[String]
scores <- (js \ "scores").validate(
stringified).flatMap(_.validate[Seq[Seq[Int]]])
data <- (js \ "data").validate(
stringified).flatMap(_.validate[Map[String, String]])
} yield Response(name, scores, data)
}
Json.parse("""{
"name":"some_name",
"scores": "[[10,15]]",
"data": "{\"attr1\":\"value1\",\"attr2\":\"value3\"}"
}""").validate[Response]
// JsSuccess(Response(some_name,Vector(Vector(10, 15)),Map(attr1 -> value1, attr2 -> value3)),)