From 7fdd5983a3d8c034ce6ed2ee9244304e4a663376 Mon Sep 17 00:00:00 2001 From: kwyczesany Date: Tue, 7 Jun 2016 21:02:38 +0200 Subject: [PATCH] +htp #19756: Add extractData and extractRequestEntity directives. (#20730) * 19756: Add extractData and extractRequestEntity directives. remove unnecessary import * #19756: add documentation to extractDataBytes and extractRequestEntity directives --- .../BasicDirectivesExamplesSpec.scala | 31 +++++++++++++++++++ .../routing-dsl/directives/alphabetically.rst | 2 ++ .../basic-directives/extractDataBytes.rst | 24 ++++++++++++++ .../basic-directives/extractRequestEntity.rst | 25 +++++++++++++++ .../directives/basic-directives/index.rst | 4 +++ .../directives/BasicDirectivesSpec.scala | 27 ++++++++++++++++ .../server/directives/BasicDirectives.scala | 16 +++++++++- .../server/directives/BasicDirectives.scala | 19 ++++++++++++ 8 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/extractDataBytes.rst create mode 100644 akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/extractRequestEntity.rst diff --git a/akka-docs/rst/scala/code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala b/akka-docs/rst/scala/code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala index 368a19328e..0b5ff6247e 100644 --- a/akka-docs/rst/scala/code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala +++ b/akka-docs/rst/scala/code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala @@ -795,5 +795,36 @@ class BasicDirectivesExamplesSpec extends RoutingSpec { } //# } + "extractRequestEntity-example" in { + //#extractRequestEntity-example + val route = + extractRequestEntity { entity => + complete(s"Request entity content-type is ${entity.contentType}") + } + + // tests: + val httpEntity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, "req") + Post("/abc", httpEntity) ~> route ~> check { + responseAs[String] shouldEqual s"Request entity content-type is text/plain; charset=UTF-8" + } + //# + } + "extractDataBytes-example" in { + //#extractDataBytes-example + val route = + extractDataBytes { data ⇒ + val sum = data.runFold(0) { (acc, i) ⇒ acc + i.utf8String.toInt } + onSuccess(sum) { s ⇒ + complete(HttpResponse(entity = HttpEntity(s.toString))) + } + } + + // tests: + val dataBytes = Source.fromIterator(() ⇒ Iterator.range(1, 10).map(x ⇒ ByteString(x.toString))) + Post("/abc", HttpEntity(ContentTypes.`text/plain(UTF-8)`, data = dataBytes)) ~> route ~> check { + responseAs[String] shouldEqual "45" + } + //# + } } diff --git a/akka-docs/rst/scala/http/routing-dsl/directives/alphabetically.rst b/akka-docs/rst/scala/http/routing-dsl/directives/alphabetically.rst index 7e718bff58..9093b04a75 100644 --- a/akka-docs/rst/scala/http/routing-dsl/directives/alphabetically.rst +++ b/akka-docs/rst/scala/http/routing-dsl/directives/alphabetically.rst @@ -47,6 +47,7 @@ Directive Description via the ``Accept-Encoding`` header (from a user-defined set) :ref:`-entity-` Extracts the request entity unmarshalled to a given type :ref:`-extract-` Extracts a single value using a ``RequestContext ⇒ T`` function +:ref:`-extractDataBytes-` Extracts the entities data bytes as a stream ``Source[ByteString, Any]`` :ref:`-extractClientIP-` Extracts the client's IP from either the ``X-Forwarded-``, ``Remote-Address`` or ``X-Real-IP`` header :ref:`-extractCredentials-` Extracts the potentially present ``HttpCredentials`` provided with the @@ -58,6 +59,7 @@ Directive Description :ref:`-extractMethod-` Extracts the request method :ref:`-extractRequest-` Extracts the current ``HttpRequest`` instance :ref:`-extractRequestContext-` Extracts the ``RequestContext`` itself +:ref:`-extractRequestEntity-` Extracts the ``RequestEntity`` from the ``RequestContext`` :ref:`-extractScheme-` Extracts the URI scheme from the request :ref:`-extractSettings-` Extracts the ``RoutingSettings`` from the ``RequestContext`` :ref:`-extractUnmatchedPath-` Extracts the yet unmatched path from the ``RequestContext`` diff --git a/akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/extractDataBytes.rst b/akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/extractDataBytes.rst new file mode 100644 index 0000000000..5b962b2de5 --- /dev/null +++ b/akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/extractDataBytes.rst @@ -0,0 +1,24 @@ +.. _-extractDataBytes-: + +extractDataBytes +================ + +Signature +--------- + +.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: extractDataBytes + +Description +----------- + +Extracts the entities data bytes as ``Source[ByteString, Any]`` from the :class:`RequestContext`. + +The directive returns a stream containing the request data bytes. + + +Example +------- + +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: extractDataBytes-example diff --git a/akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/extractRequestEntity.rst b/akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/extractRequestEntity.rst new file mode 100644 index 0000000000..53e142c5ca --- /dev/null +++ b/akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/extractRequestEntity.rst @@ -0,0 +1,25 @@ +.. _-extractRequestEntity-: + +extractRequestEntity +==================== + +Signature +--------- + +.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: extractRequestEntity + +Description +----------- + +Extracts the ``RequestEntity`` from the :class:`RequestContext`. + +The directive returns a ``RequestEntity`` without unmarshalling the request. To extract domain entity, +:ref:`-entity-` should be used. + + +Example +------- + +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: extractRequestEntity-example diff --git a/akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/index.rst b/akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/index.rst index 2b5c0bd4cd..709f7d7b29 100644 --- a/akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/index.rst +++ b/akka-docs/rst/scala/http/routing-dsl/directives/basic-directives/index.rst @@ -17,11 +17,13 @@ on two axes: a) provide a constant value or extract a value from the ``RequestCo a single value or a tuple of values. * :ref:`-extract-` + * :ref:`-extractDataBytes-` * :ref:`-extractExecutionContext-` * :ref:`-extractMaterializer-` * :ref:`-extractLog-` * :ref:`-extractRequest-` * :ref:`-extractRequestContext-` + * :ref:`-extractRequestEntity-` * :ref:`-extractSettings-` * :ref:`-extractUnmatchedPath-` * :ref:`-extractUri-` @@ -94,10 +96,12 @@ Alphabetically cancelRejections extract extractExecutionContext + extractDataBytes extractMaterializer extractLog extractRequest extractRequestContext + extractRequestEntity extractSettings extractUnmatchedPath extractUri diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/BasicDirectivesSpec.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/BasicDirectivesSpec.scala index 1bee6147a0..c1e619bb63 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/BasicDirectivesSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/BasicDirectivesSpec.scala @@ -5,6 +5,10 @@ package akka.http.scaladsl.server package directives +import akka.http.scaladsl.model._ +import akka.stream.scaladsl.Source +import akka.util.ByteString + class BasicDirectivesSpec extends RoutingSpec { "The `mapUnmatchedPath` directive" should { @@ -26,4 +30,27 @@ class BasicDirectivesSpec extends RoutingSpec { } ~> check { responseAs[String] shouldEqual "GET" } } } + + "The `extractDataBytes` directive" should { + "extract stream of ByteString from the RequestContext" in { + val dataBytes = Source.fromIterator(() ⇒ Iterator.range(1, 10).map(x ⇒ ByteString(x.toString))) + Post("/abc", HttpEntity(ContentTypes.`text/plain(UTF-8)`, data = dataBytes)) ~> { + extractDataBytes { data ⇒ + val sum = data.runFold(0) { (acc, i) ⇒ acc + i.utf8String.toInt } + onSuccess(sum) { s ⇒ + complete(HttpResponse(entity = HttpEntity(s.toString))) + } + } + } ~> check { responseAs[String] shouldEqual "45" } + } + } + + "The `extractRequestEntity` directive" should { + "extract entity from the RequestContext" in { + val httpEntity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, "req") + Post("/abc", httpEntity) ~> { + extractRequestEntity { complete(_) } + } ~> check { responseEntity shouldEqual httpEntity } + } + } } \ No newline at end of file diff --git a/akka-http/src/main/scala/akka/http/javadsl/server/directives/BasicDirectives.scala b/akka-http/src/main/scala/akka/http/javadsl/server/directives/BasicDirectives.scala index 291453393b..886223d662 100644 --- a/akka-http/src/main/scala/akka/http/javadsl/server/directives/BasicDirectives.scala +++ b/akka-http/src/main/scala/akka/http/javadsl/server/directives/BasicDirectives.scala @@ -10,6 +10,8 @@ import akka.http.impl.util.JavaMapping import akka.http.javadsl.settings.ParserSettings import akka.http.javadsl.settings.RoutingSettings import akka.japi.Util +import akka.stream.javadsl.Source +import akka.util.ByteString import scala.concurrent.ExecutionContextExecutor import akka.http.impl.model.JavaUri @@ -184,7 +186,7 @@ abstract class BasicDirectives { * Extracts the current http request entity. */ @CorrespondsTo("extract") - def extractEntity(inner: java.util.function.Function[RequestEntity, Route]): Route = RouteAdapter { + def extractEntity(inner: JFunction[RequestEntity, Route]): Route = RouteAdapter { D.extractRequest { rq ⇒ inner.apply(rq.entity).delegate } @@ -269,4 +271,16 @@ abstract class BasicDirectives { D.extractRequestContext { ctx ⇒ inner.apply(JavaMapping.toJava(ctx)(server.RoutingJavaMapping.RequestContext)).delegate } } + /** + * Extracts the entities `dataBytes` [[akka.stream.javadsl.Source]] from the [[akka.http.javadsl.server.RequestContext]]. + */ + def extractDataBytes(inner: JFunction[Source[ByteString, Any], Route]) = RouteAdapter { + D.extractRequest { ctx ⇒ inner.apply(ctx.entity.dataBytes.asJava).delegate } + } + + /** + * Extracts the [[akka.http.javadsl.model.RequestEntity]] from the [[akka.http.javadsl.server.RequestContext]]. + */ + def extractRequestEntity(inner: JFunction[RequestEntity, Route]): Route = extractEntity(inner) + } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala index 93d4952163..1b5d4fcecc 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala @@ -5,6 +5,9 @@ package akka.http.scaladsl.server package directives +import akka.stream.scaladsl.Source +import akka.util.ByteString + import scala.concurrent.{ Future, ExecutionContextExecutor } import scala.collection.immutable import akka.event.LoggingAdapter @@ -284,6 +287,20 @@ trait BasicDirectives { * @group basic */ def extractRequestContext: Directive1[RequestContext] = BasicDirectives._extractRequestContext + + /** + * Extracts the [[akka.http.scaladsl.model.RequestEntity]] from the [[akka.http.scaladsl.server.RequestContext]]. + * + * @group basic + */ + def extractRequestEntity: Directive1[RequestEntity] = BasicDirectives._extractRequestEntity + + /** + * Extracts the entities `dataBytes` [[akka.stream.scaladsl.Source]] from the [[akka.http.scaladsl.server.RequestContext]]. + * + * @group basic + */ + def extractDataBytes: Directive1[Source[ByteString, Any]] = BasicDirectives._extractDataBytes } object BasicDirectives extends BasicDirectives { @@ -296,4 +313,6 @@ object BasicDirectives extends BasicDirectives { private val _extractSettings: Directive1[RoutingSettings] = extract(_.settings) private val _extractParserSettings: Directive1[ParserSettings] = extract(_.parserSettings) private val _extractRequestContext: Directive1[RequestContext] = extract(conforms) + private val _extractRequestEntity: Directive1[RequestEntity] = extract(_.request.entity) + private val _extractDataBytes: Directive1[Source[ByteString, Any]] = extract(_.request.entity.dataBytes) }