=docs #18012 complete remaining TODO sections in scala HTTP docs
This commit is contained in:
parent
cf11eab9ae
commit
1441f201b1
19 changed files with 519 additions and 51 deletions
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
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!
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -68,4 +68,16 @@ However, akka-stream should soon provide such a feature.
|
|||
Stand-Alone HTTP Layer Usage
|
||||
----------------------------
|
||||
|
||||
// TODO
|
||||
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.
|
||||
|
|
@ -1,4 +1,16 @@
|
|||
Encoding / Decoding
|
||||
===================
|
||||
|
||||
...
|
||||
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 <http-high-level-server-side-api>` 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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,32 @@
|
|||
JSON Support
|
||||
============
|
||||
|
||||
...
|
||||
Akka HTTP's :ref:`marshalling <http-marshalling-scala>` and :ref:`unmarshalling <http-unmarshalling-scala>`
|
||||
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
|
||||
|
|
@ -3,4 +3,162 @@
|
|||
Marshalling
|
||||
===========
|
||||
|
||||
...
|
||||
"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 <http-high-level-server-side-api>`.
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -3,4 +3,117 @@
|
|||
Unmarshalling
|
||||
=============
|
||||
|
||||
...
|
||||
"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 <http-marshalling-scala>` 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 <http-high-level-server-side-api>`.
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,29 @@
|
|||
XML Support
|
||||
===========
|
||||
|
||||
...
|
||||
Akka HTTP's :ref:`marshalling <http-marshalling-scala>` and :ref:`unmarshalling <http-unmarshalling-scala>`
|
||||
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
|
||||
|
|
@ -154,4 +154,16 @@ If defined encryption is enabled on all accepted connections. Otherwise it is di
|
|||
Stand-Alone HTTP Layer Usage
|
||||
----------------------------
|
||||
|
||||
// TODO
|
||||
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.
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
.. _-withMaterializer-:
|
||||
|
||||
withMaterializer
|
||||
====================
|
||||
================
|
||||
|
||||
...
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
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
|
||||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
}
|
||||
}
|
||||
//#
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
//#
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
//#
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue