From 1441f201b18e56d1f37bdac76addc81a833f1a62 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 17 Jul 2015 16:18:18 +0200 Subject: [PATCH] =docs #18012 complete remaining TODO sections in scala HTTP docs --- .../code/docs/http/scaladsl/MarshalSpec.scala | 38 +++++ .../docs/http/scaladsl/UnmarshalSpec.scala | 27 +++ .../http/client-side/connection-level.rst | 14 +- .../rst/scala/http/common/de-coding.rst | 14 +- .../rst/scala/http/common/json-support.rst | 30 +++- .../rst/scala/http/common/marshalling.rst | 160 +++++++++++++++++- .../rst/scala/http/common/unmarshalling.rst | 115 ++++++++++++- .../rst/scala/http/common/xml-support.rst | 27 ++- .../scala/http/low-level-server-side-api.rst | 14 +- .../basic-directives/withMaterializer.rst | 2 +- .../directives/security-directives/index.rst | 18 +- .../main/scala/akka/http/scaladsl/Http.scala | 60 ++++--- .../akka/http/scaladsl/model/HttpEntity.scala | 14 +- .../akka/http/scaladsl/model/Multipart.scala | 2 +- .../scaladsl/marshalling/Marshaller.scala | 4 + .../PredefinedToEntityMarshallers.scala | 2 +- .../http/scaladsl/marshalling/package.scala | 2 + .../scaladsl/unmarshalling/Unmarshaller.scala | 25 +-- .../http/scaladsl/unmarshalling/package.scala | 2 + 19 files changed, 519 insertions(+), 51 deletions(-) create mode 100644 akka-docs-dev/rst/scala/code/docs/http/scaladsl/MarshalSpec.scala create mode 100644 akka-docs-dev/rst/scala/code/docs/http/scaladsl/UnmarshalSpec.scala diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/MarshalSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/MarshalSpec.scala new file mode 100644 index 0000000000..4e993510d6 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/MarshalSpec.scala @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl + +import akka.stream.testkit.AkkaSpec + +class MarshalSpec extends AkkaSpec { + + "use marshal" in { + import scala.concurrent.Await + import scala.concurrent.duration._ + import akka.http.scaladsl.marshalling.Marshal + import akka.http.scaladsl.model._ + + import system.dispatcher // ExecutionContext + + val string = "Yeah" + val entityFuture = Marshal(string).to[MessageEntity] + val entity = Await.result(entityFuture, 1.second) // don't block in non-test code! + entity.contentType shouldEqual ContentTypes.`text/plain(UTF-8)` + + val errorMsg = "Easy, pal!" + val responseFuture = Marshal(420 -> errorMsg).to[HttpResponse] + val response = Await.result(responseFuture, 1.second) // don't block in non-test code! + response.status shouldEqual StatusCodes.EnhanceYourCalm + response.entity.contentType shouldEqual ContentTypes.`text/plain(UTF-8)` + + val request = HttpRequest(headers = List(headers.Accept(MediaTypes.`application/json`))) + val responseText = "Plaintext" + val respFuture = Marshal(responseText).toResponseFor(request) // with content negotiation! + a[Marshal.UnacceptableResponseContentTypeException] should be thrownBy { + Await.result(respFuture, 1.second) // client requested JSON, we only have text/plain! + } + } + +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/UnmarshalSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/UnmarshalSpec.scala new file mode 100644 index 0000000000..e71392417b --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/UnmarshalSpec.scala @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl + +import akka.stream.testkit.AkkaSpec + +class UnmarshalSpec extends AkkaSpec { + + "use unmarshal" in { + import akka.http.scaladsl.unmarshalling.Unmarshal + import system.dispatcher + + import scala.concurrent.Await + import scala.concurrent.duration._ // ExecutionContext + + val intFuture = Unmarshal("42").to[Int] + val int = Await.result(intFuture, 1.second) // don't block in non-test code! + int shouldEqual 42 + + val boolFuture = Unmarshal("off").to[Boolean] + val bool = Await.result(boolFuture, 1.second) // don't block in non-test code! + bool shouldBe false + } + +} diff --git a/akka-docs-dev/rst/scala/http/client-side/connection-level.rst b/akka-docs-dev/rst/scala/http/client-side/connection-level.rst index a28ec2d5a4..86fb2f6650 100644 --- a/akka-docs-dev/rst/scala/http/client-side/connection-level.rst +++ b/akka-docs-dev/rst/scala/http/client-side/connection-level.rst @@ -68,4 +68,16 @@ However, akka-stream should soon provide such a feature. Stand-Alone HTTP Layer Usage ---------------------------- -// TODO \ No newline at end of file +Due to its Reactive-Stream-based nature the Akka HTTP layer is fully detachable from the underlying TCP +interface. While in most applications this "feature" will not be crucial it can be useful in certain cases to be able +to "run" the HTTP layer (and, potentially, higher-layers) against data that do not come from the network but rather +some other source. Potential scenarios where this might be useful include tests, debugging or low-level event-sourcing +(e.g by replaying network traffic). + +On the client-side the stand-alone HTTP layer forms a ``BidiStage`` that is defined like this: + +.. includecode2:: /../../akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala + :snippet: client-layer + +You create an instance of ``Http.ClientLayer`` by calling one of the two overloads of the ``Http().clientLayer`` method, +which also allows for varying degrees of configuration. \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/common/de-coding.rst b/akka-docs-dev/rst/scala/http/common/de-coding.rst index c49b26f6c6..89e2c9ae47 100644 --- a/akka-docs-dev/rst/scala/http/common/de-coding.rst +++ b/akka-docs-dev/rst/scala/http/common/de-coding.rst @@ -1,4 +1,16 @@ Encoding / Decoding =================== -... \ No newline at end of file +The `HTTP spec`_ defines a ``Content-Encoding`` header, which signifies whether the entity body of an HTTP message is +"encoded" and, if so, by which algorithm. The only commonly used content encodings are compression algorithms. + +Currently Akka HTTP supports the compression and decompression of HTTP requests and responses with the ``gzip`` or +``deflate`` encodings. +The core logic for this lives in the `akka.http.scaladsl.coding`_ package. + +The support is not enabled automatically, but must be explicitly requested. +For enabling message encoding/decoding with :ref:`Routing DSL ` see the :ref:`CodingDirectives`. + +.. _HTTP spec: http://tools.ietf.org/html/rfc7231#section-3.1.2.1 +.. _akka.http.scaladsl.coding: https://github.com/akka/akka/tree/release-2.3-dev/akka-http/src/main/scala/akka/http/scaladsl/coding + diff --git a/akka-docs-dev/rst/scala/http/common/json-support.rst b/akka-docs-dev/rst/scala/http/common/json-support.rst index a98126977d..cdfc292333 100644 --- a/akka-docs-dev/rst/scala/http/common/json-support.rst +++ b/akka-docs-dev/rst/scala/http/common/json-support.rst @@ -1,4 +1,32 @@ JSON Support ============ -... \ No newline at end of file +Akka HTTP's :ref:`marshalling ` and :ref:`unmarshalling ` +infrastructure makes it rather easy to seamlessly support specific wire representations of your data objects, like JSON, +XML or even binary encodings. + +For JSON Akka HTTP currently provides support for `spray-json`_ right out of the box through it's +``akka-http-spray-json`` module. + + +spray-json Support +------------------ + +The SprayJsonSupport_ trait provides a ``FromEntityUnmarshaller[T]`` and ``ToEntityMarshaller[T]`` for every type ``T`` +that an implicit ``spray.json.RootJsonReader`` and/or ``spray.json.RootJsonWriter`` (respectively) is available for. + +This is how you enable automatic support for (un)marshalling from and to JSON with `spray-json`_: + +1. Add a library dependency onto ``"com.typesafe.akka" %% "akka-http-spray-json-experimental" % "1.x"``. + +2. ``import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._`` or mix in the + ``akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport`` trait. + +3. Provide a ``RootJsonFormat[T]`` for your type and bring it into scope. + Check out the `spray-json`_ documentation for more info on how to do this. + +Once you have done this (un)marshalling between JSON and your type ``T`` should work nicely and transparently. + + +.. _spray-json: https://github.com/spray/spray-json +.. _SprayJsonSupport: @github@/akka-http-marshallers-scala/akka-http-spray-json/src/main/scala/akka/http/scaladsl/marshallers/sprayjson/SprayJsonSupport.scala \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/common/marshalling.rst b/akka-docs-dev/rst/scala/http/common/marshalling.rst index 10674cf407..487fe73e3b 100644 --- a/akka-docs-dev/rst/scala/http/common/marshalling.rst +++ b/akka-docs-dev/rst/scala/http/common/marshalling.rst @@ -3,4 +3,162 @@ Marshalling =========== -... \ No newline at end of file +"Marshalling" is the process of converting a higher-level (object) structure into some kind of lower-level +representation, often a "wire format". Other popular names for it are "Serialization" or "Pickling". + +In Akka HTTP "Marshalling" means the conversion of an object of type ``T`` into a lower-level target type, +e.g. a ``MessageEntity`` (which forms the "entity body" of an HTTP request or response) or a full ``HttpRequest`` or +``HttpResponse``. + + +Basic Design +------------ + +Marshalling of instances of type ``A`` into instances of type ``B`` is performed by a ``Marshaller[A, B]``. +Akka HTTP also predefines a number of helpful aliases for the types of marshallers that you'll likely work with most: + +.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/marshalling/package.scala + :snippet: marshaller-aliases + +Contrary to what you might initially expect ``Marshaller[A, B]`` is not a plain function ``A => B`` but rather +essentially a function ``A => Future[List[Marshalling[B]]]``. +Let's dissect this rather complicated looking signature piece by piece to understand what marshallers are designed this +way. +Given an instance of type ``A`` a ``Marshaller[A, B]`` produces: + +1. A ``Future``: This is probably quite clear. Marshallers are not required to synchronously produce a result, so instead +they return a future, which allows for asynchronicity in the marshalling process. + +2. of ``List``: Rather than only a single target representation for ``A`` marshallers can offer several ones. Which +one will be rendered onto the wire in the end is decided by content negotiation. +For example, the ``ToEntityMarshaller[OrderConfirmation]`` might offer a JSON as well as an XML representation. +The client can decide through the addition of an ``Accept`` request header which one is preferred. If the client doesn't +express a preference the first representation is picked. + +3. of ``Marshalling[B]``: Rather than returning an instance of ``B`` directly marshallers first produce a +``Marshalling[B]``. This allows for querying the ``MediaType`` and potentially the ``HttpCharset`` that the marshaller +will produce before the actual marshalling is triggered. Apart from enabling content negotiation this design allows for +delaying the actual construction of the marshalling target instance to the very last moment when it is really needed. + +This is how ``Marshalling`` is defined: + +.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/marshalling/Marshaller.scala + :snippet: marshalling + + +Predefined Marshallers +---------------------- + +Akka HTTP already predefines a number of marshallers for the most common types. +Specifically these are: + +- PredefinedToEntityMarshallers_ + + - ``Array[Byte]`` + - ``ByteString`` + - ``Array[Char]`` + - ``String`` + - ``akka.http.scaladsl.model.FormData`` + - ``akka.http.scaladsl.model.MessageEntity`` + - ``T <: akka.http.scaladsl.model.Multipart`` + +- PredefinedToResponseMarshallers_ + + - ``T``, if a ``ToEntityMarshaller[T]`` is available + - ``HttpResponse`` + - ``StatusCode`` + - ``(StatusCode, T)``, if a ``ToEntityMarshaller[T]`` is available + - ``(Int, T)``, if a ``ToEntityMarshaller[T]`` is available + - ``(StatusCode, immutable.Seq[HttpHeader], T)``, if a ``ToEntityMarshaller[T]`` is available + - ``(Int, immutable.Seq[HttpHeader], T)``, if a ``ToEntityMarshaller[T]`` is available + +- PredefinedToRequestMarshallers_ + + - ``HttpRequest`` + - ``Uri`` + - ``(HttpMethod, Uri, T)``, if a ``ToEntityMarshaller[T]`` is available + - ``(HttpMethod, Uri, immutable.Seq[HttpHeader], T)``, if a ``ToEntityMarshaller[T]`` is available + +- GenericMarshallers_ + + - ``Marshaller[Throwable, T]`` + - ``Marshaller[Option[A], B]``, if a ``Marshaller[A, B]`` and an ``EmptyValue[B]`` is available + - ``Marshaller[Either[A1, A2], B]``, if a ``Marshaller[A1, B]`` and a ``Marshaller[A2, B]`` is available + - ``Marshaller[Future[A], B]``, if a ``Marshaller[A, B]`` is available + - ``Marshaller[Try[A], B]``, if a ``Marshaller[A, B]`` is available + +.. _PredefinedToEntityMarshallers: @github@/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToEntityMarshallers.scala +.. _PredefinedToResponseMarshallers: @github@/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToResponseMarshallers.scala +.. _PredefinedToRequestMarshallers: @github@/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToRequestMarshallers.scala +.. _GenericMarshallers: @github@/akka-http/src/main/scala/akka/http/scaladsl/marshalling/GenericMarshallers.scala + + +Implicit Resolution +------------------- + +The marshalling infrastructure of Akka HTTP relies on a type-class based approach, which means that ``Marshaller`` +instances from a certain type ``A`` to a certain type ``B`` have to be available implicitly. + +The implicits for most of the predefined marshallers in Akka HTTP are provided through the companion object of the +``Marshaller`` trait. This means that they are always available and never need to be explicitly imported. +Additionally, you can simply "override" them by bringing your own custom version into local scope. + + +Custom Marshallers +------------------ + +Akka HTTP gives you a few convenience tools for constructing marshallers for your own types. +Before you do that you need to think about what kind of marshaller you want to create. +If all your marshaller needs to produce is a ``MessageEntity`` then you should probably provide a +``ToEntityMarshaller[T]``. The advantage here is that it will work on both the client- as well as the server-side since +a ``ToResponseMarshaller[T]`` as well as a ``ToRequestMarshaller[T]`` can automatically be created if a +``ToEntityMarshaller[T]`` is available. + +If, however, your marshaller also needs to set things like the response status code, the request method, the request URI +or any headers then a ``ToEntityMarshaller[T]`` won't work. You'll need to fall down to providing a +``ToResponseMarshaller[T]`` or a ``ToRequestMarshaller[T]`` directly. + +For writing you own marshallers you won't have to "manually" implement the ``Marshaller`` trait directly. +Rather, it should be possible to use one of the convenience construction helpers defined on the ``Marshaller`` +companion: + +.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/marshalling/Marshaller.scala + :snippet: marshaller-creation + + +Deriving Marshallers +-------------------- + +Sometimes you can save yourself some work by reusing existing marshallers for your custom ones. +The idea is to "wrap" an existing marshaller with some logic to "re-target" it to your type. + +In this regard wrapping a marshaller can mean one or both of the following two things: + +- Transform the input before it reaches the wrapped marshaller +- Transform the output of the wrapped marshaller + +For the latter (transforming the output) you can use ``baseMarshaller.map``, which works exactly as it does for functions. +For the former (transforming the input) you have four alternatives: + +- ``baseMarshaller.compose`` +- ``baseMarshaller.composeWithEC`` +- ``baseMarshaller.wrap`` +- ``baseMarshaller.wrapWithEC`` + +``compose`` works just like it does for functions. +``wrap`` is a compose that allows you to also change the ``ContentType`` that the marshaller marshals to. +The ``...WithEC`` variants allow you to receive an ``ExecutionContext`` internally if you need one, without having to +depend on one being available implicitly at the usage site. + + +Using Marshallers +----------------- + +In many places throughput Akka HTTP marshallers are used implicitly, e.g. when you define how to :ref:`-complete-` a +request using the :ref:`Routing DSL `. + +However, you can also use the marshalling infrastructure directly if you wish, which can be useful for example in tests. +The best entry point for this is the ``akka.http.scaladsl.marshalling.Marshal`` object, which you can use like this: + +.. includecode2:: ../../code/docs/http/scaladsl/MarshalSpec.scala + :snippet: use marshal diff --git a/akka-docs-dev/rst/scala/http/common/unmarshalling.rst b/akka-docs-dev/rst/scala/http/common/unmarshalling.rst index cc80ec53cc..9f6426335c 100644 --- a/akka-docs-dev/rst/scala/http/common/unmarshalling.rst +++ b/akka-docs-dev/rst/scala/http/common/unmarshalling.rst @@ -3,4 +3,117 @@ Unmarshalling ============= -... \ No newline at end of file +"Unmarshalling" is the process of converting some kind of a lower-level representation, often a "wire format", into a +higher-level (object) structure. Other popular names for it are "Deserialization" or "Unpickling". + +In Akka HTTP "Unmarshalling" means the conversion of a lower-level source object, e.g. a ``MessageEntity`` +(which forms the "entity body" of an HTTP request or response) or a full ``HttpRequest`` or ``HttpResponse``, +into an instance of type ``T``. + + +Basic Design +------------ + +Unmarshalling of instances of type ``A`` into instances of type ``B`` is performed by an ``Unmarshaller[A, B]``. +Akka HTTP also predefines a number of helpful aliases for the types of unmarshallers that you'll likely work with most: + +.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/package.scala + :snippet: unmarshaller-aliases + +At its core an ``Unmarshaller[A, B]`` is very similar to a function ``A => Future[B]`` and as such quite a bit simpler +than its :ref:`marshalling ` counterpart. The process of unmarshalling does not have to support +content negotiation which saves two additional layers of indirection that are required on the marshalling side. + + +Predefined Unmarshallers +------------------------ + +Akka HTTP already predefines a number of marshallers for the most common types. +Specifically these are: + +- PredefinedFromStringUnmarshallers_ + + - ``Byte`` + - ``Short`` + - ``Int`` + - ``Long`` + - ``Float`` + - ``Double`` + - ``Boolean`` + +- PredefinedFromEntityUnmarshallers_ + + - ``Array[Byte]`` + - ``ByteString`` + - ``Array[Char]`` + - ``String`` + - ``akka.http.scaladsl.model.FormData`` + +- GenericUnmarshallers_ + + - ``Unmarshaller[T, T]`` (identity unmarshaller) + - ``Unmarshaller[Option[A], B]``, if an ``Unmarshaller[A, B]`` is available + - ``Unmarshaller[A, Option[B]]``, if an ``Unmarshaller[A, B]`` is available + +.. _PredefinedFromStringUnmarshallers: @github@/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/PredefinedFromStringUnmarshallers.scala +.. _PredefinedFromEntityUnmarshallers: @github@/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/PredefinedFromEntityUnmarshallers.scala +.. _GenericUnmarshallers: @github@/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/GenericUnmarshallers.scala + + +Implicit Resolution +------------------- + +The unmarshalling infrastructure of Akka HTTP relies on a type-class based approach, which means that ``Unmarshaller`` +instances from a certain type ``A`` to a certain type ``B`` have to be available implicitly. + +The implicits for most of the predefined unmarshallers in Akka HTTP are provided through the companion object of the +``Unmarshaller`` trait. This means that they are always available and never need to be explicitly imported. +Additionally, you can simply "override" them by bringing your own custom version into local scope. + + +Custom Unmarshallers +-------------------- + +Akka HTTP gives you a few convenience tools for constructing unmarshallers for your own types. +Usually you won't have to "manually" implement the ``Unmarshaller`` trait directly. +Rather, it should be possible to use one of the convenience construction helpers defined on the ``Marshaller`` +companion: + +.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/Unmarshaller.scala + :snippet: unmarshaller-creation + + +Deriving Unmarshallers +---------------------- + +Sometimes you can save yourself some work by reusing existing unmarshallers for your custom ones. +The idea is to "wrap" an existing unmarshaller with some logic to "re-target" it to your type. + +Usually what you want to do is to transform the output of some existing unmarshaller and convert it to your type. +For this type of unmarshaller transformation Akka HTTP defines these methods: + +- ``baseUnmarshaller.transform`` +- ``baseUnmarshaller.map`` +- ``baseUnmarshaller.mapWithInput`` +- ``baseUnmarshaller.flatMap`` +- ``baseUnmarshaller.flatMapWithInput`` +- ``baseUnmarshaller.recover`` +- ``baseUnmarshaller.withDefaultValue`` +- ``baseUnmarshaller.mapWithCharset`` (only available for FromEntityUnmarshallers) +- ``baseUnmarshaller.forContentTypes`` (only available for FromEntityUnmarshallers) + +The method signatures should make their semantics relatively clear. + + +Using Unmarshallers +------------------- + +In many places throughput Akka HTTP unmarshallers are used implicitly, e.g. when you want to access the :ref:`-entity-` +of a request using the :ref:`Routing DSL `. + +However, you can also use the unmarshalling infrastructure directly if you wish, which can be useful for example in tests. +The best entry point for this is the ``akka.http.scaladsl.unmarshalling.Unmarshal`` object, which you can use like this: + +.. includecode2:: ../../code/docs/http/scaladsl/UnmarshalSpec.scala + :snippet: use unmarshal + diff --git a/akka-docs-dev/rst/scala/http/common/xml-support.rst b/akka-docs-dev/rst/scala/http/common/xml-support.rst index 5c5b0b2581..6183889999 100644 --- a/akka-docs-dev/rst/scala/http/common/xml-support.rst +++ b/akka-docs-dev/rst/scala/http/common/xml-support.rst @@ -1,4 +1,29 @@ XML Support =========== -... \ No newline at end of file +Akka HTTP's :ref:`marshalling ` and :ref:`unmarshalling ` +infrastructure makes it rather easy to seamlessly support specific wire representations of your data objects, like JSON, +XML or even binary encodings. + +For XML Akka HTTP currently provides support for `Scala XML`_ right out of the box through it's +``akka-http-xml`` module. + + +Scala XML Support +----------------- + +The ScalaXmlSupport_ trait provides a ``FromEntityUnmarshaller[NodeSeq]`` and ``ToEntityMarshaller[NodeSeq]`` that +you can use directly or build upon. + +This is how you enable support for (un)marshalling from and to JSON with `Scala XML`_ ``NodeSeq``: + +1. Add a library dependency onto ``"com.typesafe.akka" %% "akka-http-xml-experimental" % "1.x"``. + +2. ``import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._`` or mix in the + ``akka.http.scaladsl.marshallers.xml.ScalaXmlSupport`` trait. + +Once you have done this (un)marshalling between XML and ``NodeSeq`` instances should work nicely and transparently. + + +.. _Scala XML: https://github.com/scala/scala-xml +.. _ScalaXmlSupport: @github@/akka-http-marshallers-scala/akka-http-xml/src/main/scala/akka/http/scaladsl/marshallers/xml/ScalaXmlSupport.scala \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/low-level-server-side-api.rst b/akka-docs-dev/rst/scala/http/low-level-server-side-api.rst index 0fcc13055f..d664578786 100644 --- a/akka-docs-dev/rst/scala/http/low-level-server-side-api.rst +++ b/akka-docs-dev/rst/scala/http/low-level-server-side-api.rst @@ -154,4 +154,16 @@ If defined encryption is enabled on all accepted connections. Otherwise it is di Stand-Alone HTTP Layer Usage ---------------------------- -// TODO \ No newline at end of file +Due to its Reactive-Stream-based nature the Akka HTTP layer is fully detachable from the underlying TCP +interface. While in most applications this "feature" will not be crucial it can be useful in certain cases to be able +to "run" the HTTP layer (and, potentially, higher-layers) against data that do not come from the network but rather +some other source. Potential scenarios where this might be useful include tests, debugging or low-level event-sourcing +(e.g by replaying network traffic). + +On the server-side the stand-alone HTTP layer forms a ``BidiStage`` that is defined like this: + +.. includecode2:: /../../akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala + :snippet: server-layer + +You create an instance of ``Http.ServerLayer`` by calling one of the two overloads of the ``Http().serverLayer`` method, +which also allows for varying degrees of configuration. \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withMaterializer.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withMaterializer.rst index a7890d74a8..aedd752552 100644 --- a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withMaterializer.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withMaterializer.rst @@ -1,7 +1,7 @@ .. _-withMaterializer-: withMaterializer -==================== +================ ... diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/index.rst index 8342283170..75ffef7869 100644 --- a/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/index.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/index.rst @@ -26,7 +26,7 @@ other mechanism. After authentication the system believes that it knows who the most cases, in order to be able to authorize a user (i.e. allow access to some part of the system) the users identity must already have been established, i.e. he/she must have been authenticated. Without prior authentication the authorization would have to be very crude, e.g. "allow access for *all* users" or "allow access for *noone*". Only after -authentication will it be possible to, e.g., "allow access to the statistics resource for _admins_, but not for regular +authentication will it be possible to, e.g., "allow access to the statistics resource for *admins*, but not for regular *members*". Authentication and authorization may happen at the same time, e.g. when everyone who can properly be authenticated is @@ -35,5 +35,17 @@ system might have one mechanism for authentication (e.g. establishing user ident for authorization (e.g. a database lookup for retrieving user access rights). -// TODO: Explain the role of HTTP in this picture (as in, the methods listed here map to HTTP, but there is no general -purpose AAA solution provided here) \ No newline at end of file +Authentication and Authorization in HTTP +---------------------------------------- + +HTTP provides a general framework for access control and authentication, via an extensible set of challenge-response +authentication schemes, which can be used by a server to challenge a client request and by a client to provide +authentication information. The general mechanism is defined in `RFC 7235`_. + +The "HTTP Authentication Scheme Registry" defines the namespace for the authentication schemes in challenges and +credentials. You can see the currently registered schemes at http://www.iana.org/assignments/http-authschemes. + +At this point Akka HTTP only implements the "'Basic' HTTP Authentication Scheme" whose most current specification can be +found here: https://datatracker.ietf.org/doc/draft-ietf-httpauth-basicauth-update/. + +.. _RFC 7235: http://tools.ietf.org/html/rfc7235 \ No newline at end of file diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala index 12cc38d616..8f5b20189a 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala @@ -140,19 +140,7 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E log: LoggingAdapter = system.log)(implicit fm: Materializer): Future[ServerBinding] = bindAndHandle(Flow[HttpRequest].mapAsync(parallelism)(handler), interface, port, settings, httpsContext, log) - /** - * The type of the server-side HTTP layer as a stand-alone BidiStage - * that can be put atop the TCP layer to form an HTTP server. - * - * {{{ - * +------+ - * HttpResponse ~>| |~> SslTlsOutbound - * | bidi | - * HttpRequest <~| |<~ SslTlsInbound - * +------+ - * }}} - */ - type ServerLayer = BidiFlow[HttpResponse, SslTlsOutbound, SslTlsInbound, HttpRequest, Unit] + type ServerLayer = Http.ServerLayer /** * Constructs a [[ServerLayer]] stage using the configured default [[ServerSettings]]. The returned [[BidiFlow]] @@ -207,19 +195,7 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E } } - /** - * The type of the client-side HTTP layer as a stand-alone BidiStage - * that can be put atop the TCP layer to form an HTTP client. - * - * {{{ - * +------+ - * HttpRequest ~>| |~> SslTlsOutbound - * | bidi | - * HttpResponse <~| |<~ SslTlsInbound - * +------+ - * }}} - */ - type ClientLayer = BidiFlow[HttpRequest, SslTlsOutbound, SslTlsInbound, HttpResponse, Unit] + type ClientLayer = Http.ClientLayer /** * Constructs a [[ClientLayer]] stage using the configured default [[ClientConnectionSettings]]. @@ -502,6 +478,38 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E object Http extends ExtensionId[HttpExt] with ExtensionIdProvider { + //#server-layer + /** + * The type of the server-side HTTP layer as a stand-alone BidiStage + * that can be put atop the TCP layer to form an HTTP server. + * + * {{{ + * +------+ + * HttpResponse ~>| |~> SslTlsOutbound + * | bidi | + * HttpRequest <~| |<~ SslTlsInbound + * +------+ + * }}} + */ + type ServerLayer = BidiFlow[HttpResponse, SslTlsOutbound, SslTlsInbound, HttpRequest, Unit] + //# + + //#client-layer + /** + * The type of the client-side HTTP layer as a stand-alone BidiStage + * that can be put atop the TCP layer to form an HTTP client. + * + * {{{ + * +------+ + * HttpRequest ~>| |~> SslTlsOutbound + * | bidi | + * HttpResponse <~| |<~ SslTlsInbound + * +------+ + * }}} + */ + type ClientLayer = BidiFlow[HttpRequest, SslTlsOutbound, SslTlsInbound, HttpResponse, Unit] + //# + /** * Represents a prospective HTTP server binding. * diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/HttpEntity.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/HttpEntity.scala index 10e46759c3..9a78d86198 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/HttpEntity.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/HttpEntity.scala @@ -115,13 +115,23 @@ sealed trait HttpEntity extends jm.HttpEntity { sealed trait BodyPartEntity extends HttpEntity with jm.BodyPartEntity { def withContentType(contentType: ContentType): BodyPartEntity } -/* An entity that can be used for requests */ + +/** + * An [[HttpEntity]] that can be used for requests. + * Note that all entities that can be used for requests can also be used for responses. + * (But not the other way around, since [[HttpEntity.CloseDelimited]] can only be used for responses!) + */ sealed trait RequestEntity extends HttpEntity with jm.RequestEntity with ResponseEntity { def withContentType(contentType: ContentType): RequestEntity override def transformDataBytes(transformer: Flow[ByteString, ByteString, Any]): RequestEntity } -/* An entity that can be used for responses */ + +/** + * An [[HttpEntity]] that can be used for responses. + * Note that all entities that can be used for requests can also be used for responses. + * (But not the other way around, since [[HttpEntity.CloseDelimited]] can only be used for responses!) + */ sealed trait ResponseEntity extends HttpEntity with jm.ResponseEntity { def withContentType(contentType: ContentType): ResponseEntity diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/Multipart.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/Multipart.scala index cf9619b36a..346f90cd22 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/Multipart.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/Multipart.scala @@ -21,7 +21,7 @@ import akka.http.scaladsl.model.headers._ import akka.http.impl.engine.rendering.BodyPartRenderer import FastFuture._ -trait Multipart { +sealed trait Multipart { def mediaType: MultipartMediaType def parts: Source[Multipart.BodyPart, Any] diff --git a/akka-http/src/main/scala/akka/http/scaladsl/marshalling/Marshaller.scala b/akka-http/src/main/scala/akka/http/scaladsl/marshalling/Marshaller.scala index b0c71ef260..6d8e930786 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/marshalling/Marshaller.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/marshalling/Marshaller.scala @@ -63,6 +63,7 @@ sealed abstract class Marshaller[-A, +B] { Marshaller(implicit ec ⇒ c ⇒ apply(f(ec)(c))) } +//# marshaller-creation object Marshaller extends GenericMarshallers with PredefinedToEntityMarshallers @@ -117,7 +118,9 @@ object Marshaller def opaque[A, B](marshal: A ⇒ B): Marshaller[A, B] = strict { value ⇒ Marshalling.Opaque(() ⇒ marshal(value)) } } +//# +//# marshalling /** * Describes one possible option for marshalling a given value. */ @@ -151,3 +154,4 @@ object Marshalling { def map[B](f: A ⇒ B): Opaque[B] = copy(marshal = () ⇒ f(marshal())) } } +//# \ No newline at end of file diff --git a/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToEntityMarshallers.scala b/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToEntityMarshallers.scala index da7cce221e..42ca0cf716 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToEntityMarshallers.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/marshalling/PredefinedToEntityMarshallers.scala @@ -58,7 +58,7 @@ trait PredefinedToEntityMarshallers extends MultipartMarshallers { HttpEntity(ContentType(`application/x-www-form-urlencoded`, charset), string) } - implicit val HttpEntityMarshaller: ToEntityMarshaller[MessageEntity] = Marshaller strict { value ⇒ + implicit val MessageEntityMarshaller: ToEntityMarshaller[MessageEntity] = Marshaller strict { value ⇒ Marshalling.WithFixedCharset(value.contentType.mediaType, value.contentType.charset, () ⇒ value) } } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/marshalling/package.scala b/akka-http/src/main/scala/akka/http/scaladsl/marshalling/package.scala index ff2d855736..c218f07f28 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/marshalling/package.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/marshalling/package.scala @@ -8,8 +8,10 @@ import scala.collection.immutable import akka.http.scaladsl.model._ package object marshalling { + //# marshaller-aliases type ToEntityMarshaller[T] = Marshaller[T, MessageEntity] type ToHeadersAndEntityMarshaller[T] = Marshaller[T, (immutable.Seq[HttpHeader], MessageEntity)] type ToResponseMarshaller[T] = Marshaller[T, HttpResponse] type ToRequestMarshaller[T] = Marshaller[T, HttpRequest] + //# } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/Unmarshaller.scala b/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/Unmarshaller.scala index 8ec4080458..1ff02b700e 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/Unmarshaller.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/Unmarshaller.scala @@ -35,6 +35,9 @@ object Unmarshaller with PredefinedFromEntityUnmarshallers with PredefinedFromStringUnmarshallers { + // format: OFF + + //#unmarshaller-creation /** * Creates an `Unmarshaller` from the given function. */ @@ -55,18 +58,20 @@ object Unmarshaller * in the given order. The first successful unmarshalling of a "sub-unmarshallers" is the one produced by the * "super-unmarshaller". */ - def firstOf[A, B](unmarshallers: Unmarshaller[A, B]*): Unmarshaller[A, B] = - Unmarshaller { implicit ec ⇒ - a ⇒ - def rec(ix: Int, supported: Set[ContentTypeRange]): Future[B] = - if (ix < unmarshallers.size) { - unmarshallers(ix)(a).fast.recoverWith { - case Unmarshaller.UnsupportedContentTypeException(supp) ⇒ rec(ix + 1, supported ++ supp) - } - } else FastFuture.failed(Unmarshaller.UnsupportedContentTypeException(supported)) - rec(0, Set.empty) + def firstOf[A, B](unmarshallers: Unmarshaller[A, B]*): Unmarshaller[A, B] = //... + //# + Unmarshaller { implicit ec ⇒ a ⇒ + def rec(ix: Int, supported: Set[ContentTypeRange]): Future[B] = + if (ix < unmarshallers.size) { + unmarshallers(ix)(a).fast.recoverWith { + case Unmarshaller.UnsupportedContentTypeException(supp) ⇒ rec(ix + 1, supported ++ supp) + } + } else FastFuture.failed(Unmarshaller.UnsupportedContentTypeException(supported)) + rec(0, Set.empty) } + // format: ON + implicit def identityUnmarshaller[T]: Unmarshaller[T, T] = Unmarshaller(_ ⇒ FastFuture.successful) // we don't define these methods directly on `Unmarshaller` due to variance constraints diff --git a/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/package.scala b/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/package.scala index 79b4ecf3d5..f0b56e89a7 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/package.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/package.scala @@ -8,10 +8,12 @@ import akka.http.scaladsl.common.StrictForm import akka.http.scaladsl.model._ package object unmarshalling { + //# unmarshaller-aliases type FromEntityUnmarshaller[T] = Unmarshaller[HttpEntity, T] type FromMessageUnmarshaller[T] = Unmarshaller[HttpMessage, T] type FromResponseUnmarshaller[T] = Unmarshaller[HttpResponse, T] type FromRequestUnmarshaller[T] = Unmarshaller[HttpRequest, T] type FromStringUnmarshaller[T] = Unmarshaller[String, T] type FromStrictFormFieldUnmarshaller[T] = Unmarshaller[StrictForm.Field, T] + //# }