Подтвердить что ты не робот

Напишите простой сервер REST json, используя спрей в scala

Я хочу реализовать простой json-сервер REST, используя спрей в scala, который поддерживает следующие маршруты:

GET /foo => return a list of case class objects in json format
POST /bar => read a json into a case class object and perform some computation

Мой основной код стартера следующий:

import spray.routing.SimpleRoutingApp
import spray.can.Http
import akka.actor.ActorSystem
import akka.actor.Props
import akka.io.IO
import scala.collection.JavaConversions
import com.fasterxml.jackson.databind.ObjectMapper

object SprayTest extends App with SimpleRoutingApp {
  implicit val system = ActorSystem("my-system")
  val mapper = new ObjectMapper

  case class Foo(a: String, b: Int)
  case class Bar(c: Long, d: String)

  startServer(interface = "localhost", port = 8080) {
    get {
      path("foo") {
        complete {
          val c = listOfFoo()
          mapper.writeValueAsString(c)
        }
      }
    } ~ post {
      path("bar") {
        val bar: Bar = ???
        complete {
          "???"
        }
      }
    }
  }
}

Две самые важные проблемы с открытым кодом, которые я знаю, следующие:

  • Я в зависимости от jackson, но от поиска в Интернете кажется, что спрей должен иметь некоторую встроенную поддержку для сериализации и десериализации простых объектов объекта или списков объектов case.

  • Я не уверен, что "лучший", самый идиоматичный и лаконичный способ получить контент из почтового запроса и перевести его в json, чтобы я мог выполнять некоторые вычисления на объекте класса case

Кто-нибудь знает лучший подход? Есть ли способ сделать автоматизацию маршаллинга, поэтому я могу выполнить что-то вроде complete { caseObject } и преобразовать caseObject в json (и наоборот с помощью метода POST)?

4b9b3361

Ответ 1

Определенно использовать спрей json. Обычно вы разделяете модели данных в их собственный файл:

import spray.json._

case class Foo(a: String, b: Int)
case class Bar(c: Long, d: String)

object FooBarJsonProtocol extends DefaultJsonProtocol{
    implicit val fooFormat = jsonFormat2(Foo)
    implicit val barFormat = jsonFormat2(Bar)
}

Затем на маршруте

    import FooBarJsonProtocol._
    ...
    get {
      path("foo") {
        complete {
          listOfFoo() //with the implicit in scope this will serialize as json
        }
      }
    } ~ post {
      path("bar") {
        entity(as[Bar]) { bar =>  //extract json Bar from post body
          complete(bar) //serialize bar to json (or whatever processing you want to do)
        }
      }
    }
  }

Ответ 2

Я не могу себе представить, почему этот вопрос был пропущен - он кажется конкретным и хорошо выраженным.

Немного сложно найти, но документы Spray охватывают извлечение класса case в разделе Spray Routing/Advanced Topics. Было бы бессмысленно повторять их объяснение здесь, но в основном вы хотите использовать as[Foo] для десериализации содержимого HTTP в объекты. Директиву entity можно использовать для этого для тела запроса, как показано в этом более длинном примере DSL-маршрутизации с распылением. mapTo (используется в том же примере), вероятно, вы хотите сериализовать объект для ответа.

Для JSON было бы, вероятно, проще всего использовать свою отдельную библиотеку Spray-JSON, поскольку она подключается прямо к их механизму typeclass, но я подумайте, что вы с некоторым трудом выберетесь за все, что захотите. Spray-JSON может обрабатывать класс case с одной линией клея.

Кстати, строка val bar: Bar = ??? в вашем примере кода будет выполнена во время определения маршрута, а не при поступлении запроса, как вы, по-видимому, хотите. Пожалуйста, прочитайте раздел Общие сведения о структуре DSL в документах по распылительной разметке.

Ответ 3

Получил это спасибо, вот мой ответ

import spray.routing._
import spray.json._
import spray.httpx._
import spray.http._


case class UserLogin(username: String, password: String)

object UserLoginJsonSupport extends DefaultJsonProtocol with SprayJsonSupport {
   implicit val PortofolioFormats = jsonFormat2(UserLogin)
}

import UserLoginJsonSupport._


trait UserAccountsServiceAPI extends HttpService{       
    val UserAccountsServiceRouting = {
      path("api" / "userservice" ) {   
        post {
           entity(as[UserLogin]) { userLogin =>
                println("->"+userLogin.username)
                println("->"+userLogin.password)
                complete(userLogin.username)
           }
        }
      }
   }
}

Мой запрос http с curl app

curl -i 'http://localhost:8080/api/userservice' -X POST -H "Content-Type: application/json" -d '{"username": "admin", "password": "pwd"}'