6

I am using akka directives to match a particular path pattern:

/item/quantity

Examples would be

/apples/100
/bananas/200

The possible items (e.g. "apples", "bananas", ...) is not known in advance, therefore hard-coding the items using path is not an option.

However, I can't find a PathMatcher that extracts the head of the path. I'm looking for something of the form

val route = 
  get {
    path(PathHeadAsString) { item : String =>
      path(IntNumber) { qty : Int =>
        complete(s"item: $item quantity: $qty")
      } ~ complete("no quantity specified")
    } ~ complete("no item specified")
  }

Where

Get("/apples/100") ~> route ~> check {
  responseAs[String] shouldEqual "item: apples quantity: 100"
}

Is there a way to extract the first segment of the path?

The path(segment) matcher will not match if the quantity is in the path.

I obviously could use path(segments) to get a List[String] of the path elements but I would then have to extract the list head and list tail manually which seems inelegant.

Thank you in advance for your consideration and response.

Community
  • 1
  • 1
Ramón J Romero y Vigil
  • 17,373
  • 7
  • 77
  • 125

1 Answers1

19

You can compose PathMatchers with modifiers thus

path(Segment / IntNumber) { case (item, qty) =>
  complete(s"item: $item quantity: $qty")
}

OR if you need the full break-out use pathPrefix:

val route = 
pathPrefix(Segment) { item : String =>
  path(IntNumber) { qty : Int =>
    complete(s"item: $item quantity: $qty")
  } ~
  pathEnd { complete("no quantity specified") } ~
  complete("something else going on here")
} ~
complete("no item specified")

(Note the additional pathEnd directive there; even with that I wouldn't say the patterns matched represent all possible situations.)

From akka routing directives:

  • the pathPrefix directive "Applies the given PathMatcher to a prefix of the remaining unmatched path after consuming a leading slash."

  • the path directive "Applies the given PathMatcher to the remaining unmatched path after consuming a leading slash."

  • the pathEnd directive "Only passes on the request to its inner route if the request path has been matched completely."

From akka path-matchers, the Segment path matcher "Matches if the unmatched path starts with a path segment (i.e. not a slash). If so the path segment is extracted as a String instance."

Roman Kazanovskyi
  • 3,370
  • 1
  • 21
  • 22
Richard Sitze
  • 8,262
  • 3
  • 36
  • 48
  • Why you do `case (item, qty) => ...`, not just `(item, qty) => ...`? Why it has to be a partial function? – Anton K Oct 24 '18 at 12:44
  • @AntonK my assumption (i.e. guess) is that _Route_ is determining if a _pathMatcher_ matches or not by virtue of being able to ask the partial function if it is _isDefinedAt_ the given param(s). – Richard Sitze Oct 29 '18 at 21:28