diff --git a/akka-docs/rst/scala/code/docs/http/scaladsl/HttpServerExampleSpec.scala b/akka-docs/rst/scala/code/docs/http/scaladsl/HttpServerExampleSpec.scala
index acd403ac11..4500faaa55 100644
--- a/akka-docs/rst/scala/code/docs/http/scaladsl/HttpServerExampleSpec.scala
+++ b/akka-docs/rst/scala/code/docs/http/scaladsl/HttpServerExampleSpec.scala
@@ -4,7 +4,7 @@
package docs.http.scaladsl
-import akka.actor.{ ActorRef, ActorSystem }
+import akka.actor.{ Props, ActorRef, ActorSystem }
import akka.event.LoggingAdapter
import akka.http.scaladsl.Http
import akka.http.scaladsl.Http.ServerBinding
@@ -13,6 +13,7 @@ import akka.stream.ActorMaterializer
import akka.stream.scaladsl.{ Flow, Sink }
import akka.testkit.TestActors
import org.scalatest.{ Matchers, WordSpec }
+import scala.io.StdIn
import scala.language.postfixOps
import scala.concurrent.{ ExecutionContext, Future }
@@ -31,7 +32,7 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
- implicit val ec = system.dispatcher
+ implicit val executionContext = system.dispatcher
val serverSource: Source[Http.IncomingConnection, Future[Http.ServerBinding]] =
Http().bind(interface = "localhost", port = 8080)
@@ -49,7 +50,8 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
- implicit val ec = system.dispatcher
+ // needed for the future onFailure in the end
+ implicit val executionContext = system.dispatcher
val handler = get {
complete("Hello world!")
@@ -60,7 +62,7 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
val bindingFuture: Future[ServerBinding] =
Http().bindAndHandle(handler, host, port)
- bindingFuture onFailure {
+ bindingFuture.onFailure {
case ex: Exception =>
log.error(ex, "Failed to bind to {}:{}!", host, port)
}
@@ -74,7 +76,8 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
"binding-failure-handling" in compileOnlySpec {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
- implicit val ec = system.dispatcher
+ // needed for the future onFailure in the end
+ implicit val executionContext = system.dispatcher
// let's say the OS won't allow us to bind to 80.
val (host, port) = ("localhost", 80)
@@ -84,7 +87,7 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
.to(handleConnections) // Sink[Http.IncomingConnection, _]
.run()
- bindingFuture onFailure {
+ bindingFuture.onFailure {
case ex: Exception =>
log.error(ex, "Failed to bind to {}:{}!", host, port)
}
@@ -97,7 +100,7 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
"incoming-connections-source-failure-handling" in compileOnlySpec {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
- implicit val ec = system.dispatcher
+ implicit val executionContext = system.dispatcher
import Http._
val (host, port) = ("localhost", 8080)
@@ -119,7 +122,7 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
"connection-stream-failure-handling" in compileOnlySpec {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
- implicit val ec = system.dispatcher
+ implicit val executionContext = system.dispatcher
val (host, port) = ("localhost", 8080)
val serverSource = Http().bind(host, port)
@@ -153,6 +156,7 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
+ implicit val executionContext = system.dispatcher
val serverSource = Http().bind(interface = "localhost", port = 8080)
@@ -186,87 +190,110 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
import akka.http.scaladsl.model.HttpMethods._
import akka.http.scaladsl.model._
import akka.stream.ActorMaterializer
+ import scala.io.StdIn
- implicit val system = ActorSystem()
- implicit val materializer = ActorMaterializer()
+ object WebServer {
- val requestHandler: HttpRequest => HttpResponse = {
- case HttpRequest(GET, Uri.Path("/"), _, _, _) =>
- HttpResponse(entity = HttpEntity(ContentTypes.`text/html(UTF-8)`,
- "
Hello world!"))
+ def main(args: Array[String]) {
+ implicit val system = ActorSystem()
+ implicit val materializer = ActorMaterializer()
+ // needed for the future map/flatmap in the end
+ implicit val executionContext = system.dispatcher
- case HttpRequest(GET, Uri.Path("/ping"), _, _, _) =>
- HttpResponse(entity = "PONG!")
+ val requestHandler: HttpRequest => HttpResponse = {
+ case HttpRequest(GET, Uri.Path("/"), _, _, _) =>
+ HttpResponse(entity = HttpEntity(ContentTypes.`text/html(UTF-8)`,
+ "Hello world!"))
- case HttpRequest(GET, Uri.Path("/crash"), _, _, _) =>
- sys.error("BOOM!")
+ case HttpRequest(GET, Uri.Path("/ping"), _, _, _) =>
+ HttpResponse(entity = "PONG!")
- case _: HttpRequest =>
- HttpResponse(404, entity = "Unknown resource!")
+ case HttpRequest(GET, Uri.Path("/crash"), _, _, _) =>
+ sys.error("BOOM!")
+
+ case _: HttpRequest =>
+ HttpResponse(404, entity = "Unknown resource!")
+ }
+
+ val bindingFuture = Http().bindAndHandleSync(requestHandler, "localhost", 8080)
+ println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
+ StdIn.readLine() // let it run until user presses return
+ bindingFuture
+ .flatMap(_.unbind()) // trigger unbinding from the port
+ .onComplete(_ ⇒ system.terminate()) // and shutdown when done
+
+ }
}
-
- Http().bindAndHandleSync(requestHandler, "localhost", 8080)
}
// format: OFF
"high-level-server-example" in compileOnlySpec {
import akka.http.scaladsl.Http
- import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
+ import scala.io.StdIn
- implicit val system = ActorSystem()
- implicit val materializer = ActorMaterializer()
+ object WebServer {
+ def main(args: Array[String]) {
+ implicit val system = ActorSystem()
+ implicit val materializer = ActorMaterializer()
+ // needed for the future flatMap/onComplete in the end
+ implicit val executionContext = system.dispatcher
- val route =
- get {
- pathSingleSlash {
- complete {
-
- Hello world!
-
+ val route =
+ get {
+ pathSingleSlash {
+ complete(HttpEntity(ContentTypes.`text/html(UTF-8)`,"Hello world!"))
+ } ~
+ path("ping") {
+ complete("PONG!")
+ } ~
+ path("crash") {
+ sys.error("BOOM!")
+ }
}
- } ~
- path("ping") {
- complete("PONG!")
- } ~
- path("crash") {
- sys.error("BOOM!")
- }
- }
- // `route` will be implicitly converted to `Flow` using `RouteResult.route2HandlerFlow`
- Http().bindAndHandle(route, "localhost", 8080)
+ // `route` will be implicitly converted to `Flow` using `RouteResult.route2HandlerFlow`
+ val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
+ println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
+ StdIn.readLine() // let it run until user presses return
+ bindingFuture
+ .flatMap(_.unbind()) // trigger unbinding from the port
+ .onComplete(_ ⇒ system.terminate()) // and shutdown when done
+ }
+ }
}
"minimal-routing-example" in compileOnlySpec {
import akka.http.scaladsl.Http
- import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._
import akka.http.scaladsl.server.Directives._
import akka.stream.ActorMaterializer
+ import scala.io.StdIn
- object Main extends App {
- implicit val system = ActorSystem("my-system")
- implicit val materializer = ActorMaterializer()
- implicit val ec = system.dispatcher
+ object WebServer {
+ def main(args: Array[String]) {
- val route =
- path("hello") {
- get {
- complete {
- Say hello to akka-http
+ implicit val system = ActorSystem("my-system")
+ implicit val materializer = ActorMaterializer()
+ // needed for the future flatMap/onComplete in the end
+ implicit val executionContext = system.dispatcher
+
+ val route =
+ path("hello") {
+ get {
+ complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "Say hello to akka-http
"))
}
}
- }
- val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
+ val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
- println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
- Console.readLine() // for the future transformations
- bindingFuture
- .flatMap(_.unbind()) // trigger unbinding from the port
- .onComplete(_ ⇒ system.terminate()) // and shutdown when done
+ println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
+ StdIn.readLine() // let it run until user presses return
+ bindingFuture
+ .flatMap(_.unbind()) // trigger unbinding from the port
+ .onComplete(_ ⇒ system.terminate()) // and shutdown when done
+ }
}
}
@@ -380,4 +407,121 @@ class HttpServerExampleSpec extends WordSpec with Matchers {
}
}
}
+
+ "stream random numbers" in compileOnlySpec {
+ //#stream-random-numbers
+ import akka.stream.scaladsl._
+ import akka.util.ByteString
+ import akka.http.scaladsl.Http
+ import akka.http.scaladsl.model.{HttpEntity, ContentTypes}
+ import akka.http.scaladsl.server.Directives._
+ import akka.stream.ActorMaterializer
+ import scala.util.Random
+ import scala.io.StdIn
+
+ object WebServer {
+
+ def main(args: Array[String]) {
+
+ implicit val system = ActorSystem()
+ implicit val materializer = ActorMaterializer()
+ // needed for the future flatMap/onComplete in the end
+ implicit val executionContext = system.dispatcher
+
+ // streams are re-usable so we can define it here
+ // and use it for every request
+ val numbers = Source.fromIterator(() =>
+ Iterator.continually(Random.nextInt()))
+
+ val route =
+ path("random") {
+ get {
+ complete(
+ HttpEntity(
+ ContentTypes.`text/plain(UTF-8)`,
+ // transform each number to a chunk of bytes
+ numbers.map(n => ByteString(s"$n\n"))
+ )
+ )
+ }
+ }
+
+ val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
+ println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
+ StdIn.readLine() // let it run until user presses return
+ bindingFuture
+ .flatMap(_.unbind()) // trigger unbinding from the port
+ .onComplete(_ ⇒ system.terminate()) // and shutdown when done
+ }
+ }
+ //#stream-random-numbers
+ }
+
+
+ object Auction {
+ def props: Props = ???
+ }
+
+ "interact with an actor" in compileOnlySpec {
+ //#actor-interaction
+ import scala.concurrent.duration._
+ import akka.util.Timeout
+ import akka.pattern.ask
+ import akka.actor.ActorSystem
+ import akka.stream.ActorMaterializer
+ import akka.http.scaladsl.Http
+ import akka.http.scaladsl.server.Directives._
+ import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
+ import spray.json.DefaultJsonProtocol._
+ import scala.io.StdIn
+
+ object WebServer {
+
+ case class Bid(userId: String, bid: Int)
+ case object GetBids
+ case class Bids(bids: List[Bid])
+
+ // these are from spray-json
+ implicit val bidFormat = jsonFormat2(Bid)
+ implicit val bidsFormat = jsonFormat1(Bids)
+
+ def main(args: Array[String]) {
+ implicit val system = ActorSystem()
+ implicit val materializer = ActorMaterializer()
+ // needed for the future flatMap/onComplete in the end
+ implicit val executionContext = system.dispatcher
+
+ val auction = system.actorOf(Auction.props, "auction")
+
+ val route =
+ path("auction") {
+ put {
+ parameter("bid".as[Int], "user") { (bid, user) =>
+ // place a bid, fire-and-forget
+ auction ! Bid(user, bid)
+ complete(StatusCodes.Accepted, "bid placed")
+ }
+ }
+ get {
+ implicit val timeout: Timeout = 5.seconds
+
+ // query the actor for the current auction state
+ val bids: Future[Bids] = (auction ? GetBids).mapTo[Bids]
+ complete(bids)
+ }
+ }
+
+ val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
+ println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
+ StdIn.readLine() // let it run until user presses return
+ bindingFuture
+ .flatMap(_.unbind()) // trigger unbinding from the port
+ .onComplete(_ ⇒ system.terminate()) // and shutdown when done
+
+ }
+ }
+ //#actor-interaction
+ }
+
+
}
diff --git a/akka-docs/rst/scala/code/docs/http/scaladsl/SprayJsonExampleSpec.scala b/akka-docs/rst/scala/code/docs/http/scaladsl/SprayJsonExampleSpec.scala
index d37e944e0f..fe5208a5f2 100644
--- a/akka-docs/rst/scala/code/docs/http/scaladsl/SprayJsonExampleSpec.scala
+++ b/akka-docs/rst/scala/code/docs/http/scaladsl/SprayJsonExampleSpec.scala
@@ -8,9 +8,13 @@ import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import akka.http.scaladsl.server.Directives
import org.scalatest.{ Matchers, WordSpec }
+import scala.concurrent.Future
+
class SprayJsonExampleSpec extends WordSpec with Matchers {
- "spray-json example" in {
+ def compileOnlySpec(body: => Unit) = ()
+
+ "spray-json example" in compileOnlySpec {
//#example
import spray.json._
@@ -31,9 +35,7 @@ class SprayJsonExampleSpec extends WordSpec with Matchers {
val route =
get {
pathSingleSlash {
- complete {
- Item("thing", 42) // will render as JSON
- }
+ complete(Item("thing", 42)) // will render as JSON
}
} ~
post {
@@ -47,4 +49,63 @@ class SprayJsonExampleSpec extends WordSpec with Matchers {
//#
}
}
+
+ "second-spray-json-example" in compileOnlySpec {
+ //#second-spray-json-example
+ import akka.actor.ActorSystem
+ import akka.stream.ActorMaterializer
+ import akka.Done
+ import akka.http.scaladsl.server.Route
+ import akka.http.scaladsl.server.Directives._
+ import akka.http.scaladsl.model.StatusCodes
+ import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
+ import spray.json.DefaultJsonProtocol._
+
+ object WebServer {
+
+ // domain model
+ final case class Item(name: String, id: Long)
+ final case class Order(items: List[Item])
+
+ // formats for unmarshalling and marshalling
+ implicit val itemFormat = jsonFormat2(Item)
+ implicit val orderFormat = jsonFormat1(Order)
+
+ // (fake) async database query api
+ def fetchItem(itemId: Long): Future[Option[Item]] = ???
+ def saveOrder(order: Order): Future[Done] = ???
+
+ def main(args: Array[String]) {
+
+ // needed to run the route
+ implicit val system = ActorSystem()
+ implicit val materializer = ActorMaterializer()
+
+ val route: Route =
+ get {
+ pathPrefix("item" / LongNumber) { id =>
+ // there might be no item for a given id
+ val maybeItem: Future[Option[Item]] = fetchItem(id)
+
+ onSuccess(maybeItem) {
+ case Some(item) => complete(item)
+ case None => complete(StatusCodes.NotFound)
+ }
+ }
+ } ~
+ post {
+ path("create-order") {
+ entity(as[Order]) { order =>
+ val saved: Future[Done] = saveOrder(order)
+ onComplete(saved) { done =>
+ complete("order created")
+ }
+ }
+ }
+ }
+
+ }
+ }
+ //#second-spray-json-example
+ }
}
\ No newline at end of file
diff --git a/akka-docs/rst/scala/http/common/json-support.rst b/akka-docs/rst/scala/http/common/json-support.rst
index d6ae1235ee..893c3fd8d1 100644
--- a/akka-docs/rst/scala/http/common/json-support.rst
+++ b/akka-docs/rst/scala/http/common/json-support.rst
@@ -1,3 +1,5 @@
+.. _akka-http-spray-json:
+
JSON Support
============
diff --git a/akka-docs/rst/scala/http/common/xml-support.rst b/akka-docs/rst/scala/http/common/xml-support.rst
index 6183889999..32622c4905 100644
--- a/akka-docs/rst/scala/http/common/xml-support.rst
+++ b/akka-docs/rst/scala/http/common/xml-support.rst
@@ -1,3 +1,5 @@
+.. _akka-http-xml-marshalling:
+
XML Support
===========
diff --git a/akka-docs/rst/scala/http/introduction.rst b/akka-docs/rst/scala/http/introduction.rst
index c21cffbbbf..b95f7fcfc7 100644
--- a/akka-docs/rst/scala/http/introduction.rst
+++ b/akka-docs/rst/scala/http/introduction.rst
@@ -10,23 +10,129 @@ You get to pick the API level of abstraction that is most suitable for your appl
This means that, if you have trouble achieving something using a high-level API, there's a good chance that you can get
it done with a low-level API, which offers more flexibility but might require you to write more application code.
-Akka HTTP is structured into several modules:
+Using Akka HTTP
+---------------
+Akka HTTP is provided in separate jar files, to use it make sure to include the following dependencies::
-akka-http-core
- A complete, mostly low-level, server- and client-side implementation of HTTP (incl. WebSockets)
+ "com.typesafe.akka" %% "akka-http-core" % "@version@" @crossString@
+ "com.typesafe.akka" %% "akka-http-experimental" % "@version@" @crossString@
+
+
+Routing DSL for HTTP servers
+----------------------------
+The high-level, routing API of Akka HTTP provides a DSL to describe HTTP "routes" and how they should be handled.
+Each route is composed of one or more level of ``Directive`` s that narrows down to handling one specific type of
+request.
+
+For example one route might start with matching the ``path`` of the request, only matching if it is "/hello", then
+narrowing it down to only handle HTTP ``get`` requests and then ``complete`` those with a string literal, which
+will be sent back as a HTTP OK with the string as response body.
+
+Transforming request and response bodies between over-the-wire formats and objects to be used in your application is
+done separately from the route declarations, in marshallers, which are pulled in implicitly using the "magnet" pattern.
+This means that you can ``complete`` a request with any kind of object a as long as there is an implicit marshaller
+available in scope.
+
+Default marshallers are provided for simple objects like String or ByteString, and you can define your own for example
+for JSON. An additional module provides JSON serialization using the spray-json library (see :ref:`akka-http-spray-json`
+for details).
+
+The ``Route`` created using the Route DSL is then "bound" to a port to start serving HTTP requests:
+
+.. includecode2:: ../code/docs/http/scaladsl/HttpServerExampleSpec.scala
+ :snippet: minimal-routing-example
+
+A common use case is to reply to a request using a model object having the marshaller transform it into JSON. In
+this case shown by two separate routes. The first route queries an asynchronous database and marshalls the
+``Future[Option[Item]]`` result into a JSON response. The second unmarshalls an ``Order`` from the incoming request
+saves it to the database and replies with an OK when done.
+
+.. includecode2:: ../code/docs/http/scaladsl/SprayJsonExampleSpec.scala
+ :snippet: second-spray-json-example
+
+The logic for the marshalling and unmarshalling JSON in this example is provided by the "spray-json" library
+(details on how to use that here: :ref:`akka-http-spray-json`).
+
+One of the strengths of Akka HTTP is that streaming data is at its heart meaning that both request and response bodies
+can be streamed through the server achieving constant memory usage even for very large requests or responses. Streaming
+responses will be backpressured by the remote client so that the server will not push data faster than the client can
+handle, streaming requests means that the server decides how fast the remote client can push the data of the request
+body.
+
+Example that streams random numbers as long as the client accepts them:
+
+.. includecode:: ../code/docs/http/scaladsl/HttpServerExampleSpec.scala
+ :include: stream-random-numbers
+
+Connecting to this service with a slow HTTP client would backpressure so that the next random number is produced on
+demand with constant memory usage on the server. This can be seen using curl and limiting the rate
+``curl --limit-rate 50b 127.0.0.1:8080/random``
+
+
+Akka HTTP routes easily interacts with actors. In this example one route allows for placing bids in a fire-and-forget
+style while the second route contains a request-response interaction with an actor. The resulting response is rendered
+as json and returned when the response arrives from the actor.
+
+.. includecode:: ../code/docs/http/scaladsl/HttpServerExampleSpec.scala
+ :include: actor-interaction
+
+Again the logic for the marshalling and unmarshalling JSON in this example is provided by the "spray-json" library
+(details on how to use that here: :ref:`akka-http-spray-json`)
+
+
+Read more about the details of the high level APIs in the section :ref:`http-high-level-server-side-api`.
+
+Low-level HTTP server APIs
+--------------------------
+The low-level Akka HTTP server APIs allows for handling connections or individual requests by accepting
+``HttpRequest`` s and answering them by producing ``HttpResponse`` s. This is provided by the ``akka-http-core`` module.
+APIs for handling such request-responses as function calls and as a ``Flow[HttpRequest, HttpResponse, _]`` are available.
+
+.. includecode2:: ../code/docs/http/scaladsl/HttpServerExampleSpec.scala
+ :snippet: low-level-server-example
+
+Read more details about the low level APIs in the section :ref:`http-low-level-server-side-api`.
+
+
+HTTP client API
+---------------
+The client APIs provide methods for calling a HTTP server using the same ``HttpRequest`` and ``HttpResponse`` abstractions
+that Akka HTTP server uses but adds the concept of connection pools to allow multiple requests to the same server to be
+handled more performantly by re-using TCP connections to the server.
+
+Example simple request:
+
+.. includecode:: ../code/docs/http/scaladsl/HttpClientExampleSpec.scala
+ :include: single-request-example
+
+
+Read more about the details of the client APIs in the section :ref:`http-client-side`.
+
+
+
+The modules that make up Akka HTTP
+----------------------------------
+Akka HTTP is structured into several modules:
akka-http
Higher-level functionality, like (un)marshalling, (de)compression as well as a powerful DSL
- for defining HTTP-based APIs on the server-side
+ for defining HTTP-based APIs on the server-side, this is the recommended way to write HTTP servers
+ with Akka HTTP. Details can be found in the section :ref:`http-high-level-server-side-api`
+
+akka-http-core
+ A complete, mostly low-level, server- and client-side implementation of HTTP (incl. WebSockets)
+ Details can be found in sections :ref:`http-low-level-server-side-api` and :ref:`http-client-side`
akka-http-testkit
A test harness and set of utilities for verifying server-side service implementations
akka-http-spray-json
Predefined glue-code for (de)serializing custom types from/to JSON with spray-json_
+ Details can be found here: :ref:`akka-http-spray-json`
akka-http-xml
Predefined glue-code for (de)serializing custom types from/to XML with scala-xml_
+ Details can be found here: :ref:`akka-http-xml-marshalling`
.. _spray-json: https://github.com/spray/spray-json
.. _scala-xml: https://github.com/scala/scala-xml
\ No newline at end of file