Akka HTTP api 路由结构
Akka HTTP api routes structure
我正在编写基于 Akka-HTTP 的 REST API。由于我是 Akka 和 Scala 的新手,我不确定在我的项目中组织代码的最佳方式是什么。我将有大约。具有基本 CRUD 的 7 个不同实体。这意味着我将在 API 中拥有超过 25 条路线。我想根据它们在逻辑上关联的实体对路由进行分组。实现这一目标的好方法是什么?目前,我从 GitHub 上可用的一些项目中获得灵感,并将这些路线分组为特征。我有一个主要特征,其中包括一些通用的东西,扩展指令并添加封送处理:
trait Resource extends Directives with JsonSupport{
...
}
然后我组织了其他路线,如下所示。
trait UserResource extends Resource{
def userRoutes:Route =
pathPrefix("authenticate") {
pathEndOrSingleSlash {
post {
entity(as[LoginRequest]) { request =>
...
}
}
}
}
} ~
pathPrefix("subscribe") {
pathEndOrSingleSlash {
post {
entity(as[UserSubscribeRequest]) { request =>
...
}
}
}
}
}
}
有一个 class 定义异常处理程序,实例化一些帮助程序并将路由放在一起:
class Routes extends UserResource with OtherResource with SomeOtherResource{
... handlers definitions ...
... helpers ...
def allRoutesUnified: Route =
handleErrors {
cors() {
pathPrefix("api") {
authenticateOAuth2("api", PasswordAuthenticator) { _ =>
//Routes defined in other traits
otherRoutes ~ someOtherRoutes
}
} ~ userRoutes
}
}
}
终于在应用入口点:
object Main extends App{
... usual Akka stuff ..
val routes = new Routes ()
val router = routes.allRoutesUnified
Http().bindAndHandle(router, "localhost", 8080)
}
有什么更好或更优雅的路线组织方式?
问题中的编码组织和结构更类似于面向对象的编程,而不是函数式编程。功能是否优于 OO 不在 Whosebug 的范围内,但大概我们选择 scala 而不是 java 是有原因的。
此外,在特定示例中,即使您走 OO 路线,似乎也没有太大的继承需求。继承实现的唯一目的是避免单个导入语句。
职能组织
一种更实用的方法是在对象内部指定更简单的路由,而不是 classes。此外,您正在创建的 Route
值不需要用 def
实例化,因为您可以为不同的目的一遍又一遍地重复使用相同的路由:
import akka.http.scaladsl.server.Directives._
//an object, not a class
object UserResource {
//Note: val not def
val userRoutes : Route = {
//same as in question
}
}
使用对象仍然允许您在一个统一的结构下将相似的路由组合在一起,但无需为了访问路由而实例化 class 对象。
同样,您对 allRoutesUnified
的定义应该是一个接受 "inner logic" 作为参数的高阶函数。这将有助于更好地组织代码并使单元测试更容易:
object Routes {
import UserResources.userRoutes
def allRoutesUnified(innerRoute : Directive0 = userRoutes) : Route =
handleErrors {
cors() {
pathPrefix {
authenticateOAuth2("api", PasswordAuthenticator) { _ =>
innerRoute
}
}
}
}
}
现在此功能可用于 userRoutes
以外的路由。
最后,可以通过使用 new
:
以类似于问题的方式访问统一的高阶函数,但无需创建 Routes
对象
object Main extends App {
//no need to create a routes objects, i.e. no "new Routes()"
Http().bindAndHandle(
Routes.allRoutesUnified(),
"localhost",
8080
)
}
我正在编写基于 Akka-HTTP 的 REST API。由于我是 Akka 和 Scala 的新手,我不确定在我的项目中组织代码的最佳方式是什么。我将有大约。具有基本 CRUD 的 7 个不同实体。这意味着我将在 API 中拥有超过 25 条路线。我想根据它们在逻辑上关联的实体对路由进行分组。实现这一目标的好方法是什么?目前,我从 GitHub 上可用的一些项目中获得灵感,并将这些路线分组为特征。我有一个主要特征,其中包括一些通用的东西,扩展指令并添加封送处理:
trait Resource extends Directives with JsonSupport{
...
}
然后我组织了其他路线,如下所示。
trait UserResource extends Resource{
def userRoutes:Route =
pathPrefix("authenticate") {
pathEndOrSingleSlash {
post {
entity(as[LoginRequest]) { request =>
...
}
}
}
}
} ~
pathPrefix("subscribe") {
pathEndOrSingleSlash {
post {
entity(as[UserSubscribeRequest]) { request =>
...
}
}
}
}
}
}
有一个 class 定义异常处理程序,实例化一些帮助程序并将路由放在一起:
class Routes extends UserResource with OtherResource with SomeOtherResource{
... handlers definitions ...
... helpers ...
def allRoutesUnified: Route =
handleErrors {
cors() {
pathPrefix("api") {
authenticateOAuth2("api", PasswordAuthenticator) { _ =>
//Routes defined in other traits
otherRoutes ~ someOtherRoutes
}
} ~ userRoutes
}
}
}
终于在应用入口点:
object Main extends App{
... usual Akka stuff ..
val routes = new Routes ()
val router = routes.allRoutesUnified
Http().bindAndHandle(router, "localhost", 8080)
}
有什么更好或更优雅的路线组织方式?
问题中的编码组织和结构更类似于面向对象的编程,而不是函数式编程。功能是否优于 OO 不在 Whosebug 的范围内,但大概我们选择 scala 而不是 java 是有原因的。
此外,在特定示例中,即使您走 OO 路线,似乎也没有太大的继承需求。继承实现的唯一目的是避免单个导入语句。
职能组织
一种更实用的方法是在对象内部指定更简单的路由,而不是 classes。此外,您正在创建的 Route
值不需要用 def
实例化,因为您可以为不同的目的一遍又一遍地重复使用相同的路由:
import akka.http.scaladsl.server.Directives._
//an object, not a class
object UserResource {
//Note: val not def
val userRoutes : Route = {
//same as in question
}
}
使用对象仍然允许您在一个统一的结构下将相似的路由组合在一起,但无需为了访问路由而实例化 class 对象。
同样,您对 allRoutesUnified
的定义应该是一个接受 "inner logic" 作为参数的高阶函数。这将有助于更好地组织代码并使单元测试更容易:
object Routes {
import UserResources.userRoutes
def allRoutesUnified(innerRoute : Directive0 = userRoutes) : Route =
handleErrors {
cors() {
pathPrefix {
authenticateOAuth2("api", PasswordAuthenticator) { _ =>
innerRoute
}
}
}
}
}
现在此功能可用于 userRoutes
以外的路由。
最后,可以通过使用 new
:
Routes
对象
object Main extends App {
//no need to create a routes objects, i.e. no "new Routes()"
Http().bindAndHandle(
Routes.allRoutesUnified(),
"localhost",
8080
)
}