akka-http 验证路径段

问题描述

如何验证 PathMatcher 中的 akka-http 路径段? 我想拒绝请求(而不是简单地将其标记Unmatched)。

我想要实现的是返回 400 Bad request 如果 SegmentAsUserId 将段标记为无效:

path(SegmentAsUserId) { implicit userId =>
  concat(
    get {
      handleGet()
    },post {
      handlePost()
    }
  )
}

我现在找到的唯一方法是在 PathMatcher1 中抛出异常:

object SegmentAsUserId extends PathMatcher1[String] {
  override def apply(path: Path): PathMatcher.Matching[Tuple1[String]] = path match {
    case Path.Segment(segment,tail) =>
      if (ObjectId.isValid(segment))
        Matched(tail,Tuple1(segment))
      else
        throw InvalidUserIdException(segment)
    case _                           => Unmatched
  }
}

一个丑陋的解决方案抛出异常:

case class FindByIdRequest(id: String) {
  require(ObjectId.isValid(id),"The id " + id + " is invalid")
}

path(Segment).as(FindByIdRequest) { implicit userId =>
  // ...
}

我知道可以使用指令(拒绝)。但是有路径匹配的机制吗?

更新:

The solution I came up with.

解决方法

我不确定 PathMatchers 是否是您的用例所需要的。来自 Akka 官方 The PathMatcher DSL

PathMatcher mini-DSL 用于匹配传入的 URL 并从中提取值。它在路径指令中使用。

它不用于检查这些值的有效性。因此,我认为这不是您所需要的。

有一个很好的例子说明了如何使用 PathMatcher

val matcher: PathMatcher1[Option[Int]] =
  "foo" / "bar" / "X" ~ IntNumber.? / ("edit" | "create")

val route: Route =
  path(matcher) { i: Option[Int] =>
    complete(s"Matched X${i.getOrElse("")}")
  }

为了实现检查验证,请考虑以下路线:

var user = "none"

object ObjectId {
  def isValid(s: String): Boolean = s.startsWith("a")
}

val complexRoute: Route = path(Segment) { userId =>
  if (ObjectId.isValid(userId)) {
    get {
      complete(StatusCodes.OK,s"userId is: $user")
    } ~
    post {
      user = userId
      complete(StatusCodes.OK)
    }
  } else {
    complete(StatusCodes.BadRequest,s"userId $userId is not supported.")
  }
}