2013-02-01 11 views
18

Spray.ioルートを複数のファイルに分割するための実例や構造が見つかりませんでした。私のルートの現在の構造は非常に面倒なものになり、非常に単純なREST APIアプリケーションのためにそれらを異なる「コントローラ」に抽象化するとよいでしょう。Spray.ioルートを複数の「コントローラ」に分割できますか?

ドキュメントはあまり助けていないように見えます:http://spray.io/documentation/spray-routing/key-concepts/directives/#directives

は、ここで私がこれまで持っているものです。この上のヘルプのための

class AccountServiceActor extends Actor with AccountService { 

    def actorRefFactory = context 

    def receive = handleTimeouts orElse runRoute(demoRoute) 

    def handleTimeouts: Receive = { 
    case Timeout(x: HttpRequest) => 
     sender ! HttpResponse(StatusCodes.InternalServerError, "Request timed out.") 
    } 
} 


// this trait defines our service behavior independently from the service actor 
trait AccountService extends HttpService { 

    val demoRoute = { 
    get { 
     path("") { 
     respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here 
      complete(index) 
     } 
     } ~ 
     path("ping") { 
     complete("PONG!") 
     } ~ 
     path("timeout") { ctx => 
     // we simply let the request drop to provoke a timeout 
     } ~ 
     path("crash") { ctx => 
     throw new RuntimeException("crash boom bang") 
     } ~ 
     path("fail") { 
     failWith(new RuntimeException("aaaahhh")) 
     } ~ 
     path("riaktestsetup") { 
     Test.setupTestData 
     complete("SETUP!") 
     } ~ 
     path("riaktestfetch"/Rest) { id => 
     complete(Test.read(id)) 
     } 
    } 
    } 
} 

ありがとう!

答えて

14

〜コンビネータを使用して、異なる「コントローラ」のルートを組み合わせることができます。

class AccountServiceActor extends Actor with HttpService { 

    def actorRefFactory = context 

    def receive = handleTimeouts orElse runRoute(
    new AccountService1.accountService1 ~ new AccountService2.accountService2) 

    def handleTimeouts: Receive = { 
    case Timeout(x: HttpRequest) => 
     sender ! HttpResponse(StatusCodes.InternalServerError, "Request timed out.") 
    } 
} 



class AccountService1 extends HttpService { 

    val accountService1 = { 
    get { 
     path("") { 
     respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here 
      complete(index) 
     } 
     } 
    } 
} 


class AccountService2 extends HttpService { 

    val accountService2 = { 
    get { 
     path("someotherpath") { 
     respondWithMediaType(`text/html`) { // XML is marshalled to `text/xml` by default, so we simply override here 
      complete(index) 
     } 
     } 
    } 
} 
+0

そのように見えます。手動でservice1〜service2〜service3を書くのではなく、自動的に組み合わせることができる何らかの暗黙的な記述を作成できるのだろうかと思います。ありがとう! – crockpotveggies

+0

ある種の継承問題が生じるように見えるので、Hmmmは選択を解除しました。 'type引数[com.threetierlogic.AccountServ ice.AccountServiceActor]がメソッド適用の型パラメータの境界に一致しない [T <:akka.actor.Actor]' – crockpotveggies

+0

'caseクラスBase(actorRefFactory:ActorRefFactory) 'HttpResponseをGETリクエストのためのレスポンス(部分)として '/ 'にディスパッチできません。現在のレスポンス状態は 'Completed'ですが、 'Uncompleted'でなければなりません。 – crockpotveggies

33

私は個人的に大規模なAPIのためにこれを使用します。

class ApiActor extends Actor with Api { 
    override val actorRefFactory: ActorRefFactory = context 

    def receive = runRoute(route) 
} 

/** 
* API endpoints 
* 
* Individual APIs are created in traits that are mixed here 
*/ 
trait Api extends ApiService 
    with AccountApi with SessionApi 
    with ContactsApi with GroupsApi 
    with GroupMessagesApi with OneToOneMessagesApi 
    with PresenceApi 
    with EventsApi 
    with IosApi 
    with TelephonyApi 
    with TestsApi { 
    val route = { 
    presenceApiRouting ~ 
    oneToOneMessagesApiRouting ~ 
    groupMessagesApiRouting ~ 
    eventsApiRouting ~ 
    accountApiRouting ~ 
    groupsApiRouting ~ 
    sessionApiRouting ~ 
    contactsApiRouting ~ 
    iosApiRouting ~ 
    telephonyApiRouting ~ 
    testsApiRouting 
    } 
} 

私が最初に、最も一般的なルートを置くことをお勧めします、とあなたは減らすように、サブルートにできるだけ早くすることができますようpathPrefixを使用します着信要求ごとにスプレーが実行されるテストの数。

あなたは、私が最適化されていると考えているルートの下に見つけることができます:

val groupsApiRouting = { 
    pathPrefix("v3"/"groups") { 
     pathEnd { 
     get { 
      traceName("GROUPS - Get joined groups list") { listJoinedGroups } 
     } ~ 
     post { 
      traceName("GROUPS - Create group") { createGroup } 
     } 
     } ~ 
     pathPrefix(LongNumber) { groupId => 
     pathEnd { 
      get { 
      traceName("GROUPS - Get by ID") { getGroupInformation(groupId) } 
      } ~ 
      put { 
      traceName("GROUPS - Edit by ID") { editGroup(groupId) } 
      } ~ 
      delete { 
      traceName("GROUPS - Delete by ID") { deleteGroup(groupId) } 
      } 
     } ~ 
     post { 
      path("invitations"/LongNumber) { invitedUserId => 
      traceName("GROUPS - Invite user to group") { inviteUserToGroup(groupId, invitedUserId) } 
      } ~ 
      path("invitations") { 
      traceName("GROUPS - Invite multiple users") { inviteUsersToGroup(groupId) } 
      } 
     } ~ 
     pathPrefix("members") { 
      pathEnd { 
      get { 
       traceName("GROUPS - Get group members list") { listGroupMembers(groupId) } 
      } 
      } ~ 
      path("me") { 
      post { 
       traceName("GROUPS - Join group") { joinGroup(groupId) } 
      } ~ 
      delete { 
       traceName("GROUPS - Leave group") { leaveGroup(groupId) } 
      } 
      } ~ 
      delete { 
      path(LongNumber) { removedUserId => 
       traceName("GROUPS - Remove group member") { removeGroupMember(groupId, removedUserId) } 
      } 
      } 
     } ~ 
     path("coverPhoto") { 
      get { 
      traceName("GROUPS - Request a new cover photo upload") { getGroupCoverPhotoUploadUrl(groupId) } 
      } ~ 
      put { 
      traceName("GROUPS - Confirm a cover photo upload") { confirmCoverPhotoUpload(groupId) } 
      } 
     } ~ 
     get { 
      path("attachments"/"new") { 
      traceName("GROUPS - Request attachment upload") { getGroupAttachmentUploadUrl(groupId) } 
      } 
     } 
     } 
    } 
    } 
+0

タイプは 'inviteUserToGroup'を行いますeturn? 'RequestContext => Unit'? – EdgeCaseBerg

+0

@EdgeCaseBerg 'inviteUserToGroup'のタイプが' '(Long、Long)⇒Route' :) –

+0

です。こんにちはAdrien、多分あなたはそのタイプの '連結'が正しいのか分かりますか?私はその問題で遭遇します スプレー1.3.3を使用して、予期されていない--behaviour-on-spray-can-operator-with-http-two-methods-on-the-same-pをhttp://stackoverflow.com/questions/35614708/ 。 –

1

私は上記のコードスニペット、基本フォーマットと作品からこの方法を試してみました。

import akka.actor.ActorSystem 
import akka.actor.Props 
import spray.can.Http 
import akka.io.IO 
import akka.actor.ActorRefFactory 
import spray.routing.HttpService 
import akka.actor.Actor 


/** 
* API endpoints 
* 
* Individual APIs are created in traits that are mixed here 
*/ 

trait Api extends ApiService 
with UserAccountsService 
{ 
    val route ={ 
    apiServiceRouting ~ 
    accountsServiceRouting 
    } 

} 

trait ApiService extends HttpService{ 
    val apiServiceRouting={ 
    get{ 
     path("ping") { 
     get { 
     complete { 
      <h1>pong</h1> 
     } 
     } 
     } 
    } 
    } 
} 

trait UserAccountsService extends HttpService{ 
    val accountsServiceRouting={ 
    path("getAdmin") { 
     get { 
     complete { 
      <h1>AdminUserName</h1> 
     } 
     } 
    } 
    } 
} 
class ApiActor extends Actor with Api { 
    override val actorRefFactory: ActorRefFactory = context 

    def receive = runRoute(this.route) 
} 


object MainTest extends App { 

    // we need an ActorSystem to host our application in 
    implicit val system = ActorSystem("UserInformaitonHTTPServer") 

    // the handler actor replies to incoming HttpRequests 
    val handler = system.actorOf(Props[ApiActor], name = "handler") 

    // starting the server 
    IO(Http) ! Http.Bind(handler, interface = "localhost", port = 8080) 

} 
関連する問題