2014-06-06 8 views
21

Voglio realizzare un semplice server JSON REST utilizzando spruzzo in scala che supporta i seguenti itinerari:Scrivere un semplice server JSON REST utilizzando spruzzo in 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 

Il mio codice di avviamento di base è la seguente:

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

Le due più importanti questioni aperte con questo codice che io sappia sono:

  1. sono a seconda di Jackson, ma dalla ricerca sul Web, sembra che lo spray debba avere una sorta di supporto integrato per la serializzazione e la deserializzazione di semplici case o elenchi di oggetti del caso.

  2. Non sono sicuro che il "migliore", più idiomatica e modo succinto per ottenere contenuti dalla richiesta posta e Marshall in JSON in modo che possa eseguire alcune calcoli sull'oggetto caso della classe (s)

Qualcuno conosce l'approccio migliore? C'è un modo per rendere automatico il marshalling, quindi posso eseguire qualcosa come complete { caseObject } e convertire caseObject automaticamente in json (e viceversa con la definizione del metodo POST)?

risposta

20

Utilizzare decisamente spray spray. Di solito si separano i modelli di dati nel proprio file:

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

Poi nel percorso

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

In 'spray-json' 1.3.3 impor importare 'importazione spray.httpx.SprayJsonSupport._' – Core

+1

Gangstead - Grazie mille! molto utile!!! – Briksins

+0

Attenzione anche all'ordine/importazione. –

7

Non riesco a immaginare perché questa domanda sia stata rifiutata, sembra specifica e ben espressa.

È un po 'difficile da trovare, ma i documenti Spray coprono case class extraction in Percorso di spruzzo/Argomenti avanzati. Sarebbe inutile ripetere qui la loro spiegazione, ma in pratica si desidera utilizzare as[Foo] per deserializzare il contenuto HTTP in oggetti. La direttiva entity può essere utilizzata per fare ciò per il corpo di una richiesta, come mostrato in questo longer example of the spray-routing DSL. mapTo (utilizzato nello stesso esempio) è probabilmente ciò che si desidera serializzare un oggetto per la risposta.

Per JSON, sarebbe probabilmente più semplice utilizzare la libreria separata Spray-JSON, poiché si collega direttamente al loro meccanismo di classe, ma penso che con qualche sforzo si possa sposare tutto ciò che si desidera. Spray-JSON è in grado di gestire una classe di casi con una linea di colla.

A proposito, la linea val bar: Bar = ??? nel codice di esempio verrà eseguita nel momento in cui viene definito il percorso, non quando viene richiesta una richiesta, come presumibilmente si desidera. Si prega di leggere la sezione Understanding the DSL Structure dei documenti spray-routing.

2

Capito grazie, ecco la mia risposta

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

La mia richiesta HTTP con l'arricciatura app

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