json scala spray

Escriba un servidor json REST simple usando spray en scala



(3)

Quiero implementar un servidor json REST simple usando spray en scala que admita las siguientes rutas:

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

Mi código de inicio básico es el siguiente:

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 { "???" } } } } }

Los dos problemas abiertos más importantes con este código que conozco son:

  1. Dependo de Jackson, pero al buscar en la web, parece que el spray debería tener algún tipo de soporte integrado para serializar y deserializar objetos de casos simples o listas de objetos de casos.

  2. No estoy seguro de la "mejor", la forma más idiomática y sucinta de obtener contenido de la solicitud de publicación y convertirla en json para que pueda realizar algunos cálculos en los objetos de la clase de casos

¿Alguien sabe el mejor enfoque? ¿Hay alguna forma de hacer que el cálculo sea automático, de modo que pueda ejecutar algo como complete { caseObject } y hacer que caseObject convierta automáticamente en json (y viceversa con la definición del método POST)?


Definitivamente utiliza spray json. Por lo general, se separan los modelos de datos en su propio archivo:

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) }

Luego en la ruta

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) } } } }


Entendido gracias, aquí está mi respuesta.

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) } } } } }

Mi solicitud http con aplicación curl

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


No puedo imaginar por qué esta pregunta fue rechazada, parece específica y bien expresada.

Es un poco difícil de encontrar, pero los documentos de Spray cubren la extracción de clases de casos en Spray Routing / Advanced Topics. No tendría sentido repetir su explicación aquí, pero básicamente desea utilizar as[Foo] para deserializar contenido HTTP en objetos. La directiva de entity se puede usar para hacer esto para el cuerpo de una solicitud, como se muestra en este ejemplo más largo de la DSL de enrutamiento por aspersión . mapTo (utilizado en el mismo ejemplo) es probablemente lo que desea serializar un objeto para la respuesta.

Para JSON, probablemente sería más fácil usar su biblioteca Spray-JSON separado, ya que se conecta directamente a su mecanismo de tipo de clase, pero creo que podría con algún esfuerzo casarse con cualquier cosa que desee. Spray-JSON puede manejar una clase de caso con una línea de pegamento.

Por cierto, la val bar: Bar = ??? la línea val bar: Bar = ??? en su código de muestra, se ejecutará en el momento en que se define la ruta, no cuando se recibe una solicitud, como probablemente usted desea. Lea la sección Entender la estructura DSL de los documentos de enrutamiento por aspersión.