2014-05-15 7 views
9

Spray.io를 사용하여 RESTful API를 개발할 때 응용 프로그램을 어떻게 구성해야합니까?Spray.io를 사용하여 RESTful API를 구조화하는 방법은 무엇입니까?

스프레이 응용 프로그램을 분할하는 방법은 이미 this answer으로 보았지만 "요청 당 한 액터"접근 방식을 사용하지 않는 것 같아서 만족스럽지 않습니다. 루트 액터의 요청을 경로를 기반으로하는 애플리케이션의 다른 액터로 전달할 수 있습니까? 이러한 액터에서 관련 경로를 정의 할 수 있습니까?

감사합니다.

답변

8

경로 나 기타 다른 것을 기반으로 한 액터의 요청을 다른 액터로 확실히 전달할 수 있습니다. 각 서비스를 처리 할 다른 배우에 대한 모든 요청 라우팅을받는 주요 배우에서

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

Relavent 코드 : (예를 들어 프로젝트의 포크 포크 인) 내 예제 프로젝트를 확인

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

그리고 예를 들어 영화의 경로에 대한 는 :

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

여기 예제를보고 있었고 CDI를 사용하는 것으로 나타났습니다. 왜 당신이 그것을 사용하기로 결정한 특별한 이유? – EdMelo

+0

CDI는 의존성 주입을 의미합니까? – Gangstead

+0

예./* Stackoverflow가 더 많은 문자를 필요로하므로 ... */ – EdMelo

0

나는 첫 번째 전체 REST 프로젝트를 만들기로 많은 어려움을 겪고 있었다. 내가 찾은 사례는 전 세계의 안녕하세요 ... 블로그를 거의 읽지 않고 의견이 거의 없으며 예제 프로젝트를 만들기로 결정했습니다. 그것은 스칼라/akka/스프레이/MySQL을 기반으로

이 데이터 당신은 여기 https://github.com/vixxx123/scalasprayslickexample

에 그것을 확인할 수 등이 변경되었음을 클라이언트에게 알리는 웹 소켓 전체 작업 예제는이 프로젝트에서 라우팅의 샘플 코드는 :

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

그리고 배우 핸들러를 작성의 샘플 :

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

이없는 두 가지 중요한 것들이 여전히 : OAuth2를가하고 notifica를 밀어 특정 사용자/웹 연결을 통한 연결