Напишите простой сервер 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)?
Ответы
Ответ 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"}'