0

I have following code in Spray to parse the REST service called by user:

val route = {
  pathPrefix("v0") {
    pathPrefix("pets") {
      pathEndOrSingleSlash {
        pathEnd {
          get {
            complete("/v0/pets")
          }
        } ~
        get {
          complete("/v0/pets/")
        }
      } ~
      parameters('id ?) {
        id =>
          get {
            complete("/v0/pets?id=" + id)
          }
      }
    }
  }
}

The problem is that it is not behaving as expected. I am expecting following behaviour from the code:

http://127.0.0.1/v0/pets => /v0/pets
http://127.0.0.1/v0/pets/ => /v0/pets/
http://127.0.0.1/v0/pets?id=1234 = > /v0/pets?id=Some(1234)

But, I am getting following results for the queries:

http://127.0.0.1/v0/pets => /v0/pets
http://127.0.0.1/v0/pets/ => /v0/pets
http://127.0.0.1/v0/pets?id=1234 => /v0/pets
Ende Neu
  • 15,581
  • 5
  • 57
  • 68
Chuchu
  • 33
  • 7

2 Answers2

2

One of the issue here is that since id is declared as optional your parameter route handles both the presence and the absence of it (and that is handling v0/pets).

One way of doing it (and I also assume you only want to handle get requests).

You basically just declare id not optional on your parameter route:

val route = get {
  pathPrefix("v0") {
    pathPrefix("pets") {
      pathEnd {
        parameter('id) { id =>
          complete("/v0/pets?id=" + id)
        } ~ complete("/v0/pets")
      } ~
      pathSingleSlash {
        complete("/v0/pets/")
      }
    }
  }
}

Another way basically just exploits the fact that id is an optional parameter, so you just pattern match on the Option:

val route = {
  pathPrefix("v0") {
    pathPrefix("pets") {
      pathEnd {
        get {
          parameters('id ?) { id =>
            id match {
              case Some(id) => complete("/v0/pets?id=" + id)
              case None => complete("/v0/pets")
            }
          }
        }
      } ~
      pathSingleSlash {
        get {
          complete("/v0/pets/")
        }
      }
    }
  }
}
mfirry
  • 3,634
  • 1
  • 26
  • 36
1
pathPrefix("v0") {
  pathPrefix("pets") {
    pathEndOrSingleSlash {
      get {
      }
    }
  }
}

matches http://127.0.0.1/v0/pets?id=1234.

This is why

GET /v0/pets?id=1234
 ^   ^   ^  ^
 |___|___|__|____ get  
     |   |  |
     |   |  |
     |   |  |__ pathEndOrSlash
     |   |  
     |   |__ pathPrefix("pets")
     |
     |__ pathPrefix("v0")

You need to intercept the parameter before. Try

val route = {
  pathPrefix("v0") {
    pathPrefix("pets") {
      parameters('id ?) {
        id =>
          get {
            complete("/v0/pets?id=" + id)
          }
      } ~
      pathEndOrSingleSlash {
        pathEnd {
          get {
            complete("/v0/pets")
          }
        } ~
        get {
          complete("/v0/pets/")
        }
      }
    }
  }
}
Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
  • Thanks @gabriele-petronella for your reply. But with your suggested solution, the last two paths are never executed. Both of them simply get executed by the first path only and print output as /v0/pets/?id=None – Chuchu Jan 07 '16 at 15:28
  • oh yes, my bad, the optionality of `id` makes it enter the first path anyway. mfirry's solution is the way to go. – Gabriele Petronella Jan 07 '16 at 15:29