2014-05-15 14 views
9

Quando utilizzo Spray.io per sviluppare un'API RESTful, come dovrei strutturare la mia applicazione?Come strutturare un'API RESTful con Spray.io?

Ho già visto this answer su come dividere un'applicazione Spray, ma non sono soddisfatto, dal momento che non sembra utilizzare l'approccio "un attore per richiesta". Posso inoltrare richieste dall'attore root ad altri attori nella mia applicazione in base ai percorsi e, all'interno di questi attori, definire i percorsi correlati?

Grazie

risposta

8

Puoi richieste certamente avanti da un attore a un altro, sulla base di percorsi o qualsiasi altra cosa. Guarda il mio progetto di esempio (che è un fork di un fork di un progetto di esempio):

https://github.com/gangstead/spray-moviedb/blob/master/src/main/scala/com/example/routes/ApiRouter.scala

codice relavent dal protagonista che riceve tutte le richieste e le rotte di loro ad altri attori che gestiscono ogni servizio:

def receive = runRoute { 
    compressResponseIfRequested(){ 
     alwaysCache(simpleCache) { 
     pathPrefix("movies") { ctx => asb.moviesRoute ! ctx } ~ 
     pathPrefix("people") { ctx => asb.peopleRoute ! ctx } 
     } ~ 
     pathPrefix("login") { ctx => asb.loginRoute ! ctx } ~ 
     pathPrefix("account") { ctx => asb.accountRoute ! ctx } 
    } 
    } 

E per esempio il percorso film:

def receive = runRoute { 
    get { 
     parameters('query, 'page ? 1).as(TitleSearchQuery) { query => 
     val titleSearchResults = ms.getTitleSearchResults(query) 
     complete(titleSearchResults) 
     }~ 
     path(LongNumber) { movieId => 
     val movie = ms.getMovie(movieId) 
     complete(movie) 
     }~ 
     path(LongNumber/"cast") { movieId => 
     val movieCast = ms.getMovieCast(movieId) 
     complete(movieCast)  
     }~ 
     path(LongNumber/"trailers") { movieId => 
     val trailers = ms.getTrailers(movieId) 
     complete(trailers)  
     }   
    } 
    } 
+0

Stavo guardando il tuo esempio qui e ho notato che usi il CDI. Qualche ragione in particolare per cui hai scelto di usarlo? – EdMelo

+0

Per CDI intendi un'iniezione di dipendenza? – Gangstead

+0

Sì./* StackOverflow richiede più caratteri quindi ... */ – EdMelo

0

ho faticato molto con la creazione di primo progetto completo REST. Gli esempi che ho trovato erano a livello mondiale ... Ho letto alcuni blog, pochi commenti e ho deciso di creare un progetto di esempio. Si basa su scala/Akka/spruzzo/mysql

Si esempio di lavoro completo con websocket per notificare i clienti che i dati sono stati modificati, ecc Si può controllare sul https://github.com/vixxx123/scalasprayslickexample

Ecco il codice di esempio di routing da quel progetto :

val personCreateHandler = actorRefFactory.actorOf(RoundRobinPool(2).props(Props[CreateActor]), s"${TableName}CreateRouter") 
val personPutHandler = actorRefFactory.actorOf(RoundRobinPool(5).props(Props[UpdateActor]), s"${TableName}PutRouter") 
val personGetHandler = actorRefFactory.actorOf(RoundRobinPool(20).props(Props[GetActor]), s"${TableName}GetRouter") 
val personDeleteHandler = actorRefFactory.actorOf(RoundRobinPool(2).props(Props[DeleteActor]), s"${TableName}DeleteRouter") 

val userRoute = 
    pathPrefix("person") { 
     pathEnd { 
      get { 
       ctx => personGetHandler ! GetMessage(ctx, None) 
      } ~ 
      post { 
       entity(as[Person]) { 
        entity => 
         ctx => personCreateHandler ! CreateMessage(ctx, entity) 
       } 
      } 
     } ~ 
     pathPrefix (IntNumber){ 
      entityId => { 
       pathEnd { 
        get { 
         ctx => personGetHandler ! GetMessage(ctx, Some(entityId)) 
        } ~ put { 
         entity(as[Person]) { entity => 
          ctx => personPutHandler ! PutMessage(ctx, entity.copy(id = Some(entityId))) 
         } 
        } ~ delete { 
         ctx => personDeleteHandler ! DeleteMessage(ctx, entityId) 
        } ~ patch { 
         ctx => personPutHandler ! PatchMessage(ctx, entityId) 
        } 
       } 
      } 
     } 
    } 

e campione da creare gestore attore:

override def receive: Receive = { 

    case CreateMessage(ctx, person) => 

     val localCtx = ctx 
     connectionPool withSession { 
     implicit session => 
      try { 
      val resId = PersonsIdReturning += person 
      val addedPerson = person.copy(id = Some(resId.asInstanceOf[Int])) 
      localCtx.complete(addedPerson) 
      publishAll(CreatePublishMessage(TableName, localCtx.request.uri + "/" + addedPerson.id.get, addedPerson)) 
      L.debug(s"Person create success") 
      } catch { 
      case e: Exception => 
       L.error(s"Ups cannot create person: ${e.getMessage}", e) 
       localCtx.complete(e) 
      } 
     } 
    } 

ci sono ancora due cose importanti mancanti: OAuth2 e spingere notificazione a utente/connessione specifici tramite websocket