From c9adfcfbc78b83d43cb91b8b3605eb7ba5bbf8e3 Mon Sep 17 00:00:00 2001 From: Konrad Malawski Date: Sun, 20 Sep 2015 19:27:04 +0100 Subject: [PATCH] =htc #18518 make it simpler to unmarshal csv values from params --- .../ParameterDirectivesExamplesSpec.scala | 16 +++++++++++++++- .../parameter-directives/parameters.rst | 6 ++++++ .../directives/ParameterDirectivesSpec.scala | 19 +++++++++++++++++++ .../http/scaladsl/common/NameReceptacle.scala | 4 ++-- .../PredefinedFromStringUnmarshallers.scala | 7 +++++++ 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala index c40c0fb907..6c5838eec3 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala @@ -7,8 +7,9 @@ package directives import akka.http.scaladsl.model._ import akka.http.scaladsl.server.Route +import akka.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers -class ParameterDirectivesExamplesSpec extends RoutingSpec { +class ParameterDirectivesExamplesSpec extends RoutingSpec with PredefinedFromStringUnmarshallers { "example-1" in { val route = parameter('color) { color => @@ -180,4 +181,17 @@ class ParameterDirectivesExamplesSpec extends RoutingSpec { responseAs[String] shouldEqual "The parameters are x = '1', x = '2'" } } + "csv" in { + val route = + parameter("names".as(CsvString)) { names => + complete(s"The parameters are ${names.mkString(", ")}") + } + + Get("/?names=Caplin") ~> route ~> check { + responseAs[String] shouldEqual "The parameters are Caplin" + } + Get("/?names=Caplin,John") ~> route ~> check { + responseAs[String] shouldEqual "The parameters are Caplin, John" + } + } } diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameters.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameters.rst index d10421f267..e5ca2e6458 100644 --- a/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameters.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameters.rst @@ -94,6 +94,12 @@ Repeated parameter .. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala :snippet: repeated +Csv valued parameter +++++++++++++++++++++ + +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala + :snippet: csv + Repeated, deserialized parameter ++++++++++++++++++++++++++++++++ diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/ParameterDirectivesSpec.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/ParameterDirectivesSpec.scala index 4889fd9546..fbca6989e3 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/ParameterDirectivesSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/ParameterDirectivesSpec.scala @@ -7,6 +7,7 @@ package directives import org.scalatest.{ FreeSpec, Inside } import akka.http.scaladsl.unmarshalling.Unmarshaller.HexInt +import akka.http.scaladsl.unmarshalling.Unmarshaller.CsvString class ParameterDirectivesSpec extends FreeSpec with GenericRoutingSpec with Inside { "when used with 'as[Int]' the parameter directive should" - { @@ -52,6 +53,24 @@ class ParameterDirectivesSpec extends FreeSpec with GenericRoutingSpec with Insi } } + "when used with 'as(CsvString)' the parameter directive should" - { + val route = + parameter("names".as(CsvString)) { names ⇒ + complete(s"The parameters are ${names.mkString(", ")}") + } + + "extract a single name" in { + Get("/?names=Caplin") ~> route ~> check { + responseAs[String] shouldEqual "The parameters are Caplin" + } + } + "extract a number of names" in { + Get("/?names=Caplin,John") ~> route ~> check { + responseAs[String] shouldEqual "The parameters are Caplin, John" + } + } + } + "when used with 'as(HexInt)' the parameter directive should" - { "extract parameter values as Int" in { Get("/?amount=1f") ~> { diff --git a/akka-http/src/main/scala/akka/http/scaladsl/common/NameReceptacle.scala b/akka-http/src/main/scala/akka/http/scaladsl/common/NameReceptacle.scala index 41ba493307..00854da023 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/common/NameReceptacle.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/common/NameReceptacle.scala @@ -7,8 +7,8 @@ package akka.http.scaladsl.common import akka.http.scaladsl.unmarshalling.{ FromStringUnmarshaller ⇒ FSU } private[http] trait ToNameReceptacleEnhancements { - implicit def symbol2NR(symbol: Symbol) = new NameReceptacle[String](symbol.name) - implicit def string2NR(string: String) = new NameReceptacle[String](string) + implicit def symbol2NR(symbol: Symbol): NameReceptacle[String] = new NameReceptacle[String](symbol.name) + implicit def string2NR(string: String): NameReceptacle[String] = new NameReceptacle[String](string) } object ToNameReceptacleEnhancements extends ToNameReceptacleEnhancements diff --git a/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/PredefinedFromStringUnmarshallers.scala b/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/PredefinedFromStringUnmarshallers.scala index 254c85ad5f..8894ce96d3 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/PredefinedFromStringUnmarshallers.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/PredefinedFromStringUnmarshallers.scala @@ -4,6 +4,8 @@ package akka.http.scaladsl.unmarshalling +import scala.collection.immutable + trait PredefinedFromStringUnmarshallers { implicit val byteFromStringUnmarshaller: Unmarshaller[String, Byte] = @@ -76,6 +78,11 @@ trait PredefinedFromStringUnmarshallers { } } + val CsvString: Unmarshaller[String, immutable.Seq[String]] = + Unmarshaller.strict[String, immutable.Seq[String]] { string ⇒ + string.split(",").toList + } + private def numberFormatError(value: String, target: String): PartialFunction[Throwable, Nothing] = { case e: NumberFormatException ⇒ throw if (value.isEmpty) Unmarshaller.NoContentException else new IllegalArgumentException(s"'$value' is not a valid $target value", e)