在 Scala 中使用 QueryParamDecoder 解码可选查询参数
Decode an optional query parameter using QueryParamDecoder in Scala
我想解码我的 Scala 代码中的可选查询参数。我正在使用 http4s。该参数的形式为 ?part=35/43
。最终目标是将这个分数存储为 Type Part = (Int, Int)
,这样我们就可以将 (35, 43)
作为元组在代码中进一步使用。我创建了一个对象,例如:
https://http4s.org/v0.18/dsl/#optional-query-parameters
object OptionalPartitionQueryParamMatcher
extends OptionalValidatingQueryParamDecoderMatcher[Part]("part")
现在 OptionalValidatingQueryParamDecoderMatcher
需要范围内的隐式 QueryParamDecoder[Part]
。
为此我创建了一个隐式 val,它需要检查我们是否真的有一个有效的分数,也就是说,两个字符都应该是数字(而不是 a/1
或 b/c
等)且分数应小于 1(1/2
、5/8
等):
implicit val ev: QueryParamDecoder[Part] =
new QueryParamDecoder[Part] {
def decode(
partition: QueryParameterValue
): ValidatedNel[ParseFailure, Part] = {
val partAndPartitions = partition.value.split("/")
Validated
.catchOnly[NumberFormatException] {
val part = partAndPartitions(0).toInt
val partitions = partAndPartitions(1).toInt
if (
partAndPartitions.length != 2 || part > partitions || part <= 0 || partitions <= 0
) {
throw new IllegalArgumentException
}
(part, partitions)
}
.leftMap(e => ParseFailure("Invalid query parameter part", e.getMessage))
.toValidatedNel
}
}
上面代码的问题是,它只捕获 NumberFormatException
(当它不能使用 .toInt
将字符串转换为 Int 时也是如此)但是如果我输入类似 [=23 的东西怎么办? =],然后它应该捕获 ArrayIndexOutOfBoundsException
因为我正在查询数组中的前两个值,或者当小数根本无效时假设 IllegalArgumentException
。我怎样才能做到这一点,一次性捕获所有内容?谢谢!
嗯,最简单的方法是使用 .catchOnly[Throwable]
(甚至直接 QueryParamDecoder .fromUnsafeCast
),它会捕获任何错误。
不过,我个人更愿意这样做:
(我现在无法编译代码,如果有错别字,请见谅)
implicit final val PartQueryParamDecoder: QueryParamDecoder[Part] =
QueryParamDecoder[String].emap { str =>
def failure(details: String): Either[ParseFailure, Part] =
Left(ParseFailure(
sanitized = "Invalid query parameter part",
details = s"'${str}' is not properly formttated: ${details}"
))
str.split('/').toList match {
case aRaw :: bRaw :: Nil =>
(aRaw.toIntOption, bRaw.toIntOption) match {
case (Some(a), Some(b)) =>
Right(Part(a, b))
case _ =>
failure(details = "Some of the fraction parts are not numbers")
}
case _ =>
failure(details = "It doesn't correspond to a fraction 'a/b'")
}
}
我想解码我的 Scala 代码中的可选查询参数。我正在使用 http4s。该参数的形式为 ?part=35/43
。最终目标是将这个分数存储为 Type Part = (Int, Int)
,这样我们就可以将 (35, 43)
作为元组在代码中进一步使用。我创建了一个对象,例如:
https://http4s.org/v0.18/dsl/#optional-query-parameters
object OptionalPartitionQueryParamMatcher
extends OptionalValidatingQueryParamDecoderMatcher[Part]("part")
现在 OptionalValidatingQueryParamDecoderMatcher
需要范围内的隐式 QueryParamDecoder[Part]
。
为此我创建了一个隐式 val,它需要检查我们是否真的有一个有效的分数,也就是说,两个字符都应该是数字(而不是 a/1
或 b/c
等)且分数应小于 1(1/2
、5/8
等):
implicit val ev: QueryParamDecoder[Part] =
new QueryParamDecoder[Part] {
def decode(
partition: QueryParameterValue
): ValidatedNel[ParseFailure, Part] = {
val partAndPartitions = partition.value.split("/")
Validated
.catchOnly[NumberFormatException] {
val part = partAndPartitions(0).toInt
val partitions = partAndPartitions(1).toInt
if (
partAndPartitions.length != 2 || part > partitions || part <= 0 || partitions <= 0
) {
throw new IllegalArgumentException
}
(part, partitions)
}
.leftMap(e => ParseFailure("Invalid query parameter part", e.getMessage))
.toValidatedNel
}
}
上面代码的问题是,它只捕获 NumberFormatException
(当它不能使用 .toInt
将字符串转换为 Int 时也是如此)但是如果我输入类似 [=23 的东西怎么办? =],然后它应该捕获 ArrayIndexOutOfBoundsException
因为我正在查询数组中的前两个值,或者当小数根本无效时假设 IllegalArgumentException
。我怎样才能做到这一点,一次性捕获所有内容?谢谢!
嗯,最简单的方法是使用 .catchOnly[Throwable]
(甚至直接 QueryParamDecoder .fromUnsafeCast
),它会捕获任何错误。
不过,我个人更愿意这样做:
(我现在无法编译代码,如果有错别字,请见谅)
implicit final val PartQueryParamDecoder: QueryParamDecoder[Part] =
QueryParamDecoder[String].emap { str =>
def failure(details: String): Either[ParseFailure, Part] =
Left(ParseFailure(
sanitized = "Invalid query parameter part",
details = s"'${str}' is not properly formttated: ${details}"
))
str.split('/').toList match {
case aRaw :: bRaw :: Nil =>
(aRaw.toIntOption, bRaw.toIntOption) match {
case (Some(a), Some(b)) =>
Right(Part(a, b))
case _ =>
failure(details = "Some of the fraction parts are not numbers")
}
case _ =>
failure(details = "It doesn't correspond to a fraction 'a/b'")
}
}