[英]http4s - get request body as String or InputStream
I'm trying to define HttpService
that receives json and parses it to case class with json4s
library:我试图定义
HttpService
接收JSON并将其分析与案例类json4s
库:
import org.http4s._
import org.http4s.dsl._
import org.json4s._
import org.json4s.native.JsonMethods._
case class Request(firstName: String, secondName: String)
HttpService {
case req @ POST -> Root =>
val request = parse(<map req.body or req.bodyAsText to JsonInput>).extract[Request]
Ok()
}
How can I get org.json4s.JsonInput
from req.body
or req.bodyAsText
?我怎样才能得到
org.json4s.JsonInput
从req.body
或req.bodyAsText
?
I know that json4s
also have StringInput
and StreamInput
that inherits from JsonInput
for using with String
and InputStream
so I think that I need to convert req.body
to InputStream
or req.bodyAsText
to String
but I still do not understand how.我知道
json4s
也有继承自JsonInput
StringInput
和StreamInput
用于与String
和InputStream
一起使用,所以我认为我需要将req.body
转换为InputStream
或req.bodyAsText
转换为String
但我仍然不明白如何。
I'm new to Scala and I do not yet fully understand some concepts such as scalaz.stream.Process
.我是 Scala 的新手,我还没有完全理解一些概念,例如
scalaz.stream.Process
。
Peter's solution both corrects the question and answers it, but I stumbled here looking for the solution to OP's stated, but not intended, question: "how to get request body as [...] InputStream" in http4s
.彼得的解决方案既纠正了问题,又回答了它,但我在这里偶然发现了 OP 提出但并非有意的问题的解决方案:“如何将请求正文作为 [...] InputStream” in
http4s
。 Thanks to the discussion in Issue 634 on GitHub, here's what I came up with:感谢 GitHub 上问题 634 中的讨论,这是我想出的:
import java.io.InputStream
import org.http4s._
implicit val inputStreamDecoder: EntityDecoder[InputStream] =
EntityDecoder.decodeBy(MediaRange.`*/*`) { msg =>
DecodeResult.success(scalaz.stream.io.toInputStream(msg.body))
}
And then in your HttpService, use that decoder like so:然后在您的 HttpService 中,像这样使用该解码器:
request.as[InputStream].flatMap { inputStream => ...inputStream is an InputStream... }
Or skip the whole Decoder dance, if you want:或者跳过整个解码器舞蹈,如果你想:
val inputStream = scalaz.stream.io.toInputStream(request.body)
You can use the http4s-json4s-jackson
(or http4s-json4s-native
) packages and use an org.http4s.EntityDecoder
to easily get a Foo
(I renamed your Request
case class to Foo
below) from a request.您可以使用
http4s-json4s-jackson
(或http4s-json4s-native
)包并使用org.http4s.EntityDecoder
从请求中轻松获取Foo
(我在下面将您的Request
案例类重命名为Foo
)。
EntityDecoder
is a type class which can decode an entity from the request body. EntityDecoder
是一个类型类,可以从请求正文中解码实体。 We want to get the Foo
posted in JSON, so we need to create an EntityDecoder[Foo]
which can decode JSON.我们想让
Foo
以 JSON EntityDecoder[Foo]
发布,因此我们需要创建一个可以解码 JSON 的EntityDecoder[Foo]
。 If we want to create this decoder using json4s we need a Reader
(or a JsonFormat
).如果我们想使用 json4s 创建这个解码器,我们需要一个
Reader
(或一个JsonFormat
)。
If you have an EntityDecoder[Foo]
instance, we can get the Foo
from the request with req.as[Foo]
.如果你有一个
EntityDecoder[Foo]
例如,我们可以得到Foo
从请求req.as[Foo]
。
import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.http4s._
import org.http4s.dsl._
import org.http4s.json4s.jackson._
case class Foo(firstName: String, secondName: String)
// create a json4s Reader[Foo]
implicit val formats = DefaultFormats
implicit val fooReader = new Reader[Foo] {
def read(value: JValue): Foo = value.extract[Foo]
}
// create a http4s EntityDecoder[Foo] (which uses the Reader)
implicit val fooDec = jsonOf[Foo]
val service = HttpService {
case req @ POST -> Root =>
// req.as[Foo] gives us a Task[Foo]
// and since Ok(...) gives a Task[Response] we need to use flatMap
req.as[Foo] flatMap ( foo => Ok(foo.firstName + " " + foo.secondName) )
}
Note: The json libraries libraries used most often with http4s are probably argonaut and circe .注意:最常与 http4s 一起使用的 json 库可能是argonaut和circe 。 So you might find more http4s examples using one of those libraries.
因此,您可能会发现更多使用这些库之一的 http4s 示例。
You may use flatMap
and as
inside it before calling the Http4s service to decode responses from it:在调用 Http4s 服务解码来自它的响应之前,您可以使用
flatMap
和as
在其中:
@Test def `Get json gives valid contact`: Unit = {
val request = Request[IO](GET, uri"/contact")
val io = Main.getJsonWithContact.orNotFound.run(request)
// here is magic
val response = io.flatMap(_.as[Json]).unsafeRunSync()
val contact = contactEncoder(Contact(1, "Denis", "123")) // this is encoding to json for assertion
assertEquals(contact, response)
}
This is how types work here:这就是类型在这里的工作方式:
val io: IO[Response[IO]] = Main.getJsonWithContact.orNotFound.run(request)
val response: IO[Json] = io.flatMap(_.as[Json])
val res: Json = response.unsafeRunSync()
as[String]
will return the string just like this. as[String]
将像这样返回字符串。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.