Can Spray.io routes be split into multiple “Controllers”?

前端 未结 3 753
-上瘾入骨i
-上瘾入骨i 2020-12-23 17:56

I haven\'t found a solid example or structure to splitting up Spray.io routes into multiple files. I am finding that the current structure of my routes are going to become v

相关标签:
3条回答
  • 2020-12-23 18:15

    I personally use this for large APIs:

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

    I would recommend putting the most common routes first, and use pathPrefix as soon as you can in the sub-routes, so that you reduce the number of tests that Spray runs for each incoming request.

    You'll find below a route that I believe is optimized:

      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 讨论(0)
  • 2020-12-23 18:18

    You can combine routes from different "Controllers" using ~ combinator.

    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 讨论(0)
  • 2020-12-23 18:36

    I tried this way from the above code snippet, basic format and works.

    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)
    
    }
    
    0 讨论(0)
提交回复
热议问题