有人能提供一些关于如何在喷涂中构建路由的好指示吗? 我的路线非常冗长,甚至IDEA在编辑包含路由的文件时变得非常慢(自动完成时间为5-10秒)....
pathPrefix("customers") {
pathEnd {
get {
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized)) {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
complete {
m.getCustomers
}
}
}
}
}
} ~
path(IntNumber) { id =>
post {
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized)) {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
entity(as[Customer]) { c =>
complete {
m.updateCustomer(c).map {
case 0 => StatusCodes.UnprocessableEntity
case 1 => StatusCodes.Accepted
case _ => StatusCodes.InternalServerError
}.handleSuccessWith { case _ =>
siblingWorkers ! Push("customers", None)
}
}
}
}
}
}
} ~
delete {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
complete {
m.deleteCustomer(id).map {
case 0 => StatusCodes.UnprocessableEntity
case 1 => StatusCodes.Accepted
case _ => StatusCodes.InternalServerError
}.handleSuccessWith { case _ =>
siblingWorkers ! Push("customers", None)
}
}
}
}
}
} ~
path("new") {
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized)) {
post {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
entity(as[Customer]) { c =>
complete {
m.insertCustomer(c).handleSuccessWith { case _ =>
siblingWorkers ! Push("customers", None)
}
}
}
}
}
}
}
}
} ~
pathPrefix("groups") {
pathEnd {
get {
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized)) {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
complete {
m.getGroups
}
}
}
}
}
} ~
pathPrefix(IntNumber) { groupId =>
pathEnd {
complete {
m.getGroupById(groupId)
}
} ~
path("users") {
complete {
m.getGroupById(groupId).flatMap { groupO =>
groupO.map { group =>
m.getUsers(group)
}.getOrElse(Future.successful(Seq()))
}
}
}
} ~
pathPrefix(Segment) { groupName =>
pathEnd {
complete {
m.getGroupByName(groupName)
}
} ~
path("users") {
complete {
m.getGroupByName(groupName).flatMap { groupO =>
groupO.map { group =>
m.getUsers(group)
}.getOrElse(Future.successful(Seq()))
}
}
}
}
} ~
pathPrefix("users") {
path("me") {
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized)) {
withSessionKey[String]("userId") { uid =>
complete {
m.getUserById(uid.toInt).map(_.get)
}
}
}
} ~
path("new") {
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized orElse RejectionHandler.Default)) {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
entity(as[NewUser]) { r =>
complete {
m.addUser(r).handleCompletionWith{ _ => siblingWorkers ! Push("users", None)}
}
}
}
}
}
} ~
pathPrefix(IntNumber) { uid =>
pathEnd {
get {
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized orElse RejectionHandler.Default)) {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
complete {
m.getUserById(uid)
}
}
}
}
} ~
post {
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized orElse RejectionHandler.Default)) {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
entity(as[User]) { u =>
complete {
m.updateUser(u).map {
case 0 => StatusCodes.UnprocessableEntity
case 1 => StatusCodes.Accepted
case _ => StatusCodes.InternalServerError
}.handleCompletionWith { _ => siblingWorkers ! Push("users", None) }
}
}
}
}
}
} ~
delete {
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized orElse RejectionHandler.Default)) {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
complete {
m.deleteUserById(uid).map {
case 0 => StatusCodes.UnprocessableEntity
case 1 => StatusCodes.Accepted
case _ => StatusCodes.InternalServerError
}.handleCompletionWith{ _ => siblingWorkers ! Push("groups", None)}
}
}
}
}
}
} ~
pathPrefix("groups") {
path("new") {
entity(as[NewUserGroup]) { g =>
complete {
m.addUserGroup(UserGroup(uid, g.id)).map {
case 0 => StatusCodes.UnprocessableEntity
case 1 => StatusCodes.Accepted
case _ => StatusCodes.InternalServerError
}.handleCompletionWith{ _ => siblingWorkers ! Push("groups", None)}
}
}
} ~
pathEnd {
get {
complete {
m.getUserGroups(uid)
}
} ~
post {
entity(as[Seq[Int]]) { groups =>
complete {
m.setUserGroups(uid, groups).map {
case Some(x) if x < groups.length => StatusCodes.UnprocessableEntity
case Some(x) if x == groups.length => StatusCodes.OK
case _ => StatusCodes.InternalServerError
}.handleCompletionWith{ _ => siblingWorkers ! Push("users", None)}
}
}
}
}
}
} ~
pathEnd {
get {
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized)) {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
complete {
m.getUsers
}
}
}
}
}
}
答案 0 :(得分:1)
您可以将路由拆分为多个路由。在您的情况下:客户,组,用户可能被提取到相应的路线。
class CustomersRoute extends ... {
def route: Route = pathPrefix("customers") {
...
}
}
然后你把它们结合起来:
val routes = pathPrefix("v1") {
customers.route ~
groups.route ~
users.route
}
答案 1 :(得分:1)
您可以将资源拆分为单独的特征,例如UserRoutes.scala
,ContentRoutes.scala
,AdminRoutes.scala
,并将它们全部扩展为HttpService
。您现在可以拥有一个新类,它构成所有路由的组合,并扩展HttpServiceActor
复合类可以使用~
运算符链接您的分割路由。例如。 val routes = userRoutes.routes ~ adminRoutes.routes ~ contentRoutes.routes
。它还为您提供了一个注入依赖项的好地方。
答案 2 :(得分:1)
除了其他人已经提到的内容之外,我还利用了编写指令和创建自定义指令的功能,以减少重复代码并使路由结构更具可读性。
代码中经常重复的一件事是:
handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized orElse RejectionHandler.Default)) {
withSessionKey[String]("groups") { g =>
validate(g.contains("admin"), "Not authorized") {
…
}
}
}
您可以考虑将其分解为自定义指令。像这样(未经测试):
def handleSessionKeyValidation(key: String, requiredValue: String) = {
val rejectionHandlers = handleRejections(RejectionHandler.apply(handleMissingAuthSessionKey orElse handleValidationErrorAsUnauthorized))
val sessionKeyDir = withSessionKey[String](key)
(rejectionHandlers & sessionKeyDir).flatMap[HNil](value =>
if (value.contains(requiredValue)) pass
else reject(AuthorizationFailedRejection)
)
}
现在,开始组合您的HTTP方法和路径指令,并使用自定义指令,路线的第一部分可能看起来更像这样:
(get & path("customers") & pathEnd) {
handleSessionKeyValidation("groups", "admin"){
complete{
m.getCustomers
}
}
} ~
(post & path("customers" / IntNumber)) { id =>
handleSessionKeyValidation("groups", "admin"){
entity(as[Customer]) { c =>
complete {
m.updateCustomer(c).map {
case 0 => StatusCodes.UnprocessableEntity
case 1 => StatusCodes.Accepted
case _ => StatusCodes.InternalServerError
}.handleSuccessWith { case _ =>
siblingWorkers ! Push("customers", None)
}
}
}
}
} ~
(delete & path("customers" / IntNumber)) { id =>
handleSessionKeyValidation("groups", "admin") {
complete {
m.deleteCustomer(id).map {
case 0 => StatusCodes.UnprocessableEntity
case 1 => StatusCodes.Accepted
case _ => StatusCodes.InternalServerError
}.handleSuccessWith { case _ =>
siblingWorkers ! Push("customers", None)
}
}
}
} ~
(post & path("customers" / "new")) {
handleSessionKeyValidation("groups", "admin"){
entity(as[Customer]) { c =>
complete {
m.insertCustomer(c).handleSuccessWith { case _ =>
siblingWorkers ! Push("customers", None)
}
}
}
}
}
即使在上面的示例中,handleSessionKeyValidation指令的使用也有些重复。我们可以通过增加handleSessionKeyValidation的范围并包装更大部分的路径来减少重复。这样的事情。
pathPrefixTest("customers"){
handleSessionKeyValidation("groups", "admin") {
(get & path("customers") & pathEnd) {
complete{
m.getCustomers
}
} ~
(post & path("customers" / IntNumber)) { id =>
entity(as[Customer]) { c =>
complete {
m.updateCustomer(c).map {
case 0 => StatusCodes.UnprocessableEntity
case 1 => StatusCodes.Accepted
case _ => StatusCodes.InternalServerError
}.handleSuccessWith { case _ =>
siblingWorkers ! Push("customers", None)
}
}
}
} ~
(delete & path("customers" / IntNumber)) { id =>
complete {
m.deleteCustomer(id).map {
case 0 => StatusCodes.UnprocessableEntity
case 1 => StatusCodes.Accepted
case _ => StatusCodes.InternalServerError
}.handleSuccessWith { case _ =>
siblingWorkers ! Push("customers", None)
}
}
} ~
(post & path("customers" / "new")) {
entity(as[Customer]) { c =>
complete {
m.insertCustomer(c).handleSuccessWith { case _ =>
siblingWorkers ! Push("customers", None)
}
}
}
}
}
} ~