如何解组 json 响应使用 Akka HTTP 删除不必要的字段

How to unmarshall json response removing unnecessary fields using Akka HTTP

我是 Akka HTTP 的新手,我想从 JSON 响应中删除不必要的字段,只获取必要的字段。例如,我使用 this 端点来获取响应,它包含一堆字段。目前我只需要 'name' 和 'versions'。我想知道如何将其反序列化为仅包含 'name' 和 'versions' 的案例 class。我编写了以下行以将响应作为字符串获取。

import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpRequest, HttpResponse}
import akka.stream.scaladsl.{Flow, Sink, Source}
import akka.stream.{ActorMaterializer, OverflowStrategy}

import scala.concurrent.Future
import scala.concurrent.duration.DurationInt
import scala.language.postfixOps
import scala.util.{Failure, Success}

object SoftwareRegistry extends App {

  implicit val system = ActorSystem("NPMRegistry")
  implicit val materializer = ActorMaterializer()

  import system.dispatcher

  case class NPMPackage(name: String)

  // reading the packages
  val filename = "B:\Scala\NPMRegistry\src\main\resources\packages.txt"
  val bufferedSource = scala.io.Source.fromFile(filename)
  val listOfPackages: List[NPMPackage] = (for (line <- bufferedSource.getLines) yield {
    NPMPackage(line.trim)
  }).toList
  bufferedSource.close()

  // source
  val sourceList = Source(listOfPackages)

  // sink
  val sink = Sink.foreach[NPMPackage] { p =>
    // https request
    val responseFuture: Future[HttpResponse] =
      Http().singleRequest(HttpRequest(uri = s"https://registry.npmjs.org/${p.name}"))
    val x = responseFuture
      .flatMap(_.entity.toStrict(2 seconds))
      .map(_.data.utf8String)
    x.onComplete {
      case Success(res) => println(res)
      case Failure(_) => sys.error("Something went wrong")
    }
  }

  // flow to slow things down and streaming sink to time-delayed operations
  val bufferedFlow = Flow[NPMPackage]
    .buffer(10, overflowStrategy = OverflowStrategy.backpressure)
    .throttle(1, 3 seconds)

  sourceList.async
    .via(bufferedFlow).async
    .to(sink)
    .run()
}

并打印以下输出

要解析 json,您需要使用一些库。在 akka-http 文档中,他们使用 spray-json。使用适当的 akkaHttpVersion.

将以下依赖项添加到您的 build.sbt
"com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpVersion

现在您需要数据的序列化器和反序列化器。我正在使用一个简单的模型,根据需要更改它。

trait Formatter extends DefaultJsonProtocol {

  implicit object jsonFormat extends JsonFormat[Versions] {
    override def read(json: JsValue): Versions = json match {
      case JsObject(fields) =>
        Versions(fields.keys.toList)
    }

    override def write(obj: Versions): JsValue = JsonParser(obj.toString)
  }

  implicit val formatterPackage: RootJsonFormat[Package] = jsonFormat2(Package)

  case class Package(name: String, versions: Versions)

  case class Versions(versions: List[String])
}

终于sink:

 //needed import with others
 import spray.json._

 object SoftwareRegistry extends App  with Formatter {

   //existing code
   //---------


   val sink = Sink.foreach[NPMPackage] { p =>
       // https request
       val responseFuture: Future[HttpResponse] =
         Http().singleRequest(HttpRequest(uri = s"https://registry.npmjs.org/${p.name}"))
       val packages = responseFuture
         .flatMap(
           _.entity
             .dataBytes
             .via(JsonFraming.objectScanner(Int.MaxValue))
             .map(_.utf8String)
             .map(_.parseJson.convertTo[Package])
             .toMat(Sink.seq)(Keep.right)
             .run()
         )

       packages.onComplete {
         case Success(res) => println(res)
         case Failure(_) => sys.error("Something went wrong")
       }
   }

   //existing code
   //---------
}