io.circe_如何使用Circe(Un)在Akka HTTP中封送JSON

io.circe

by Miguel Lopez

由Miguel Lopez

如何使用Circe(Un)在Akka HTTP中封送JSON (How to (Un)marshal JSON in Akka HTTP with Circe)

Even though the usual library to (un)marshal JSON in Akka HTTP applications is spray-json, I decided to give circe a try. I use it in the Akka HTTP beginners course I’m working on. *cough* it’s free ? *cough*

即使在Akka HTTP应用程序中用于(取消)封送JSON的常用库是spray-json,我还是决定尝试一下。 我正在研究的Akka HTTP初学者课程中使用它。 * 咳嗽 * 是免费的吗? * 咳嗽*

In this post I’d like to show you why I tried it out.

在这篇文章中,我想向您展示为什么我尝试了它。

To use circe with Akka HTTP — and other JSON libraries for that matter — we have to create the marshalers and unmarshalers manually. Thankfully, there is an additional library that already does that for us.

要将circe与Akka HTTP以及其他JSON库一起使用,我们必须手动创建封送程序和取消封送程序。 值得庆幸的是,已经有一个额外的库已经为我们做到了。

项目设置和概述 (Project setup and overview)

Clone the project’s repository, and checkout the branch 3.3-repository-implementation.

克隆项目的存储库 ,然后检出branch 3.3-repository-implementation

Under src/main/scala you'll find the following files:

src/main/scala您将找到以下文件:

$ tree srcsrc└── main    └── scala        ├── Main.scala        ├── Todo.scala        └── TodoRepository.scala2 directories, 3 files

The Main object is the application's entry point. So far it has a hello world route and it binds it to a given host and route.

Main对象是应用程序的入口点。 到目前为止,它具有问候世界路由,并将其绑定到给定的主机和路由。

Todo is our application’s model. And the TodoRepository is in charge of persisting and accessing todos. So far it only has an in-memory implementation to keep things simple and focused.

Todo是我们应用程序的模型。 TodoRepository负责持久化和访问待办事项。 到目前为止,它只有一个内存实现来使事情简单和集中。

列出所有待办事项 (Listing all the todos)

We’ll change the Main object’s route to list all the todos in a repository. We will also add some initial todos for testing:

我们将更改Main对象的路由以列出存储库中的所有待办事项。 我们还将添加一些初始待办事项进行测试:

import akka.actor.ActorSystemimport akka.http.scaladsl.Httpimport akka.stream.ActorMaterializerimport scala.concurrent.Awaitimport scala.util.{Failure, Success}object Main extends App {  val host = "0.0.0.0"  val port = 9000  implicit val system: ActorSystem = ActorSystem(name = "todoapi")  implicit val materializer: ActorMaterializer = ActorMaterializer()  import system.dispatcher  val todos = Seq(    Todo("1", "Clean the house", "", done = false),    Todo("2", "Learn Scala", "", done = true),  )  val todoRepository = new InMemoryTodoRepository(todos)  import akka.http.scaladsl.server.Directives._  def route = path("todos") {    get {      complete(todoRepository.all())    }  }  val binding = Http().bindAndHandle(route, host, port)  binding.onComplete {    case Success(_) => println("Success!")    case Failure(error) => println(s"Failed: ${error.getMessage}")  }  import scala.concurrent.duration._  Await.result(binding, 3.seconds)}

Now we’re listening to requests under /todos and we respond with all the todos we have in our todoRepository.

现在,我们正在侦听/todos下的请求,并使用todoRepository所有todo进行响应。

However, if we try to run this it won’t compile:

但是,如果我们尝试运行此命令,它将无法编译:

Error:(26, 34) type mismatch; found   : scala.concurrent.Future[Seq[Todo]] required: akka.http.scaladsl.marshalling.ToResponseMarshallable      complete(todoRepository.all())

The compilation error is telling us it doesn’t know how to marshal our todos into JSON.

编译错误告诉我们它不知道如何将待办事项编组为JSON。

We need to import circe and the support library:

我们需要导入circe和支持库:

import akka.http.scaladsl.server.Directives._import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._import io.circe.generic.auto._def route = path("todos") {  get {    complete(todoRepository.all())  }}

With those two extra lines we can now run our Main object and test our new route.

通过这两行,我们现在可以运行Main对象并测试新路线。

Make a GET request to http://localhost:9000/todos :

http://localhost:9000/todos发出GET请求:

And we get our todos back! ?

而且我们还可以得到待办事项! ?

创建待办事项 (Creating todos)

Turns out that unmarshaling JSON into our models doesn’t take much effort either. But our TodoRepository doesn’t support saving todos at the moment. Let’s add that functionality first:

事实证明,将JSON编组到我们的模型中也不需要太多的工作。 但是我们的TodoRepository目前不支持保存TodoRepository 。 让我们先添加该功能:

import scala.concurrent.{ExecutionContext, Future}trait TodoRepository {  def all(): Future[Seq[Todo]]  def done(): Future[Seq[Todo]]  def pending(): Future[Seq[Todo]]  def save(todo: Todo): Future[Todo]}class InMemoryTodoRepository(initialTodos: Seq[Todo] = Seq.empty)(implicit ec: ExecutionContext) extends TodoRepository {  private var todos: Vector[Todo] = initialTodos.toVector  override def all(): Future[Seq[Todo]] = Future.successful(todos)  override def done(): Future[Seq[Todo]] = Future.successful(todos.filter(_.done))  override def pending(): Future[Seq[Todo]] = Future.successful(todos.filterNot(_.done))  override def save(todo: Todo): Future[Todo] = Future.successful {    todos = todos :+ todo    todo  }}

We added a method save to the trait and the implementation. Because we are using a Vector our implementation of save will store duplicated todos. That’s fine for the purposes of this tutorial.

我们向特征和实现添加了save方法。 因为我们使用的是Vector ,所以save的实现将存储重复的待办事项。 就本教程而言,这很好。

Let’s add a new route that will listen to POST requests. This route receive a Todo as the request’s body and saves it into our repository:

让我们添加一条新的路由来监听POST请求。 此路由将Todo作为请求的主体,并将其保存到我们的存储库中:

def route = path("todos") {  get {    complete(todoRepository.all())  } ~ post {    entity(as[Todo]) { todo =>      complete(todoRepository.save(todo))    }  }}

Using the entity directive we can build a route that automatically parses incoming JSON to our model. It also rejects requests with invalid JSON:

使用entity指令,我们可以构建一个路由,该路由自动将传入的JSON解析到我们的模型。 它还拒绝使用无效JSON的请求:

We sent the done field as a string, and it should have been a boolean, which our API responded to with bad request.

我们以字符串形式发送了done字段,它应该是一个布尔值,我们的API响应该请求时发出了错误请求。

Let’s make a valid request to create a new todo:

让我们发出一个有效的请求来创建一个新的待办事项:

This time we sent the property as done := false, which tells HTTPie to send the value as Boolean instead of String.

这次我们将属性发送为done := false ,这告诉HTTPie将值作为Boolean而不是String

We get our todo back and a 200 status code, which means it went well. We can confirm it worked by querying the todos again:

我们找回待办事项和200状态代码,这意味着一切顺利。 我们可以通过再次查询待办事项来确认它是否有效:

We get three todos, the hardcoded ones and the new one we created.

我们得到三个待办事项,分别是硬编码和新创建的。

结语 (Wrapping up)

We added JSON marshaling and unmarshaling to our application by adding the dependencies (it was already done in the project) and by importing both libraries.

通过添加依赖项(已经在项目中完成)并导入两个库,我们在应用程序中添加了JSON封送处理和取消封送处理。

Circe figures out how to handle our models without much intervention from us.

Circe指出了如何在没有太多干预的情况下处理我们的模型。

In a future post, we will explore how to accomplish the same functionality with spray-json instead.

在以后的文章中,我们将探索如何使用spray-json来实现相同的功能。

Stay tuned!

敬请关注!

If you liked this tutorial and want to learn how to build an API for a todo application, check out our new free course! ???

如果您喜欢本教程,并且想学习如何为待办事项应用程序构建API,请查看我们的新免费课程! ???

Akka HTTP QuickstartLearn how to create web applications and APIs with Akka HTTP in this free course!link.codemunity.io

Akka HTTP快速入门 在此免费课程中,了解如何使用Akka HTTP创建Web应用程序和API! link.codemunity.io

Originally published at www.codemunity.io.

最初在www.codemunity.io上发布。

翻译自: https://www.freecodecamp.org/news/un-marshalling-json-in-akka-http-with-circe-3dcc2764eedb/

io.circe

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值