Напишите простой сервер JSON REST с помощью spray в scala
Я хочу реализовать простой сервер JSON REST с помощью spray в 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 {
"???"
}
}
}
}
}
две наиболее важные открытые проблемы с этим кодом, о которых я знаю:
Я в зависимости от Джексона, но от поиска в интернете кажется, что spray должен иметь какую-то встроенную поддержку для сериализации и десериализации простых объектов case или списков объекты дела.
Я не уверен, что "лучший", самый идиоматичный и краткий способ получить контент из запроса post и Маршалл его в json, чтобы я мог выполнить некоторые вычисления на объекте (объектах) класса case
кто-нибудь знает лучший подход? Есть ли способ сделать маршалинг автоматическим, чтобы я мог выполнить что-то вроде complete { caseObject }
и caseObject
автоматически конвертировать в json (и наоборот с определением POST метод)?
3 ответов
определенно используйте спрей 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)
}
}
}
}
Я не могу понять, почему этот вопрос был проголосован-он кажется конкретным и хорошо выраженным.
Это немного трудно найти, но спрей документов обложка случай извлечения класса под трассой брызг / предварительными темами. Было бы бессмысленно повторять свои объяснения, но в основном вы хотите использовать as[Foo]
десериализовать содержимое HTTP в объекты. The может использоваться для этого для тела запроса, как показано в этом больше примеров распыление DSL. mapTo
(используется в том же примере), вероятно, что вы хотите сериализовать объект в ответ.
для JSON, вероятно, было бы проще использовать их отдельные спрей-JSON-формате библиотека, так как она подключается прямо к их механизму typeclass, но я думаю, что вы могли бы с некоторыми усилиями жениться на чем угодно. Спрей-JSON может обрабатывать класс корпуса с одной линией клея.
кстати, строку val bar: Bar = ???
в вашем примере кода будет выполняться во время определения маршрута, а не при поступлении запроса, как вы предположительно хотите. Ознакомьтесь, пожалуйста понимание структуры DSL раздел документов маршрутизации распыления.
понял спасибо, вот мой ответ
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"}'