0

here are three routes I am trying to match

/games/2016/1
/games/2016
/games

and I'm trying to do so with this routing structure:

pathPrefix("games") {
  logger.info("INSIDE GAMES PATH KEY ")
  path(PathEnd) {
    complete("no numbers")
  } ~ path(IntNumber / IntNumber) { case (year: Int, week: Int) =>
    logger.info("Matched week/year")
    //gets games for this year and week
    complete("two numbers")
  } ~ path(IntNumber) { year: Int =>
    logger.info("Matched year")
    complete("one number")
  }
}

This works for the first two examples I have, but does not work for the last. What am I doing wrong, and how I can fix it so my route matches /games

I've tried switching PathEnd to PathNetural, RemainingPath etc to no avail.

EDIT: The test case I am using:

  it must "return all games for this week" in {
    Get("/games") ~>
      NflRoutes.gamesRoutes ~> check {
      val games: Seq[NflGame] = responseAs[Seq[NflGame]]
      games.size must be (14)
    }
  }

and the error with logs:

> test-only *NflRoutesTest*
[info] Compiling 1 Scala source to /home/chris/dev/suredbits-api/target/scala-2.11/classes...
[info] Compiling 1 Scala source to /home/chris/dev/suredbits-api/target/scala-2.11/test-classes...
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/home/chris/dev/suredbits-api/lib/nfldb-api-assembly-0.0.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/chris/.ivy2/cache/ch.qos.logback/logback-classic/jars/logback-classic-1.0.13.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
13:09:39.721 TKD [com-suredbits-api-routes-NflRoutesTest-akka.actor.default-dispatcher-3] INFO  akka.event.slf4j.Slf4jLogger - Slf4jLogger started
13:09:39.907 TKD [suredbits-api-akka.actor.default-dispatcher-4] INFO  akka.event.slf4j.Slf4jLogger - Slf4jLogger started
13:09:40.012 TKD [pool-9-thread-6-ScalaTest-running-NflRoutesTest] INFO  c.suredbits.api.routes.NflRoutes$ - INSIDE GAMES PATH KEY 
[info] NflRoutesTest:
[info] - must return all games for this week *** FAILED ***
[info]   Request was rejected (DynamicVariable.scala:58)
[info] ScalaTest
[info] Run completed in 934 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
[info] *** 1 TEST FAILED ***
[error] Failed: Total 1, Failed 1, Errors 0, Passed 0
[error] Failed tests:
[error]     com.suredbits.api.routes.NflRoutesTest
[error] (test:testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 4 s, completed Oct 10, 2016 1:09:40 PM
> 
Chris Stewart
  • 1,641
  • 2
  • 28
  • 60

1 Answers1

2

Try matching against pathEnd first. Based on the documentation I added some basic logic in place of your ???:

val fooRoute = pathPrefix("games") {
  pathEnd { complete ("empty path") } ~
  path(IntNumber / IntNumber) {case (a : Int, b : Int) => complete(s"a = $a b = $b")} ~
  path(IntNumber) { case a : Int => complete(s"a = $a")}
}

This route can be tested with the following code which passes:

Get("/games") ~> fooRoute ~> check {
  responseAs[String] equalsIgnoreCase "empty path"
}

Get("/games/2016") ~> fooRoute ~> check {
  responseAs[String] equalsIgnoreCase "a = 2016"
}

Get("/games/2016/1") ~> fooRoute ~> check {
  responseAs[String] equalsIgnoreCase "a = 2016 b = 1"
}
Ramón J Romero y Vigil
  • 17,373
  • 7
  • 77
  • 125
  • @ChrisStewart I've added some functionality and unit tests which pass. Can you elaborate on "did not work"? – Ramón J Romero y Vigil Oct 10 '16 at 17:50
  • I've editted the OP to be more realistic, note that the log message `"INSIDE GAMES PATH KEY "` is hit when I test my path. – Chris Stewart Oct 10 '16 at 18:10
  • @ChrisStewart Change `path(PathEnd) {...` to the directive `pathEnd {...`. There's a note in the docs: The empty string (also called empty word or identity) is a neutral element of string concatenation operation, so it will match everything, but remember that path requires whole remaining path being matched – Ramón J Romero y Vigil Oct 10 '16 at 18:13
  • You can also create an actual tree, by using `pathPrefix(IntNumber) { a => pathEnd { /* your last case */ } ~ path(IntNumber) { b => /* your second case */ } }` – jrudolph Oct 11 '16 at 13:58