简体   繁体   中英

Extract path parameters with akka http routing dsl

Akka HTTP has good support in the routing dsl for extracting path query parameters (those following the ?, concatenated by &), but not for path parameters separated by ; (such as /my/path;JSESSIONID=123)

How is this best accomplished?

Easier than I thought. Could probably remove dependency on scalaz (Lens) and optimize the code a bit, but this will do for now.

Btw, also discovered that path params destroys the ability to match paths with the path directive: /my/path;JSESSIONID=123 does not match the directive path("my" / "path")

The solution below addresses this by removing the path params from the request context, and instead providing them.

Note to Akka guys: maybe you could incorporate something similar in the framework so the next guy that looks for getting JSESSIONID from path params doesn't have to implement the same?

  def pathParams: Directive1[List[String]] = {
    val prv = provide(List.empty[String])
    def somePathParams(ctxPathLens: Lens[RequestContext, Path]) =
      extract(ctx => (Slash ~ Segments).apply(ctxPathLens.get(ctx))).flatMap {
        case Matched(_, Tuple1(path)) =>
          path.takeRight(1) match {
            case last :: Nil => last.split(';').toList match {
              case lastHead :: lastTail => provide(lastTail) & mapRequestContext(
                ctxPathLens.set(_, Path((path.dropRight(1) :+ lastHead).mkString("/", "/", ""))))
              case _ => prv
            }
            case _ => prv
          }
        case _ => prv
      }

    val unmatchedPath = somePathParams(Lens.lensu((ctx, path) =>
      ctx.mapUnmatchedPath(_ => path),
      _.unmatchedPath))

    val requestPath = somePathParams(Lens.lensu((ctx, path) =>
      ctx.mapRequest(r => r.withUri(r.uri.withPath(path)))
      , _.request.uri.path))

    unmatchedPath.tflatMap(_ => Directive.Empty) & requestPath
  }

  def pathParamsMap: Directive1[Map[String, String]] =
    pathParams.map(_.map(_.split('=').toList match {
      case key :: Nil => key -> ""
      case key :: values => key -> values.mkString("=")
      case _ => ???
    }).toMap)

  def optionalPathParam(name: String): Directive1[Option[String]] =
    pathParamsMap.map(_.get(name))

  def optionalPathParamSessionId:Directive1[Option[UUID]] =
    optionalPathParam(jsessionidKey).map(_.flatMap(j => Try(UUID.fromString(j)).toOption))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM