akka-http 验证路径段
akka-http validate path segment
如何验证 PathMatcher
中的 akka-http 路径段?
我想拒绝请求(而不是简单地将其标记为 Unmatched
)。
我想要实现的是 return 400 Bad request if SegmentAsUserId
marks segment as invalid:
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 =>
// ...
}
我知道可以使用指令(拒绝)。但是有路径匹配的机制吗?
更新:
我不确定 PathMatchers
是您的用例所需要的。来自Akka官方The PathMatcher DSL:
The PathMatcher mini-DSL is used to match incoming URL’s and extract values from them. It is used in the path directive.
它不用于检查这些值的有效性。所以我认为这不是你需要的。
那里有一个很好的例子说明如何使用 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.")
}
}
如果从@TomerShetah 的回答中看不出指令可以重复使用,你可以这样做:
object ValidatedObjectId {
def apply(directive: Directive[String]): Directive[String] =
directive.filter(
id => ObjectId.isValid(id), // or just ObjectId.isValid
rejectionObject // e.g. MalformedPathParamRejection("message")
)
}
val complexRoute: Route = ValidatedObjectId(path(Segment)) { userId =>
get {
complete(StatusCodes.OK, s"userId is: $user")
} ~
post {
user = userId
complete(StatusCodes.OK)
}
}
如何验证 PathMatcher
中的 akka-http 路径段?
我想拒绝请求(而不是简单地将其标记为 Unmatched
)。
我想要实现的是 return 400 Bad request if SegmentAsUserId
marks segment as invalid:
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 =>
// ...
}
我知道可以使用指令(拒绝)。但是有路径匹配的机制吗?
更新:
我不确定 PathMatchers
是您的用例所需要的。来自Akka官方The PathMatcher DSL:
The PathMatcher mini-DSL is used to match incoming URL’s and extract values from them. It is used in the path directive.
它不用于检查这些值的有效性。所以我认为这不是你需要的。
那里有一个很好的例子说明如何使用 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.")
}
}
如果从@TomerShetah 的回答中看不出指令可以重复使用,你可以这样做:
object ValidatedObjectId {
def apply(directive: Directive[String]): Directive[String] =
directive.filter(
id => ObjectId.isValid(id), // or just ObjectId.isValid
rejectionObject // e.g. MalformedPathParamRejection("message")
)
}
val complexRoute: Route = ValidatedObjectId(path(Segment)) { userId =>
get {
complete(StatusCodes.OK, s"userId is: $user")
} ~
post {
user = userId
complete(StatusCodes.OK)
}
}