簡體   English   中英

http4s - 以 String 或 InputStream 形式獲取請求正文

[英]http4s - get request body as String or InputStream

我試圖定義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()
}

我怎樣才能得到org.json4s.JsonInputreq.bodyreq.bodyAsText

我知道json4s也有繼承自JsonInput StringInputStreamInput用於與StringInputStream一起使用,所以我認為我需要將req.body轉換為InputStreamreq.bodyAsText轉換為String但我仍然不明白如何。

我是 Scala 的新手,我還沒有完全理解一些概念,例如scalaz.stream.Process

彼得的解決方案既糾正了問題,又回答了它,但我在這里偶然發現了 OP 提出但並非有意的問題的解決方案:“如何將請求正文作為 [...] InputStream” in http4s 感謝 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))
}

然后在您的 HttpService 中,像這樣使用該解碼器:

request.as[InputStream].flatMap { inputStream => ...inputStream is an InputStream... }

或者跳過整個解碼器舞蹈,如果你想:

val inputStream = scalaz.stream.io.toInputStream(request.body)

您可以使用http4s-json4s-jackson (或http4s-json4s-native )包並使用org.http4s.EntityDecoder從請求中輕松獲取Foo (我在下面將您的Request案例類重命名為Foo )。

EntityDecoder是一個類型類,可以從請求正文中解碼實體。 我們想讓Foo以 JSON EntityDecoder[Foo]發布,因此我們需要創建一個可以解碼 JSON 的EntityDecoder[Foo] 如果我們想使用 json4s 創建這個解碼器,我們需要一個Reader (或一個JsonFormat )。

如果你有一個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) )
}

注意:最常與 http4s 一起使用的 json 庫可能是argonautcirce 因此,您可能會發現更多使用這些庫之一的 http4s 示例。

在調用 Http4s 服務解碼來自它的響應之前,您可以使用flatMapas其中:

@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)
}

這就是類型在這里的工作方式:

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]將像這樣返回字符串。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM