
Содержание статьи
от Мигеля Лопеса

В предыдущей публикации мы добавили поддержку JSON к нашему Akka HTTP API с помощью circe.
На этот раз мы сделаем то же самое, но с помощью spray-json. Akka HTTP поддерживает это, предоставляя официальную библиотеку – нам не нужна сторонняя библиотека, как это было с circe.
Настройка проекта
Для настройки проекта мы выполним те же шаги, что и в предыдущем руководстве.
Клонируйте репо и проверьте ветку 3.3-repository-implementation
.
Мы также внесем изменения, которые были внесены в предыдущем учебнике.
Сначала мы заменим зависимость circe на зависимость spray-json, поскольку она нам не понадобится для этого учебника. Обновите build.sbt
файл с таким содержимым:
name := "akkahttp-quickstart"version := "0.1"scalaVersion := "2.12.6"val akkaVersion = "2.5.13"val akkaHttpVersion = "10.1.3"libraryDependencies ++= Seq( "com.typesafe.akka" %% "akka-actor" % akkaVersion, "com.typesafe.akka" %% "akka-testkit" % akkaVersion % Test, "com.typesafe.akka" %% "akka-stream" % akkaVersion, "com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion % Test, "com.typesafe.akka" %% "akka-http" % akkaHttpVersion, "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion % Test, "com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpVersion, "org.scalatest" %% "scalatest" % "3.0.5" % Test)
Далее мы добавим a save
функция до 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 }}
Это позволит создать запрос POST для создания новых задач.
И, наконец, обновите 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", "Record amazing gifs for the tutorials", "", done = false), Todo("2", "Finish the spray-json tutorial", "", done = true), ) val todoRepository = new InMemoryTodoRepository(todos) import akka.http.scaladsl.server.Directives._ def route = path("todos") { get { complete(todoRepository.all()) } ~ post { entity(as[Todo]) { todo => complete(todoRepository.save(todo)) } } } 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)}
После этого мы можем перейти к поддержке анализа JSON.
Создание формата
Проект не должен компилироваться сейчас, потому что Akka HTTP не знает, как конвертировать JSON в наши модели и наоборот.
Добавить поддержку JSON с помощью circe было достаточно просто. Это включало только добавление нескольких операторов импорта.
К сожалению, из spray-json это не так. Усилия тоже не так велики.
Итак, начнём.
Поскольку мы хотим использовать spray-json из Akka HTTP, мы можем просмотреть официальные документы Akka HTTP о том, как добиться того, что мы хотим.
Нам нужно расширить черту SprayJsonSupport
чтобы дать Akka HTTP знать, как анализировать наши модели в и из JSON (через файл FromEntityUnmarshaller
и ToEntityMarshaller
обеспечивается признаком).
И создать актуальное форматмы будем использовать признак DefaultJsonProtocol
из spray-json.
Добавьте следующий объект под Todo
модель:
object TodoFormat extends SprayJsonSupport with DefaultJsonProtocol { implicit val todoFormat = jsonFormat4(Todo)}
Это дополнительный шаг, который нам необходим при использовании spray-json. Это нужно сделать для каждой модели, которую у нас есть.
Чтобы наш проект заработал, нам нужно импортировать TodoFormat
в нашем Main
объект:
import TodoFormat._import akka.http.scaladsl.server.Directives._def route = path("todos") { get { complete(todoRepository.all()) } ~ post { entity(as[Todo]) { todo => complete(todoRepository.save(todo)) } }}
Запустите программу, и она должна работать нормально.
Давайте проведем несколько тестов!
Тестирование нашего API
Нам нужно убедиться, что наш API работает должным образом. Давайте спросим его, как мы делали в предыдущем учебнике, чтобы проверить, функциональность такая же.
Отправка запроса GET в localhost:9000/todos
должно дать нам первоначальные задачи:

Прекрасно, это работает так же.
Давайте посмотрим, дает ли нам отправка недействительного JSON что-то подобное:

Это делает. Сообщение об ошибке разное, но мы получаем то же 400 Bad Request
что является важной частью.
Давайте создадим новое задание с действительным JSON:

И чтобы кончить, давайте еще раз спросим todos, чтобы убедиться, что они сохранены:

Там мы уходим. У нас есть рабочая программа с spray-json.
Круто, не правда ли?
Подведению
Несмотря на то, что работа с spray-json подразумевает дополнительную ручную работу, вам не нужна дополнительная зависимость от сторонних разработчиков, чтобы заставить его работать с Akka HTTP.
Это действительно вопрос преимуществ.
В будущем мы будем исследовать, как выполнить различные варианты использования для обоих, чтобы сравнить их. Следите за обновлением!
Если вам понравилось это руководство и вы хотите узнать, как создать API для программы Todo, просмотрите наш новый бесплатно конечно! ???
Akka HTTP Quickstart
Узнайте, как создать веб-приложения и API с помощью Akka HTTP в этом бесплатном курсе!link.codemunity.io
Первоначально опубликовано на www.codemunity.io.