我正在尝试使用sttp核心库和sttp json4s库来接收json响应并将其转换为case类。
Github上的源代码是 here ,我尝试复制的此示例的文档是 here
对GET
网址http://httpbin.org/get?foo=bar
的{{1}}请求的响应如下:
{
"args": {
"foo": "bar"
},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip,deflate",
"Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
"Connection": "close",
"Cookie": "_gauges_unique_day=1; _gauges_unique_month=1; _gauges_unique_year=1; _gauges_unique=1; stale_after=never",
"Forwarded": "for=49.255.235.138",
"Host": "httpbin.org",
"Save-Data": "on",
"Scheme": "http",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
},
"origin": "49.255.235.138, 66.249.82.79",
"url": "http://httpbin.org/get?foo=bar"
}
尝试读取上面的json响应的case类看起来像:
case class HttpBinResponse(
args: Map[String, String],
origin: String,
headers: Map[String,String]
)
案例类已在测试文件的顶部定义,可供测试访问。
此测试通过:
it should "send a GET request parse response as JSON" in {
implicit val backend = HttpURLConnectionBackend()
val queryParams = Map("foo" -> "bar", "bugs" -> "life")
val endpoint:Uri = uri"http://httpbin.org/get?foo=bar"
val request = sttp
.get(endpoint)
.response(asJson[HttpBinResponse])
val response = request.send()
// response.body is an Either
response.code should be(200)
val res = response.body.fold(_ => { "Error" }, a => { a })
res shouldBe a[HttpBinResponse]
}
产生错误的代码如下所示:
it should "send a GET request parse response as JSON" in {
implicit val backend = HttpURLConnectionBackend()
val queryParams = Map("foo" -> "bar", "bugs" -> "life")
val endpoint:Uri = uri"http://httpbin.org/get?foo=bar"
val request = sttp
.get(endpoint)
.response(asJson[HttpBinResponse])
val response = request.send()
// response.body is an Either
response.code should be(200)
val res = response.body.fold(_ => { "Error" }, a => { a })
res shouldBe a[HttpBinResponse]
println(res.origin)
}
但是,当我尝试访问res.origin
中的值时,我看到的错误是value origin is not a member of java.io.Serializable
28. Waiting for source changes... (press enter to interrupt)
[info] Compiling 1 Scala source to /Users/localuser/Do/scalaexercises/target/scala-2.12/test-classes...
[error] /Users/localuser/Do/scalaexercises/src/test/scala/example/SttpSpec.scala:58: value origin is not a member of java.io.Serializable
[error] println(res.origin)
[error] ^
[error] one error found
[error] (test:compileIncremental) Compilation failed
答案 0 :(得分:0)
Rob Norris on the gitter scala channel回答了这个问题:
折叠Either时,结果为Serializable。尝试模式匹配,或折叠到sys.error而不是String。
结果上的模式匹配:
val res = response.body.fold(_ => { "Error" }, a => { a })
res match {
case HttpBinResponse(_, origin) => {
println("-----------------------------")
print("The origin for the request is ")
print(origin)
println("-----------------------------")
}
case _ => "Error"
}
将左侧折叠为sys.error
而不是字符串,在这种情况下不需要模式匹配:
val res = response.body.fold(
_ => { error("Error") },
a => { a }
)
println(res.origin)
res.args should contain("foo" -> "bar")
res.args should contain key("bugs")
res.args should contain value("life")
res.origin.length should be >10
这两种方法中的任何一种都可以解决问题。