Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

airframe-http: Allow more flexible http path routing #418

Merged
merged 2 commits into from Mar 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 10 additions & 9 deletions airframe-http/src/main/scala/wvlet/airframe/http/Router.scala
Expand Up @@ -31,11 +31,19 @@ class Router(val routes: Seq[Route]) {
routes
.find { r =>
r.method == request.method &&
r.pathComponents.length == request.pathComponents.length &&
request.path.startsWith(r.pathPrefix)
checkPath(request.pathComponents, r.pathComponents)
}
}

private def checkPath(requestPathComponents: Seq[String], routePathComponents: Seq[String]): Boolean = {
if (requestPathComponents.length == routePathComponents.length) {
requestPathComponents.zip(routePathComponents).forall {
case (requestPathComponent, routePathComponent) =>
routePathComponent.startsWith(":") || routePathComponent == requestPathComponent
}
} else false
}

/**
* Add methods annotated with @Endpoint to the routing table
*/
Expand Down Expand Up @@ -83,13 +91,6 @@ case class Route(controllerSurface: Surface, method: HttpMethod, path: String, m
.toIndexedSeq
}

lazy val pathPrefix: String = {
"/" +
pathComponents
.takeWhile(!_.startsWith(":"))
.mkString("/")
}

def returnTypeSurface: Surface = methodSurface.returnType

/**
Expand Down
Expand Up @@ -20,6 +20,7 @@ import wvlet.log.LogSupport
object ControllerExample {
case class User(id: String, name: String)
case class CreateUserRequest(name: String)
case class Group(name: String, users: Seq[User])
}

/**
Expand Down Expand Up @@ -54,6 +55,28 @@ trait ControllerExample extends LogSupport {
info(s"id: ${id}, ${httpRequest.contentString}")
httpRequest.contentString
}

@Endpoint(path = "/:group/users", method = HttpMethod.GET)
def groupUsers(group: String): Group = {
val g = Group(group, Seq(User("10", "leo")))
info(s"get ${g}")
g
}

@Endpoint(path = "/:group/user/:id", method = HttpMethod.GET)
def groupUser(group: String, id: String): Group = {
val g = Group(group, Seq(User(id, "leo")))
info(s"get ${g}")
g
}

@Endpoint(path = "/conflict/users", method = HttpMethod.GET)
def conflictPath(): Group = {
val g = Group("xxx", Seq(User("10", "leo")))
info(s"get ${g}")
g
}

}

trait InvalidService {
Expand Down
30 changes: 30 additions & 0 deletions airframe-http/src/test/scala/wvlet/airframe/http/RouterTest.scala
Expand Up @@ -122,6 +122,36 @@ class RouterTest extends AirframeSpec {

ret.get.asInstanceOf[ControllerExample.User].name shouldBe "aina"
}

{
val req = SimpleHttpRequest(HttpMethod.GET, "/scala/users")
val ret =
router
.findRoute(req)
.flatMap(_.call(serviceProvider, req))

ret.get shouldBe ControllerExample.Group("scala", Seq(ControllerExample.User("10", "leo")))
}

{
val req = SimpleHttpRequest(HttpMethod.GET, "/scala/user/11")
val ret =
router
.findRoute(req)
.flatMap(_.call(serviceProvider, req))

ret.get shouldBe ControllerExample.Group("scala", Seq(ControllerExample.User("11", "leo")))
}

{
val req = SimpleHttpRequest(HttpMethod.GET, "/conflict/users")
val ret =
router
.findRoute(req)
.flatMap(_.call(serviceProvider, req))

ret.get shouldBe ControllerExample.Group("xxx", Seq(ControllerExample.User("10", "leo")))
}
}
}
}