0

An endpoint should echo a part of the request path. There are two variants of the request:

<host>/xyz-<token>/
<host>/xyz-<token>.txt

The token part is what I would like to extract. However, I am only able to match the second variant and not the first. The request is being rejected with a 'The requested resource could not be found'The slash seems to prevent the matching. When I remove the slash from the first variant, it matches, when I append a slash to the second one, it stops matching. I have tried several variants, the simplest reproducible being:

val tokenRoute: Route = pathSuffix(s"xyz-(.+)".r) { token: String => pathEndOrSingleSlash { complete(token.split('.').head) } }

Adding or removing a slash to the end of the regex seems to have no effect. Removing the pathEndOrSingleSlash directive neither.

What am I misunderstanding here?

EDIT:

I have been oversimplifying - the matched path should also include

<host>/<prefix>/xyz-<token>/
<host>/<prefix>/xyz-<token>.txt

which pathPrefix does not handle - requests including the prefix, e.g <host>/abc/xyz-<token>/ are rejected with 'The requested resource could not be found'.

I want to simply ignore the prefix, just capture the token incoming to any path.

kostja
  • 60,521
  • 48
  • 179
  • 224
  • Is the prefix always only one path element after the host or could there be multiple/variable levels of prefix depth before getting to the part with the tokens? – cmbaxter Feb 03 '16 at 14:45
  • @cmbaxter 0 to 1 element in all existing requests. I assume it would complicate things a good bit to make it glob any path independent of levels? – kostja Feb 03 '16 at 14:53

1 Answers1

2

I think what you meant to use was pathPrefix instead of pathSuffix. If you change your route to look like the following code, I believe things will start working for you:

pathPrefix(s"xyz-(.+)".r) { token: String =>
  pathEndOrSingleSlash {
    complete(token.split('.').head)
  }
}

EDIT

My original answer won't handle the case mentioned in the OP's edit. If there can be variability in the leading path elements that need to be matched on then it is best to start working from the back end of the path instead of the front, leading back to using pathSuffix. Here is how suffix based matching can be used including some test scenarios to show what kinds of paths are handled properly:

  val route:Route =
    pathSuffix(Slash.?){
      pathSuffix(s"xyz-(.+)".r) { token: String =>          
        complete(token.split('.').head)         
      }
    }

  "A request to my route" should{
    "handle the route ending with a dot extension and no trailing slash" in {
      Get("/xyz-foo.txt") ~> route ~> check{
        handled ==== true
        responseAs[String] ==== "foo"
      }      
    }    
    "handle the route with no dot extension and having a trailing slash" in {
      Get("/xyz-foo/") ~> route ~> check{
        handled ==== true
        responseAs[String] ==== "foo"
      }      
    }
    "handle a number of prefix elements in the path and end in a single slash" in {
      Get("/hello/world/xyz-foo/") ~> route ~> check{
        handled ==== true
        responseAs[String] ==== "foo"
      }      
    }
    "handle a number of prefix elements in the path and end with a dot extension" in {
      Get("/hello/world/xyz-foo.txt") ~> route ~> check{
        handled ==== true
        responseAs[String] ==== "foo"
      }      
    }    
  }
cmbaxter
  • 35,283
  • 4
  • 86
  • 95
  • + 1 thanks, the both paths do match with `pathPrefix`. I oversimplified the path unfortunately for the question and also have to match an optional arbitrary prefix between the host and the token: `//xyz-/`. Do you have an idea how to match that? What bothers me as well is that I dont get 'why' the `pathSuffix' cannot be adjusted for my needs. – kostja Feb 03 '16 at 12:03
  • @kostja, can you include in your update what you want to do with that prefix and how pathPrefix is not handling it. – cmbaxter Feb 03 '16 at 13:49