diff --git a/zio-http-benchmarks/src/main/scala-2.13/zio/http/benchmarks/EndpointBenchmark.scala b/zio-http-benchmarks/src/main/scala-2.13/zio/http/benchmarks/EndpointBenchmark.scala index 1087b8c1f0..8a3b9cd9ca 100644 --- a/zio-http-benchmarks/src/main/scala-2.13/zio/http/benchmarks/EndpointBenchmark.scala +++ b/zio-http-benchmarks/src/main/scala-2.13/zio/http/benchmarks/EndpointBenchmark.scala @@ -107,7 +107,7 @@ class EndpointBenchmark { val collectHttpApp = Routes( Method.GET / "users" / int("userId") / "posts" / int("postId") -> handler { (userIdInt: Int, postIdInt: Int, req: Request) => - val query = req.url.queryParams.get("query").flatMap(_.headOption).get + val query = req.url.queryParams.get("query").get Response.json(ExampleData(userIdInt, postIdInt, query).toJson) }, diff --git a/zio-http/src/main/scala/zio/http/QueryParams.scala b/zio-http/src/main/scala/zio/http/QueryParams.scala index ae9ae203fd..cd9367c941 100644 --- a/zio-http/src/main/scala/zio/http/QueryParams.scala +++ b/zio-http/src/main/scala/zio/http/QueryParams.scala @@ -84,16 +84,28 @@ final case class QueryParams(map: Map[String, Chunk[String]]) { QueryParams(map.filter(p.tupled)) /** - * Retrieves the query parameter values having the specified name. + * Retrieves all query parameter values having the specified name. */ - def get(key: String): Option[Chunk[String]] = map.get(key) + def getAll(key: String): Option[Chunk[String]] = map.get(key) /** - * Retrieves the query parameter value having the specified name, or else uses - * the default iterable. + * Retrieves the first query parameter value having the specified name. */ - def getOrElse(key: String, default: => Iterable[String]): Chunk[String] = - map.getOrElse(key, Chunk.fromIterable(default)) + def get(key: String): Option[String] = getAll(key).flatMap(_.headOption) + + /** + * Retrieves all query parameter values having the specified name, or else + * uses the default iterable. + */ + def getAllOrElse(key: String, default: => Iterable[String]): Chunk[String] = + getAll(key).getOrElse(Chunk.fromIterable(default)) + + /** + * Retrieves the first query parameter value having the specified name, or + * else uses the default value. + */ + def getOrElse(key: String, default: => String): String = + get(key).getOrElse(default) override def hashCode: Int = normalize.map.hashCode diff --git a/zio-http/src/main/scala/zio/http/codec/internal/EncoderDecoder.scala b/zio-http/src/main/scala/zio/http/codec/internal/EncoderDecoder.scala index 15bfd5eaea..a49bbd4a00 100644 --- a/zio-http/src/main/scala/zio/http/codec/internal/EncoderDecoder.scala +++ b/zio-http/src/main/scala/zio/http/codec/internal/EncoderDecoder.scala @@ -283,7 +283,7 @@ private[codec] object EncoderDecoder { val queryParamValue = queryParams - .getOrElse(query.name, Nil) + .getAllOrElse(query.name, Nil) .collectFirst(query.textCodec) queryParamValue match { diff --git a/zio-http/src/test/scala/zio/http/QueryParamsSpec.scala b/zio-http/src/test/scala/zio/http/QueryParamsSpec.scala index 5c3d6d9e14..277ace21ed 100644 --- a/zio-http/src/test/scala/zio/http/QueryParamsSpec.scala +++ b/zio-http/src/test/scala/zio/http/QueryParamsSpec.scala @@ -230,6 +230,18 @@ object QueryParamsSpec extends ZIOHttpSpec { } }, ), + suite("get - getAll")( + test("success") { + val name = "name" + val default = "default" + val unknown = "non-existent" + val queryParams = QueryParams(name -> "a", name -> "b") + assertTrue(queryParams.get(name).get == "a") && + assertTrue(queryParams.getOrElse(unknown, default) == default) && + assertTrue(queryParams.getAll(name).get.length == 2) && + assertTrue(queryParams.getAllOrElse(unknown, Chunk(default)).length == 1) + }, + ), suite("encode - decode")( test("success") { val genQueryParamsWithoutCornerCases = diff --git a/zio-http/src/test/scala/zio/http/codec/HttpCodecSpec.scala b/zio-http/src/test/scala/zio/http/codec/HttpCodecSpec.scala index d5535a6260..058bebb9c1 100644 --- a/zio-http/src/test/scala/zio/http/codec/HttpCodecSpec.scala +++ b/zio-http/src/test/scala/zio/http/codec/HttpCodecSpec.scala @@ -137,8 +137,8 @@ object HttpCodecSpec extends ZIOHttpSpec { test("paramBool encoding") { val requestTrue = codecBool.encodeRequest(true) val requestFalse = codecBool.encodeRequest(false) - assert(requestTrue.url.queryParams.get(isAge).get.head)(Assertion.equalTo("true")) && - assert(requestFalse.url.queryParams.get(isAge).get.head)(Assertion.equalTo("false")) + assert(requestTrue.url.queryParams.get(isAge).get)(Assertion.equalTo("true")) && + assert(requestFalse.url.queryParams.get(isAge).get)(Assertion.equalTo("false")) }, ) + suite("Codec with examples") {