scala - por - farmacopea argentina 7 edicion volumen 1
¿Se pueden dividir las rutas de Spray.io en múltiples "Controladores"? (3)
No he encontrado un ejemplo o estructura sólida para dividir las rutas de Spray.io en varios archivos. Estoy descubriendo que la estructura actual de mis rutas se va a volver muy engorrosa, y sería bueno abstraerlas en diferentes "Controladores" para una aplicación API REST muy simple.
Los documentos no parecen ayudar demasiado: http://spray.io/documentation/spray-routing/key-concepts/directives/#directives
Esto es lo que tengo hasta ahora:
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))
}
}
}
}
Gracias por ayudar en esto!
Intenté de esta manera desde el fragmento de código anterior, el formato básico y las obras.
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)
}
Puede combinar rutas de diferentes "Controladores" usando ~ 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)
}
}
}
}
Yo personalmente uso esto para grandes 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
}
}
Recomendaría poner primero las rutas más comunes y usar pathPrefix
tan pronto como pueda en las pathPrefix
, para reducir la cantidad de pruebas que Spray ejecuta para cada solicitud entrante.
A continuación encontrará una ruta que creo que está optimizada:
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) }
}
}
}
}
}