diff --git a/akka-docs-dev/rst/java/http/index.rst b/akka-docs-dev/rst/java/http/index.rst new file mode 100644 index 0000000000..99a1336ce9 --- /dev/null +++ b/akka-docs-dev/rst/java/http/index.rst @@ -0,0 +1,6 @@ +.. _http-java: + +Akka HTTP +========= + +... \ No newline at end of file diff --git a/akka-docs-dev/rst/java/stream-cookbook.rst b/akka-docs-dev/rst/java/stream-cookbook.rst new file mode 100644 index 0000000000..73be206f2e --- /dev/null +++ b/akka-docs-dev/rst/java/stream-cookbook.rst @@ -0,0 +1,14 @@ +.. _stream-cookbook-java: + +######## +Cookbook +######## + +TODO + +.. _cookbook-parse-lines-java: + +Parsing lines from a stream of ByteStrings +------------------------------------------ + +TODO \ No newline at end of file diff --git a/akka-docs-dev/rst/java/stream-flows-and-basics.rst b/akka-docs-dev/rst/java/stream-flows-and-basics.rst index bb1c6aab60..bfb1f1b809 100644 --- a/akka-docs-dev/rst/java/stream-flows-and-basics.rst +++ b/akka-docs-dev/rst/java/stream-flows-and-basics.rst @@ -194,7 +194,7 @@ and ``runWith()`` methods defined on flow elements as well as a small number of well-known sinks, such as ``runForeach(el -> )`` (being an alias to ``runWith(Sink.foreach(el -> ))``. Materialization is currently performed synchronously on the materializing thread. -Tha actual stream processing is handled by :ref:`Actors actor-java` started up during the streams materialization, +The actual stream processing is handled by actors started up during the streams materialization, which will be running on the thread pools they have been configured to run on - which defaults to the dispatcher set in :class:`MaterializationSettings` while constructing the :class:`ActorFlowMaterializer`. diff --git a/akka-docs-dev/rst/scala/code/docs/http/HttpServerExampleSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/HttpServerExampleSpec.scala deleted file mode 100644 index fe4550a6ec..0000000000 --- a/akka-docs-dev/rst/scala/code/docs/http/HttpServerExampleSpec.scala +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2009-2014 Typesafe Inc. - */ - -package docs.http - -import akka.actor.ActorSystem -import akka.http.scaladsl.model._ -import akka.stream.scaladsl._ -import akka.stream.testkit.AkkaSpec -import scala.concurrent.Future - -class HttpServerExampleSpec - extends AkkaSpec("akka.actor.default-mailbox.mailbox-type = akka.dispatch.UnboundedMailbox") { - def ActorSystem(): ActorSystem = system - - "binding example" in { - //#bind-example - import akka.http.scaladsl.Http - import akka.stream.ActorFlowMaterializer - - implicit val system = ActorSystem() - implicit val materializer = ActorFlowMaterializer() - - val serverSource: Source[Http.IncomingConnection, Future[Http.ServerBinding]] = - Http(system).bind(interface = "localhost", port = 8080) - val bindingFuture: Future[Http.ServerBinding] = serverSource.to(Sink.foreach { connection => - // foreach materializes the source - println("Accepted new connection from " + connection.remoteAddress) - // ... and then actually handle the connection - }).run() - //#bind-example - } - - "full-server-example" in { - import akka.http.scaladsl.Http - import akka.stream.ActorFlowMaterializer - - implicit val system = ActorSystem() - implicit val materializer = ActorFlowMaterializer() - - val serverSource = Http(system).bind(interface = "localhost", port = 8080) - - //#full-server-example - import akka.http.scaladsl.model.HttpMethods._ - import akka.stream.scaladsl.{ Flow, Sink } - - val requestHandler: HttpRequest => HttpResponse = { - case HttpRequest(GET, Uri.Path("/"), _, _, _) => - HttpResponse( - entity = HttpEntity(MediaTypes.`text/html`, - "Hello world!")) - - case HttpRequest(GET, Uri.Path("/ping"), _, _, _) => - HttpResponse(entity = "PONG!") - - case HttpRequest(GET, Uri.Path("/crash"), _, _, _) => - sys.error("BOOM!") - - case _: HttpRequest => - HttpResponse(404, entity = "Unknown resource!") - } - - val bindingFuture: Future[Http.ServerBinding] = serverSource.to(Sink.foreach { connection => - println("Accepted new connection from " + connection.remoteAddress) - - connection handleWithSyncHandler requestHandler - // this is equivalent to - // connection handleWith { Flow[HttpRequest] map requestHandler } - }).run() - //#full-server-example - } -} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/HttpClientExampleSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/HttpClientExampleSpec.scala new file mode 100644 index 0000000000..969f3e09f1 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/HttpClientExampleSpec.scala @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl + +import akka.actor.ActorSystem +import org.scalatest.{ Matchers, WordSpec } + +class HttpClientExampleSpec extends WordSpec with Matchers { + + "outgoing-connection-example" in { + pending // compile-time only test + //#outgoing-connection-example + import scala.concurrent.Future + import akka.stream.ActorFlowMaterializer + import akka.stream.scaladsl._ + import akka.http.scaladsl.model._ + import akka.http.scaladsl.Http + + implicit val system = ActorSystem() + implicit val materializer = ActorFlowMaterializer() + + val connectionFlow: Flow[HttpRequest, HttpResponse, Future[Http.OutgoingConnection]] = + Http().outgoingConnection("http://akka.io") + val responseFuture: Future[HttpResponse] = + Source.single(HttpRequest(uri = "/")) + .via(connectionFlow) + .runWith(Sink.head) + //#outgoing-connection-example + } + + "host-level-example" in { + pending // compile-time only test + //#host-level-example + import scala.concurrent.Future + import scala.util.Try + import akka.stream.ActorFlowMaterializer + import akka.stream.scaladsl._ + import akka.http.scaladsl.model._ + import akka.http.scaladsl.Http + + implicit val system = ActorSystem() + implicit val materializer = ActorFlowMaterializer() + + // construct a pool client flow with context type `Int` + val poolClientFlow = Http().cachedHostConnectionPool[Int]("http://akka.io") + val responseFuture: Future[(Try[HttpResponse], Int)] = + Source.single(HttpRequest(uri = "/") -> 42) + .via(poolClientFlow) + .runWith(Sink.head) + //#host-level-example + } + + "single-request-example" in { + pending // compile-time only test + //#single-request-example + import scala.concurrent.Future + import akka.stream.ActorFlowMaterializer + import akka.http.scaladsl.model._ + import akka.http.scaladsl.Http + + implicit val system = ActorSystem() + implicit val materializer = ActorFlowMaterializer() + + val responseFuture: Future[HttpResponse] = + Http().singleRequest(HttpRequest(uri = "http://akka.io")) + //#single-request-example + } + +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/HttpServerExampleSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/HttpServerExampleSpec.scala new file mode 100644 index 0000000000..05ef9cfa77 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/HttpServerExampleSpec.scala @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl + +import scala.concurrent.Future +import org.scalatest.{ WordSpec, Matchers } +import akka.actor.ActorSystem + +class HttpServerExampleSpec extends WordSpec with Matchers { + + "binding-example" in { + import akka.stream.ActorFlowMaterializer + import akka.stream.scaladsl._ + import akka.http.scaladsl.Http + + implicit val system = ActorSystem() + implicit val materializer = ActorFlowMaterializer() + + val serverSource: Source[Http.IncomingConnection, Future[Http.ServerBinding]] = + Http().bind(interface = "localhost", port = 8080) + val bindingFuture: Future[Http.ServerBinding] = + serverSource.to(Sink.foreach { connection => // foreach materializes the source + println("Accepted new connection from " + connection.remoteAddress) + // ... and then actually handle the connection + }).run() + } + + "full-server-example" in { + import akka.stream.ActorFlowMaterializer + import akka.stream.scaladsl.Sink + import akka.http.scaladsl.Http + import akka.http.scaladsl.model.HttpMethods._ + import akka.http.scaladsl.model._ + + implicit val system = ActorSystem() + implicit val materializer = ActorFlowMaterializer() + + val serverSource = Http().bind(interface = "localhost", port = 8080) + + val requestHandler: HttpRequest => HttpResponse = { + case HttpRequest(GET, Uri.Path("/"), _, _, _) => + HttpResponse(entity = HttpEntity(MediaTypes.`text/html`, + "Hello world!")) + + case HttpRequest(GET, Uri.Path("/ping"), _, _, _) => + HttpResponse(entity = "PONG!") + + case HttpRequest(GET, Uri.Path("/crash"), _, _, _) => + sys.error("BOOM!") + + case _: HttpRequest => + HttpResponse(404, entity = "Unknown resource!") + } + + val bindingFuture: Future[Http.ServerBinding] = + serverSource.to(Sink.foreach { connection => + println("Accepted new connection from " + connection.remoteAddress) + + connection handleWithSyncHandler requestHandler + // this is equivalent to + // connection handleWith { Flow[HttpRequest] map requestHandler } + }).run() + } + + "low-level-server-example" in { + import akka.stream.ActorFlowMaterializer + import akka.http.scaladsl.Http + import akka.http.scaladsl.model.HttpMethods._ + import akka.http.scaladsl.model._ + + implicit val system = ActorSystem() + implicit val materializer = ActorFlowMaterializer() + + val requestHandler: HttpRequest => HttpResponse = { + case HttpRequest(GET, Uri.Path("/"), _, _, _) => + HttpResponse(entity = HttpEntity(MediaTypes.`text/html`, + "Hello world!")) + + case HttpRequest(GET, Uri.Path("/ping"), _, _, _) => + HttpResponse(entity = "PONG!") + + case HttpRequest(GET, Uri.Path("/crash"), _, _, _) => + sys.error("BOOM!") + + case _: HttpRequest => + HttpResponse(404, entity = "Unknown resource!") + } + + Http().bindAndHandleSync(requestHandler, "localhost", 8080) + } + + // format: OFF + + "high-level-server-example" in { + import akka.stream.ActorFlowMaterializer + import akka.http.scaladsl.Http + import akka.http.scaladsl.server.Directives._ + import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._ + + implicit val system = ActorSystem() + implicit val materializer = ActorFlowMaterializer() + + val route = + get { + pathSingleSlash { + complete { + + Hello world! + + } + } ~ + path("ping") { + complete("PONG!") + } ~ + path("crash") { + sys.error("BOOM!") + } + } + + Http().bindAndHandle(route, "localhost", 8080) + } + + "minimal-routing-example" in { + import akka.stream.ActorFlowMaterializer + import akka.http.scaladsl.Http + import akka.http.scaladsl.server.Directives._ + import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._ + + object Main extends App { + implicit val system = ActorSystem("my-system") + implicit val materializer = ActorFlowMaterializer() + + val route = + path("hello") { + get { + complete { +

Say hello to spray

+ } + } + } + + val bindingFuture = Http().bindAndHandle(route, "localhost", 8080) + + println(s"Server online at http://localhost:8080/\nPress RETURN to stop...") + Console.readLine() + + import system.dispatcher // for the future transformations + bindingFuture + .flatMap(_.unbind()) // trigger unbinding from the port + .onComplete(_ ⇒ system.shutdown()) // and shutdown when done + } + } + + "long-routing-example" in { + import akka.actor.ActorRef + import akka.util.Timeout + import akka.pattern.ask + import akka.http.scaladsl.marshalling.ToResponseMarshaller + import akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller + import akka.http.scaladsl.model.StatusCodes.MovedPermanently + import akka.http.scaladsl.coding.Deflate + import akka.http.scaladsl.server.Directives._ + + // types used by the API routes + type Money = Double // only for demo purposes, don't try this at home! + type TransactionResult = String + case class User(name: String) + case class Order(email: String, amount: Money) + case class Update(order: Order) + case class OrderItem(i: Int, os: Option[String], s: String) + implicit val orderUM: FromRequestUnmarshaller[Order] = ??? + implicit val orderM: ToResponseMarshaller[Seq[Order]] = ??? + implicit val timeout: Timeout = ??? // for actor asks + + val route = { + path("orders") { + authenticateBasic(realm = "admin area", myAuthenticator) { user => + get { + encodeResponseWith(Deflate) { + complete { + // marshal custom object with in-scope marshaller + retrieveOrdersFromDB + } + } + } ~ + post { + // decompress gzipped or deflated requests if required + decodeRequest { + // unmarshal with in-scope unmarshaller + entity(as[Order]) { order => + complete { + // ... write order to DB + "Order received" + } + } + } + } + } + } ~ + // extract URI path element as Int + pathPrefix("order" / IntNumber) { orderId => + pathEnd { + (put | parameter('method ! "put")) { + // form extraction from multipart or www-url-encoded forms + formFields('email, 'total.as[Money]).as(Order) { order => + complete { + // complete with serialized Future result + (myDbActor ? Update(order)).mapTo[TransactionResult] + } + } + } ~ + get { + // debugging helper + logRequest("GET-ORDER") { + // use in-scope marshaller to create completer function + completeWith(instanceOf[Order]) { completer => + // custom + processOrderRequest(orderId, completer) + } + } + } + } ~ + path("items") { + get { + // parameters to case class extraction + parameters('size.as[Int], 'color ?, 'dangerous ? "no") + .as(OrderItem) { orderItem => + // ... route using case class instance created from + // required and optional query parameters + complete("") // hide + } + } + } + } ~ + pathPrefix("documentation") { + // optionally compresses the response with Gzip or Deflate + // if the client accepts compressed responses + encodeResponse { + // serve up static content from a JAR resource + getFromResourceDirectory("docs") + } + } ~ + path("oldApi" / Rest) { pathRest => + redirect("http://oldapi.example.com/" + pathRest, MovedPermanently) + } + } + + // backend entry points + def myAuthenticator: Authenticator[User] = ??? + def retrieveOrdersFromDB: Seq[Order] = ??? + def myDbActor: ActorRef = ??? + def processOrderRequest(id: Int, complete: Order => Unit): Unit = ??? + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/ModelSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/ModelSpec.scala similarity index 87% rename from akka-docs-dev/rst/scala/code/docs/http/ModelSpec.scala rename to akka-docs-dev/rst/scala/code/docs/http/scaladsl/ModelSpec.scala index a3c2fc92f1..1ab2cd3a43 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/ModelSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/ModelSpec.scala @@ -1,4 +1,8 @@ -package docs.http +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl //#import-model import akka.http.scaladsl.model._ @@ -7,19 +11,18 @@ import akka.http.scaladsl.model._ import akka.stream.testkit.AkkaSpec import akka.util.ByteString -import akka.http.scaladsl.model.headers.{ GenericHttpCredentials, BasicHttpCredentials } -import org.scalatest.MustMatchers +import akka.http.scaladsl.model.headers.BasicHttpCredentials class ModelSpec extends AkkaSpec { "construct request" in { //#construct-request import HttpMethods._ - // construct simple GET request to `homeUri` + // construct a simple GET request to `homeUri` val homeUri = Uri("/abc") HttpRequest(GET, uri = homeUri) - // construct simple GET request to "/index" which is converted to Uri automatically + // construct simple GET request to "/index" (implicit string to Uri conversion) HttpRequest(GET, uri = "/index") // construct simple POST request containing entity @@ -70,11 +73,13 @@ class ModelSpec extends AkkaSpec { // create an ``Authorization`` header with HTTP Basic authentication data val auth = Authorization(BasicHttpCredentials("joe", "josepp")) - // a method that extracts basic HTTP credentials from a request + // custom type case class User(name: String, pass: String) + + // a method that extracts basic HTTP credentials from a request def credentialsOfRequest(req: HttpRequest): Option[User] = for { - Authorization(BasicHttpCredentials(user, pass)) <- req.header[headers.Authorization] + Authorization(BasicHttpCredentials(user, pass)) <- req.header[Authorization] } yield User(user, pass) //#headers diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala new file mode 100644 index 0000000000..3fef32836d --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server + +import akka.http.scaladsl.server._ + +class CaseClassExtractionExamplesSpec extends RoutingSpec { + + // format: OFF + + "example-1" in { + case class Color(red: Int, green: Int, blue: Int) + + val route = + path("color") { + parameters('red.as[Int], 'green.as[Int], 'blue.as[Int]) { (red, green, blue) => + val color = Color(red, green, blue) + // ... route working with the `color` instance + null // hide + } + } + Get("/color?red=1&green=2&blue=3") ~> route ~> check { responseAs[String] shouldEqual "Color(1,2,3)" } // hide + } + + "example-2" in { + case class Color(red: Int, green: Int, blue: Int) + + val route = + path("color") { + parameters('red.as[Int], 'green.as[Int], 'blue.as[Int]).as(Color) { color => + // ... route working with the `color` instance + null // hide + } + } + Get("/color?red=1&green=2&blue=3") ~> route ~> check { responseAs[String] shouldEqual "Color(1,2,3)" } // hide + } + + "example-3" in { + case class Color(name: String, red: Int, green: Int, blue: Int) + + val route = + (path("color" / Segment) & parameters('r.as[Int], 'g.as[Int], 'b.as[Int])) + .as(Color) { color => + // ... route working with the `color` instance + null // hide + } + Get("/color/abc?r=1&g=2&b=3") ~> route ~> check { responseAs[String] shouldEqual "Color(abc,1,2,3)" } // hide + } + + //# example-4 + case class Color(name: String, red: Int, green: Int, blue: Int) { + require(!name.isEmpty, "color name must not be empty") + require(0 <= red && red <= 255, "red color component must be between 0 and 255") + require(0 <= green && green <= 255, "green color component must be between 0 and 255") + require(0 <= blue && blue <= 255, "blue color component must be between 0 and 255") + } + //# + + "example 4 test" in { + val route = + (path("color" / Segment) & + parameters('r.as[Int], 'g.as[Int], 'b.as[Int])).as(Color) { color => + doSomethingWith(color) // route working with the Color instance + } + Get("/color/abc?r=1&g=2&b=3") ~> route ~> check { + responseAs[String] shouldEqual "Color(abc,1,2,3)" + } + Get("/color/abc?r=1&g=2&b=345") ~> route ~> check { + rejection must beLike { + case ValidationRejection("requirement failed: blue color component must be between 0 and 255", _) => ok + } + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/server/DirectiveExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/DirectiveExamplesSpec.scala similarity index 52% rename from akka-docs-dev/rst/scala/code/docs/http/server/DirectiveExamplesSpec.scala rename to akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/DirectiveExamplesSpec.scala index f0f49f7848..efbeafe9de 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/server/DirectiveExamplesSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/DirectiveExamplesSpec.scala @@ -2,7 +2,7 @@ * Copyright (C) 2009-2014 Typesafe Inc. */ -package docs.http.server +package docs.http.scaladsl.server import akka.http.scaladsl.server._ import Directives._ @@ -11,7 +11,9 @@ import org.scalatest._ class DirectiveExamplesSpec extends RoutingSpec { - "example-1, example-2" in { + // format: OFF + + "example-1" in { val route: Route = path("order" / IntNumber) { id => get { @@ -19,37 +21,49 @@ class DirectiveExamplesSpec extends RoutingSpec { "Received GET request for order " + id } } ~ - put { - complete { - "Received PUT request for order " + id - } + put { + complete { + "Received PUT request for order " + id } + } } verify(route) // hide } - "example-3" in { + "example-2" in { def innerRoute(id: Int): Route = get { complete { "Received GET request for order " + id } } ~ - put { - complete { - "Received PUT request for order " + id - } + put { + complete { + "Received PUT request for order " + id } + } val route: Route = path("order" / IntNumber) { id => innerRoute(id) } verify(route) // hide } + "example-3" in { + val route = + path("order" / IntNumber) { id => + (get | put) { ctx => + ctx.complete(s"Received ${ctx.request.method.name} request for order $id") + } + } + verify(route) // hide + } + "example-4" in { val route = path("order" / IntNumber) { id => - (get | put) { ctx => - ctx.complete("Received " + ctx.request.method.name + " request for order " + id) + (get | put) { + extractMethod { m => + complete(s"Received ${m.name} request for order $id") + } } } verify(route) // hide @@ -59,8 +73,10 @@ class DirectiveExamplesSpec extends RoutingSpec { val getOrPut = get | put val route = path("order" / IntNumber) { id => - getOrPut { ctx => - ctx.complete("Received " + ctx.request.method.name + " request for order " + id) + getOrPut { + extractMethod { m => + complete(s"Received ${m.name} request for order $id") + } } } verify(route) // hide @@ -69,51 +85,18 @@ class DirectiveExamplesSpec extends RoutingSpec { "example-6" in { val getOrPut = get | put val route = - (path("order" / IntNumber) & getOrPut) { id => - ctx => - ctx.complete("Received " + ctx.request.method.name + " request for order " + id) + (path("order" / IntNumber) & getOrPut & extractMethod) { (id, m) => + complete(s"Received ${m.name} request for order $id") } verify(route) // hide } "example-7" in { - val orderGetOrPut = path("order" / IntNumber) & (get | put) + val orderGetOrPutWithMethod = + path("order" / IntNumber) & (get | put) & extractMethod val route = - orderGetOrPut { id => - ctx => - ctx.complete("Received " + ctx.request.method.name + " request for order " + id) - } - verify(route) // hide - } - - "example-8" in { - val orderGetOrPut = path("order" / IntNumber) & (get | put) - val requestMethod = extract(_.request.method) - val route = - orderGetOrPut { id => - requestMethod { m => - complete("Received " + m.name + " request for order " + id) - } - } - verify(route) // hide - } - - "example-9" in { - val orderGetOrPut = path("order" / IntNumber) & (get | put) - val requestMethod = extract(_.request.method) - val route = - (orderGetOrPut & requestMethod) { (id, m) => - complete("Received " + m.name + " request for order " + id) - } - verify(route) // hide - } - - "example-A" in { - val orderGetOrPutMethod = - path("order" / IntNumber) & (get | put) & extract(_.request.method) - val route = - orderGetOrPutMethod { (id, m) => - complete("Received " + m.name + " request for order " + id) + orderGetOrPutWithMethod { (id, m) => + complete(s"Received ${m.name} request for order $id") } verify(route) // hide } diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/ExceptionHandlerExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/ExceptionHandlerExamplesSpec.scala new file mode 100644 index 0000000000..011bbc9563 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/ExceptionHandlerExamplesSpec.scala @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server + +// format: OFF + +object MyExplicitExceptionHandler { + + //#explicit-handler-example + import akka.actor.ActorSystem + import akka.stream.ActorFlowMaterializer + import akka.http.scaladsl.Http + import akka.http.scaladsl.model._ + import akka.http.scaladsl.server._ + import StatusCodes._ + import Directives._ + + val myExceptionHandler = ExceptionHandler { + case _: ArithmeticException => + extractUri { uri => + println(s"Request to $uri could not be handled normally") + complete(HttpResponse(InternalServerError, entity = "Bad numbers, bad result!!!")) + } + } + + object MyApp extends App { + implicit val system = ActorSystem() + implicit val materializer = ActorFlowMaterializer() + + val route: Route = + handleExceptions(myExceptionHandler) { + // ... some route structure + null // hide + } + + Http().bindAndHandle(route, "localhost", 8080) + } + //# +} + +object MyImplicitExceptionHandler { + + //#implicit-handler-example + import akka.actor.ActorSystem + import akka.stream.ActorFlowMaterializer + import akka.http.scaladsl.Http + import akka.http.scaladsl.model._ + import akka.http.scaladsl.server._ + import StatusCodes._ + import Directives._ + + implicit def myExceptionHandler: ExceptionHandler = + ExceptionHandler { + case _: ArithmeticException => + extractUri { uri => + println(s"Request to $uri could not be handled normally") + complete(HttpResponse(InternalServerError, entity = "Bad numbers, bad result!!!")) + } + } + + object MyApp extends App { + implicit val system = ActorSystem() + implicit val materializer = ActorFlowMaterializer() + + val route: Route = + // ... some route structure + null // hide + + Http().bindAndHandle(route, "localhost", 8080) + } + //# +} + +class ExceptionHandlerExamplesSpec extends RoutingSpec { + + "test explicit example" in { + Get() ~> handleExceptions(MyExplicitExceptionHandler.myExceptionHandler) { + _.complete((1 / 0).toString) + } ~> check { + responseAs[String] === "Bad numbers, bad result!!!" + } + } + + "test implicit example" in { + import akka.http.scaladsl.server._ + import MyImplicitExceptionHandler.myExceptionHandler + Get() ~> Route.seal(ctx => ctx.complete((1 / 0).toString)) ~> check { + responseAs[String] === "Bad numbers, bad result!!!" + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/FullTestKitExampleSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/FullTestKitExampleSpec.scala new file mode 100644 index 0000000000..3bf9a7d639 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/FullTestKitExampleSpec.scala @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server + +// format: OFF + +//# source-quote +import org.scalatest.{ Matchers, WordSpec } +import akka.http.scaladsl.model.StatusCodes +import akka.http.scaladsl.testkit.ScalatestRouteTest +import akka.http.scaladsl.server._ +import Directives._ + +class FullTestKitExampleSpec extends WordSpec with Matchers with ScalatestRouteTest { + + val smallRoute = + get { + pathSingleSlash { + complete { + "Captain on the bridge!" + } + } ~ + path("ping") { + complete("PONG!") + } + } + + "The service" should { + + "return a greeting for GET requests to the root path" in { + Get() ~> smallRoute ~> check { + responseAs[String] should contain("Captain on the bridge") + } + } + + "return a 'PONG!' response for GET requests to /ping" in { + Get("/ping") ~> smallRoute ~> check { + responseAs[String] shouldEqual "PONG!" + } + } + + "leave GET requests to other paths unhandled" in { + Get("/kermit") ~> smallRoute ~> check { + handled shouldBe false + } + } + + "return a MethodNotAllowed error for PUT requests to the root path" in { + Put() ~> Route.seal(smallRoute) ~> check { + status === StatusCodes.MethodNotAllowed + responseAs[String] shouldEqual "HTTP method not allowed, supported methods: GET" + } + } + } +} +//# \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/RejectionHandlerExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/RejectionHandlerExamplesSpec.scala new file mode 100644 index 0000000000..777faf84bd --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/RejectionHandlerExamplesSpec.scala @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server + +// format: OFF + +object MyRejectionHandler { + + //#custom-handler-example + import akka.actor.ActorSystem + import akka.stream.ActorFlowMaterializer + import akka.http.scaladsl.Http + import akka.http.scaladsl.model._ + import akka.http.scaladsl.server._ + import StatusCodes._ + import Directives._ + + implicit def myRejectionHandler = + RejectionHandler.newBuilder() + .handle { case MissingCookieRejection(cookieName) => + complete(HttpResponse(BadRequest, entity = "No cookies, no service!!!")) + } + .handle { case AuthorizationFailedRejection ⇒ + complete(Forbidden, "You're out of your depth!") + } + .handleAll[MethodRejection] { methodRejections ⇒ + val names = methodRejections.map(_.supported.name) + complete(MethodNotAllowed, s"Can't do that! Supported: ${names mkString " or "}!") + } + .handleNotFound { complete(NotFound, "Not here!") } + .result() + + object MyApp extends App { + implicit val system = ActorSystem() + implicit val materializer = ActorFlowMaterializer() + + val route: Route = + // ... some route structure + null // hide + + Http().bindAndHandle(route, "localhost", 8080) + } + //# +} + +class RejectionHandlerExamplesSpec extends RoutingSpec { + import MyRejectionHandler._ + + "example-1" in { + import akka.http.scaladsl.coding.Gzip + + val route = + path("order") { + get { + complete("Received GET") + } ~ + post { + decodeRequestWith(Gzip) { + complete("Received compressed POST") + } + } + } + } + + "test custom handler example" in { + import akka.http.scaladsl.server._ + Get() ~> Route.seal(reject(MissingCookieRejection("abc"))) ~> check { + responseAs[String] === "No cookies, no service!!!" + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/server/RoutingSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/RoutingSpec.scala similarity index 90% rename from akka-docs-dev/rst/scala/code/docs/http/server/RoutingSpec.scala rename to akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/RoutingSpec.scala index 8aec6b4891..fcc3c5b194 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/server/RoutingSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/RoutingSpec.scala @@ -2,7 +2,7 @@ * Copyright (C) 2009-2014 Typesafe Inc. */ -package docs.http.server +package docs.http.scaladsl.server import akka.http.scaladsl.server.Directives import akka.http.scaladsl.testkit.ScalatestRouteTest diff --git a/akka-docs-dev/rst/scala/code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala similarity index 98% rename from akka-docs-dev/rst/scala/code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala rename to akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala index 1b714618f2..59498fadd6 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala @@ -2,16 +2,14 @@ * Copyright (C) 2009-2014 Typesafe Inc. */ -package docs.http.server +package docs.http.scaladsl.server package directives +import scala.util.control.NonFatal +import akka.util.ByteString import akka.http.scaladsl.model.headers.RawHeader import akka.http.scaladsl.server.RouteResult.Rejected import akka.http.scaladsl.server._ -import akka.util.ByteString - -import scala.util.control.NonFatal - import akka.http.scaladsl.model._ class BasicDirectivesExamplesSpec extends RoutingSpec { @@ -164,7 +162,7 @@ class BasicDirectivesExamplesSpec extends RoutingSpec { rejections.nonEmpty shouldEqual true } } - "mapRouteResponsePF" in { + "mapRouteResultPF" in { case object MyCustomRejection extends Rejection val rejectRejections = // not particularly useful directive mapRouteResultPF { diff --git a/akka-docs-dev/rst/scala/code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/CodingDirectivesExamplesSpec.scala similarity index 99% rename from akka-docs-dev/rst/scala/code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala rename to akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/CodingDirectivesExamplesSpec.scala index 977b8e7a61..8756bf3e41 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/CodingDirectivesExamplesSpec.scala @@ -2,7 +2,7 @@ * Copyright (C) 2009-2014 Typesafe Inc. */ -package docs.http.server +package docs.http.scaladsl.server package directives import akka.http.scaladsl.coding._ diff --git a/akka-docs-dev/rst/scala/code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/CookieDirectivesExamplesSpec.scala similarity index 98% rename from akka-docs-dev/rst/scala/code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala rename to akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/CookieDirectivesExamplesSpec.scala index 5004c84bf0..b6b47a4a45 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/CookieDirectivesExamplesSpec.scala @@ -2,7 +2,7 @@ * Copyright (C) 2009-2014 Typesafe Inc. */ -package docs.http.server +package docs.http.scaladsl.server package directives import akka.http.scaladsl.server._ diff --git a/akka-docs-dev/rst/scala/code/docs/http/server/directives/DebuggingDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/DebuggingDirectivesExamplesSpec.scala similarity index 99% rename from akka-docs-dev/rst/scala/code/docs/http/server/directives/DebuggingDirectivesExamplesSpec.scala rename to akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/DebuggingDirectivesExamplesSpec.scala index fe50aadfad..6ad0a8944f 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/server/directives/DebuggingDirectivesExamplesSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/DebuggingDirectivesExamplesSpec.scala @@ -2,7 +2,7 @@ * Copyright (C) 2009-2014 Typesafe Inc. */ -package docs.http.server +package docs.http.scaladsl.server package directives import akka.http.scaladsl.model.{ HttpResponse, HttpRequest } diff --git a/akka-docs-dev/rst/scala/code/docs/http/server/directives/ExecutionDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/ExecutionDirectivesExamplesSpec.scala similarity index 98% rename from akka-docs-dev/rst/scala/code/docs/http/server/directives/ExecutionDirectivesExamplesSpec.scala rename to akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/ExecutionDirectivesExamplesSpec.scala index 881abe89fd..4204e52a93 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/server/directives/ExecutionDirectivesExamplesSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/ExecutionDirectivesExamplesSpec.scala @@ -2,7 +2,7 @@ * Copyright (C) 2009-2014 Typesafe Inc. */ -package docs.http.server +package docs.http.scaladsl.server package directives import akka.http.scaladsl.model.StatusCodes diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/FormFieldDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/FormFieldDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..6cc61a89a6 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/FormFieldDirectivesExamplesSpec.scala @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import akka.http.scaladsl.server.Route +import akka.http.scaladsl.model._ + +class FormFieldDirectivesExamplesSpec extends RoutingSpec { + + "formFields" in { + val route = + formFields('color, 'age.as[Int]) { (color, age) => + complete(s"The color is '$color' and the age ten years ago was ${age - 10}") + } + + Post("/", FormData(Seq("color" -> "blue", "age" -> "68"))) ~> route ~> check { + responseAs[String] shouldEqual "The color is 'blue' and the age ten years ago was 58" + } + + Get("/") ~> Route.seal(route) ~> check { + status shouldEqual StatusCodes.BadRequest + responseAs[String] shouldEqual "Request is missing required form field 'color'" + } + } + +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/FutureDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/FutureDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..db7c3bc43b --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/FutureDirectivesExamplesSpec.scala @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import java.util.concurrent.TimeUnit +import scala.concurrent.Future +import scala.util.{ Success, Failure } +import akka.http.scaladsl.server.ExceptionHandler +import akka.actor.{ Actor, Props } +import akka.util.Timeout +import akka.http.scaladsl.model._ +import akka.http.scaladsl.server.Route +import StatusCodes._ + +// format: OFF + +class FutureDirectivesExamplesSpec extends RoutingSpec { + object TestException extends Throwable + + implicit val myExceptionHandler = + ExceptionHandler { + case TestException => ctx => + ctx.complete(InternalServerError, "Unsuccessful future!") + } + + val resourceActor = system.actorOf(Props(new Actor { + def receive = { case _ => sender ! "resource" } + })) + implicit val responseTimeout = Timeout(2, TimeUnit.SECONDS) + + "example-1" in { + def divide(a: Int, b: Int): Future[Int] = Future { + a / b + } + + val route = + path("divide" / IntNumber / IntNumber) { (a, b) => + onComplete(divide(a, b)) { + case Success(value) => complete(s"The result was $value") + case Failure(ex) => complete(InternalServerError, s"An error occurred: ${ex.getMessage}") + } + } + + Get("/divide/10/2") ~> route ~> check { + responseAs[String] shouldEqual "The result was 5" + } + + Get("/divide/10/0") ~> Route.seal(route) ~> check { + status shouldEqual InternalServerError + responseAs[String] shouldEqual "An error occurred: / by zero" + } + } + + "example-2" in { + val route = + path("success") { + onSuccess(Future { "Ok" }) { extraction => + complete(extraction) + } + } ~ + path("failure") { + onSuccess(Future.failed[String](TestException)) { extraction => + complete(extraction) + } + } + + Get("/success") ~> route ~> check { + responseAs[String] shouldEqual "Ok" + } + + Get("/failure") ~> Route.seal(route) ~> check { + status shouldEqual InternalServerError + responseAs[String] shouldEqual "Unsuccessful future!" + } + } + + "example-3" in { + val route = + path("success") { + onFailure(Future { "Ok" }) { extraction => + failWith(extraction) // not executed. + } + } ~ + path("failure") { + onFailure(Future.failed[String](TestException)) { extraction => + failWith(extraction) + } + } + + Get("/success") ~> route ~> check { + responseAs[String] shouldEqual "Ok" + } + + Get("/failure") ~> Route.seal(route) ~> check { + status shouldEqual InternalServerError + responseAs[String] shouldEqual "Unsuccessful future!" + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/HeaderDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/HeaderDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..cbaf451c6f --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/HeaderDirectivesExamplesSpec.scala @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import akka.http.scaladsl.model._ +import akka.http.scaladsl.server.MissingHeaderRejection +import akka.http.scaladsl.server.Route +import headers._ +import StatusCodes._ + +class HeaderDirectivesExamplesSpec extends RoutingSpec { + "headerValueByName-0" in { + val route = + headerValueByName("X-User-Id") { userId => + complete(s"The user is $userId") + } + + Get("/") ~> RawHeader("X-User-Id", "Joe42") ~> route ~> check { + responseAs[String] shouldEqual "The user is Joe42" + } + + Get("/") ~> Route.seal(route) ~> check { + status shouldEqual BadRequest + responseAs[String] shouldEqual "Request is missing required HTTP header 'X-User-Id'" + } + } + "headerValue-0" in { + def extractHostPort: HttpHeader => Option[Int] = { + case h: `Host` => Some(h.port) + case x => None + } + + val route = + headerValue(extractHostPort) { port => + complete(s"The port was $port") + } + + Get("/") ~> Host("example.com", 5043) ~> route ~> check { + responseAs[String] shouldEqual "The port was 5043" + } + Get("/") ~> Route.seal(route) ~> check { + status shouldEqual NotFound + responseAs[String] shouldEqual "The requested resource could not be found." + } + } + "headerValuePF-0" in { + def extractHostPort: PartialFunction[HttpHeader, Int] = { + case h: `Host` => h.port + } + + val route = + headerValuePF(extractHostPort) { port => + complete(s"The port was $port") + } + + Get("/") ~> Host("example.com", 5043) ~> route ~> check { + responseAs[String] shouldEqual "The port was 5043" + } + Get("/") ~> Route.seal(route) ~> check { + status shouldEqual NotFound + responseAs[String] shouldEqual "The requested resource could not be found." + } + } + "headerValueByType-0" in { + val route = + headerValueByType[Origin]() { origin ⇒ + complete(s"The first origin was ${origin.originList.head}") + } + + val originHeader = Origin(Seq(HttpOrigin("http://localhost:8080"))) + + // extract a header if the type is matching + Get("abc") ~> originHeader ~> route ~> check { + responseAs[String] shouldEqual "The first origin was http://localhost:8080" + } + + // reject a request if no header of the given type is present + Get("abc") ~> route ~> check { + rejection must beLike { case MissingHeaderRejection("Origin") ⇒ ok } + } + } + "optionalHeaderValueByType-0" in { + val route = + optionalHeaderValueByType[Origin]() { + case Some(origin) ⇒ complete(s"The first origin was ${origin.originList.head}") + case None ⇒ complete("No Origin header found.") + } + + val originHeader = Origin(Seq(HttpOrigin("http://localhost:8080"))) + // extract Some(header) if the type is matching + Get("abc") ~> originHeader ~> route ~> check { + responseAs[String] shouldEqual "The first origin was http://localhost:8080" + } + + // extract None if no header of the given type is present + Get("abc") ~> route ~> check { + responseAs[String] shouldEqual "No Origin header found." + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/HostDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/HostDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..3339ea2e5b --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/HostDirectivesExamplesSpec.scala @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import akka.http.scaladsl.model._ +import headers._ +import StatusCodes._ + +class HostDirectivesExamplesSpec extends RoutingSpec { + + "extract-hostname" in { + val route = + hostName { hn => + complete(s"Hostname: $hn") + } + + Get() ~> Host("company.com", 9090) ~> route ~> check { + status shouldEqual OK + responseAs[String] shouldEqual "Hostname: company.com" + } + } + + "list-of-hosts" in { + val route = + host("api.company.com", "rest.company.com") { + complete("Ok") + } + + Get() ~> Host("rest.company.com") ~> route ~> check { + status shouldEqual OK + responseAs[String] shouldEqual "Ok" + } + + Get() ~> Host("notallowed.company.com") ~> route ~> check { + handled shouldBe false + } + } + + "predicate" in { + val shortOnly: String => Boolean = (hostname) => hostname.length < 10 + + val route = + host(shortOnly) { + complete("Ok") + } + + Get() ~> Host("short.com") ~> route ~> check { + status shouldEqual OK + responseAs[String] shouldEqual "Ok" + } + + Get() ~> Host("verylonghostname.com") ~> route ~> check { + handled shouldBe false + } + } + + "using-regex" in { + val route = + host("api|rest".r) { prefix => + complete(s"Extracted prefix: $prefix") + } ~ + host("public.(my|your)company.com".r) { captured => + complete(s"You came through $captured company") + } + + Get() ~> Host("api.company.com") ~> route ~> check { + status shouldEqual OK + responseAs[String] shouldEqual "Extracted prefix: api" + } + + Get() ~> Host("public.mycompany.com") ~> route ~> check { + status shouldEqual OK + responseAs[String] shouldEqual "You came through my company" + } + } + + "failing-regex" in { + { + host("server-([0-9]).company.(com|net|org)".r) { target => + complete("Will never complete :'(") + } + } must throwAn[IllegalArgumentException] + } + +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..8ee4b51642 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport +import akka.http.scaladsl.model._ +import spray.json.DefaultJsonProtocol +import headers._ +import StatusCodes._ + +//# person-case-class +case class Person(name: String, favoriteNumber: Int) + +//# person-json-support +object PersonJsonSupport extends DefaultJsonProtocol with SprayJsonSupport { + implicit val PortofolioFormats = jsonFormat2(Person) +} +//# + +class MarshallingDirectivesExamplesSpec extends RoutingSpec { + + "example-entity-with-json" in { + import PersonJsonSupport._ + + val route = post { + entity(as[Person]) { person => + complete(s"Person: ${person.name} - favorite number: ${person.favoriteNumber}") + } + } + + Post("/", HttpEntity(`application/json`, """{ "name": "Jane", "favoriteNumber" : 42 }""")) ~> + route ~> check { + responseAs[String] shouldEqual "Person: Jane - favorite number: 42" + } + } + + "example-produce-with-json" in { + import PersonJsonSupport._ + + val findPerson = (f: Person => Unit) => { + + //... some processing logic... + + //complete the request + f(Person("Jane", 42)) + } + + val route = get { + produce(instanceOf[Person]) { completionFunction => ctx => findPerson(completionFunction) } + } + + Get("/") ~> route ~> check { + mediaType shouldEqual `application/json` + responseAs[String] must contain(""""name": "Jane"""") + responseAs[String] must contain(""""favoriteNumber": 42""") + } + } + + "example-handleWith-with-json" in { + import PersonJsonSupport._ + + val updatePerson = (person: Person) => { + + //... some processing logic... + + //return the person + person + } + + val route = post { + handleWith(updatePerson) + } + + Post("/", HttpEntity(`application/json`, """{ "name": "Jane", "favoriteNumber" : 42 }""")) ~> + route ~> check { + mediaType shouldEqual `application/json` + responseAs[String] must contain(""""name": "Jane"""") + responseAs[String] must contain(""""favoriteNumber": 42""") + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..ed547ca4b0 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import akka.http.scaladsl.model._ + +class MethodDirectivesExamplesSpec extends RoutingSpec { + + "delete-method" in { + val route = delete { complete("This is a DELETE request.") } + + Delete("/") ~> route ~> check { + responseAs[String] shouldEqual "This is a DELETE request." + } + } + + "get-method" in { + val route = get { complete("This is a GET request.") } + + Get("/") ~> route ~> check { + responseAs[String] shouldEqual "This is a GET request." + } + } + + "head-method" in { + val route = head { complete("This is a HEAD request.") } + + Head("/") ~> route ~> check { + responseAs[String] shouldEqual "This is a HEAD request." + } + } + + "options-method" in { + val route = options { complete("This is an OPTIONS request.") } + + Options("/") ~> route ~> check { + responseAs[String] shouldEqual "This is an OPTIONS request." + } + } + + "patch-method" in { + val route = patch { complete("This is a PATCH request.") } + + Patch("/", "patch content") ~> route ~> check { + responseAs[String] shouldEqual "This is a PATCH request." + } + } + + "post-method" in { + val route = post { complete("This is a POST request.") } + + Post("/", "post content") ~> route ~> check { + responseAs[String] shouldEqual "This is a POST request." + } + } + + "put-method" in { + val route = put { complete("This is a PUT request.") } + + Put("/", "put content") ~> route ~> check { + responseAs[String] shouldEqual "This is a PUT request." + } + } + + "method-example" in { + val route = method(HttpMethods.PUT) { complete("This is a PUT request.") } + + Put("/", "put content") ~> route ~> check { + responseAs[String] shouldEqual "This is a PUT request." + } + + Get("/") ~> Route.seal(route) ~> check { + status shouldEqual StatusCodes.MethodNotAllowed + responseAs[String] shouldEqual "HTTP method not allowed, supported methods: PUT" + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/MiscDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/MiscDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..bb4e83b04f --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/MiscDirectivesExamplesSpec.scala @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import akka.http.scaladsl.model._ +import akka.http.scaladsl.server._ +import headers._ + +class MiscDirectivesExamplesSpec extends RoutingSpec { + "cancelAllRejections-example" in { + def isMethodRejection: Rejection => Boolean = { + case MethodRejection(_) => true + case _ => false + } + + val route = + cancelAllRejections(isMethodRejection) { + post { + complete("Result") + } + } + + Get("/") ~> route ~> check { + rejections shouldEqual Nil + handled shouldEqual false + } + } + "cancelRejection-example" in { + val route = + cancelRejection(MethodRejection(HttpMethods.POST)) { + post { + complete("Result") + } + } + + Get("/") ~> route ~> check { + rejections shouldEqual Nil + handled shouldEqual false + } + } + "clientIP-example" in { + val route = clientIP { ip => + complete("Client's ip is " + ip.toOption.map(_.getHostAddress).getOrElse("unknown")) + } + + Get("/").withHeaders(`Remote-Address`("192.168.3.12")) ~> route ~> check { + responseAs[String] shouldEqual "Client's ip is 192.168.3.12" + } + } + "jsonpWithParameter-example" in { + case class Test(abc: Int) + object TestProtocol { + import spray.json.DefaultJsonProtocol._ + implicit val testFormat = jsonFormat(Test, "abc") + } + val route = + jsonpWithParameter("jsonp") { + import TestProtocol._ + import spray.httpx.SprayJsonSupport._ + complete(Test(456)) + } + + Get("/?jsonp=result") ~> route ~> check { + responseAs[String] shouldEqual + """result({ + | "abc": 456 + |})""".stripMarginWithNewline("\n") + contentType shouldEqual MediaTypes.`application/javascript`.withCharset(HttpCharsets.`UTF-8`) + } + Get("/") ~> route ~> check { + responseAs[String] shouldEqual + """{ + | "abc": 456 + |}""".stripMarginWithNewline("\n") + contentType shouldEqual ContentTypes.`application/json` + } + } + "rejectEmptyResponse-example" in { + val route = rejectEmptyResponse { + path("even" / IntNumber) { i => + complete { + // returns Some(evenNumberDescription) or None + Option(i).filter(_ % 2 == 0).map { num => + s"Number $num is even." + } + } + } + } + + Get("/even/23") ~> Route.seal(route) ~> check { + status shouldEqual StatusCodes.NotFound + } + Get("/even/28") ~> route ~> check { + responseAs[String] shouldEqual "Number 28 is even." + } + } + "requestEntityEmptyPresent-example" in { + val route = + requestEntityEmpty { + complete("request entity empty") + } ~ + requestEntityPresent { + complete("request entity present") + } + + Post("/", "text") ~> Route.seal(route) ~> check { + responseAs[String] shouldEqual "request entity present" + } + Post("/") ~> route ~> check { + responseAs[String] shouldEqual "request entity empty" + } + } + "requestInstance-example" in { + val route = + requestInstance { request => + complete(s"Request method is ${request.method} and length is ${request.entity.data.length}") + } + + Post("/", "text") ~> route ~> check { + responseAs[String] shouldEqual "Request method is POST and length is 4" + } + Get("/") ~> route ~> check { + responseAs[String] shouldEqual "Request method is GET and length is 0" + } + } + "requestUri-example" in { + val route = + requestUri { uri => + complete(s"Full URI: $uri") + } + + Get("/") ~> route ~> check { + // tests are executed with the host assumed to be "example.com" + responseAs[String] shouldEqual "Full URI: http://example.com/" + } + Get("/test") ~> route ~> check { + responseAs[String] shouldEqual "Full URI: http://example.com/test" + } + } + "rewriteUnmatchedPath-example" in { + def ignore456(path: Uri.Path) = path match { + case s @ Uri.Path.Segment(head, tail) if head.startsWith("456") => + val newHead = head.drop(3) + if (newHead.isEmpty) tail + else s.copy(head = head.drop(3)) + case _ => path + } + val ignoring456 = rewriteUnmatchedPath(ignore456) + + val route = + pathPrefix("123") { + ignoring456 { + path("abc") { + complete(s"Content") + } + } + } + + Get("/123/abc") ~> route ~> check { + responseAs[String] shouldEqual "Content" + } + Get("/123456/abc") ~> route ~> check { + responseAs[String] shouldEqual "Content" + } + } + "unmatchedPath-example" in { + val route = + pathPrefix("abc") { + unmatchedPath { remaining => + complete(s"Unmatched: '$remaining'") + } + } + + Get("/abc") ~> route ~> check { + responseAs[String] shouldEqual "Unmatched: ''" + } + Get("/abc/456") ~> route ~> check { + responseAs[String] shouldEqual "Unmatched: '/456'" + } + } + "validate-example" in { + val route = + requestUri { uri => + validate(uri.path.toString.size < 5, s"Path too long: '${uri.path.toString}'") { + complete(s"Full URI: $uri") + } + } + + Get("/234") ~> route ~> check { + responseAs[String] shouldEqual "Full URI: http://example.com/234" + } + Get("/abcdefghijkl") ~> route ~> check { + rejection shouldEqual ValidationRejection("Path too long: '/abcdefghijkl'", None) + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..495cf7aa89 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import spray.http.StatusCodes + +class ParameterDirectivesExamplesSpec extends RoutingSpec { + "example-1" in { + val route = + parameter('color) { color => + complete(s"The color is '$color'") + } + + Get("/?color=blue") ~> route ~> check { + responseAs[String] shouldEqual "The color is 'blue'" + } + + Get("/") ~> Route.seal(route) ~> check { + status shouldEqual StatusCodes.NotFound + responseAs[String] shouldEqual "Request is missing required query parameter 'color'" + } + } + "required-1" in { + val route = + parameters('color, 'backgroundColor) { (color, backgroundColor) => + complete(s"The color is '$color' and the background is '$backgroundColor'") + } + + Get("/?color=blue&backgroundColor=red") ~> route ~> check { + responseAs[String] shouldEqual "The color is 'blue' and the background is 'red'" + } + Get("/?color=blue") ~> Route.seal(route) ~> check { + status shouldEqual StatusCodes.NotFound + responseAs[String] shouldEqual "Request is missing required query parameter 'backgroundColor'" + } + } + "optional" in { + val route = + parameters('color, 'backgroundColor.?) { (color, backgroundColor) => + val backgroundStr = backgroundColor.getOrElse("") + complete(s"The color is '$color' and the background is '$backgroundStr'") + } + + Get("/?color=blue&backgroundColor=red") ~> route ~> check { + responseAs[String] shouldEqual "The color is 'blue' and the background is 'red'" + } + Get("/?color=blue") ~> route ~> check { + responseAs[String] shouldEqual "The color is 'blue' and the background is ''" + } + } + "optional-with-default" in { + val route = + parameters('color, 'backgroundColor ? "white") { (color, backgroundColor) => + complete(s"The color is '$color' and the background is '$backgroundColor'") + } + + Get("/?color=blue&backgroundColor=red") ~> route ~> check { + responseAs[String] shouldEqual "The color is 'blue' and the background is 'red'" + } + Get("/?color=blue") ~> route ~> check { + responseAs[String] shouldEqual "The color is 'blue' and the background is 'white'" + } + } + "required-value" in { + val route = + parameters('color, 'action ! "true") { (color) => + complete(s"The color is '$color'.") + } + + Get("/?color=blue&action=true") ~> route ~> check { + responseAs[String] shouldEqual "The color is 'blue'." + } + + Get("/?color=blue&action=false") ~> Route.seal(route) ~> check { + status shouldEqual StatusCodes.NotFound + responseAs[String] shouldEqual "The requested resource could not be found." + } + } + "mapped-value" in { + val route = + parameters('color, 'count.as[Int]) { (color, count) => + complete(s"The color is '$color' and you have $count of it.") + } + + Get("/?color=blue&count=42") ~> route ~> check { + responseAs[String] shouldEqual "The color is 'blue' and you have 42 of it." + } + + Get("/?color=blue&count=blub") ~> Route.seal(route) ~> check { + status shouldEqual StatusCodes.BadRequest + responseAs[String] shouldEqual "The query parameter 'count' was malformed:\n'blub' is not a valid 32-bit integer value" + } + } + "parameterMap" in { + val route = + parameterMap { params => + def paramString(param: (String, String)): String = s"""${param._1} = '${param._2}'""" + complete(s"The parameters are ${params.map(paramString).mkString(", ")}") + } + + Get("/?color=blue&count=42") ~> route ~> check { + responseAs[String] shouldEqual "The parameters are color = 'blue', count = '42'" + } + Get("/?x=1&x=2") ~> route ~> check { + responseAs[String] shouldEqual "The parameters are x = '2'" + } + } + "parameterMultiMap" in { + val route = + parameterMultiMap { params => + complete(s"There are parameters ${params.map(x => x._1 + " -> " + x._2.size).mkString(", ")}") + } + + Get("/?color=blue&count=42") ~> route ~> check { + responseAs[String] shouldEqual "There are parameters color -> 1, count -> 1" + } + Get("/?x=23&x=42") ~> route ~> check { + responseAs[String] shouldEqual "There are parameters x -> 2" + } + } + "parameterSeq" in { + val route = + parameterSeq { params => + def paramString(param: (String, String)): String = s"""${param._1} = '${param._2}'""" + complete(s"The parameters are ${params.map(paramString).mkString(", ")}") + } + + Get("/?color=blue&count=42") ~> route ~> check { + responseAs[String] shouldEqual "The parameters are color = 'blue', count = '42'" + } + Get("/?x=1&x=2") ~> route ~> check { + responseAs[String] shouldEqual "The parameters are x = '1', x = '2'" + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/server/directives/PathDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/PathDirectivesExamplesSpec.scala similarity index 99% rename from akka-docs-dev/rst/scala/code/docs/http/server/directives/PathDirectivesExamplesSpec.scala rename to akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/PathDirectivesExamplesSpec.scala index 3f5c713431..2e3cc7166b 100644 --- a/akka-docs-dev/rst/scala/code/docs/http/server/directives/PathDirectivesExamplesSpec.scala +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/PathDirectivesExamplesSpec.scala @@ -2,7 +2,7 @@ * Copyright (C) 2009-2014 Typesafe Inc. */ -package docs.http.server +package docs.http.scaladsl.server package directives import akka.http.scaladsl.server._ diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/RangeDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/RangeDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..aa77b7f6f2 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/RangeDirectivesExamplesSpec.scala @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import akka.http.scaladsl.model._ +import headers._ + +class RangeDirectivesExamplesSpec extends RoutingSpec { + + "withRangeSupport" in { + val route = + withRangeSupport(4, 2L) { + complete("ABCDEFGH") + } + + Get() ~> addHeader(Range(ByteRange(3, 4))) ~> route ~> check { + headers must contain(`Content-Range`(ContentRange(3, 4, 8))) + status shouldEqual StatusCodes.PartialContent + responseAs[String] shouldEqual "DE" + } + + Get() ~> addHeader(Range(ByteRange(0, 1), ByteRange(1, 2), ByteRange(6, 7))) ~> route ~> check { + headers must not(contain(like[HttpHeader] { case `Content-Range`(_, _) ⇒ ok })) + responseAs[MultipartByteRanges] must beLike { + case MultipartByteRanges( + BodyPart(entity1, `Content-Range`(RangeUnit.Bytes, range1) +: _) +: + BodyPart(entity2, `Content-Range`(RangeUnit.Bytes, range2) +: _) +: Seq() + ) ⇒ entity1.asString shouldEqual "ABC" and range1 shouldEqual ContentRange(0, 2, 8) and + entity2.asString shouldEqual "GH" and range2 shouldEqual ContentRange(6, 7, 8) + } + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/RespondWithDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/RespondWithDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..014b2ef939 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/RespondWithDirectivesExamplesSpec.scala @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import akka.http.scaladsl.server.UnacceptedResponseContentTypeRejection +import akka.http.scaladsl.model._ +import headers._ + +class RespondWithDirectivesExamplesSpec extends RoutingSpec { + + "respondWithHeader-examples" in { + val route = + path("foo") { + respondWithHeader(RawHeader("Funky-Muppet", "gonzo")) { + complete("beep") + } + } + + Get("/foo") ~> route ~> check { + header("Funky-Muppet") shouldEqual Some(RawHeader("Funky-Muppet", "gonzo")) + responseAs[String] shouldEqual "beep" + } + } + + "respondWithHeaders-examples" in { + val route = + path("foo") { + respondWithHeaders(RawHeader("Funky-Muppet", "gonzo"), Origin(Seq(HttpOrigin("http://spray.io")))) { + complete("beep") + } + } + + Get("/foo") ~> route ~> check { + header("Funky-Muppet") shouldEqual Some(RawHeader("Funky-Muppet", "gonzo")) + header[Origin] shouldEqual Some(Origin(Seq(HttpOrigin("http://spray.io")))) + responseAs[String] shouldEqual "beep" + } + } + + "respondWithMediaType-examples" in { + import MediaTypes._ + + val route = + path("foo") { + respondWithMediaType(`application/json`) { + complete("[]") // marshalled to `text/plain` here + } + } + + Get("/foo") ~> route ~> check { + mediaType shouldEqual `application/json` + responseAs[String] shouldEqual "[]" + } + + Get("/foo") ~> Accept(MediaRanges.`text/*`) ~> route ~> check { + rejection shouldEqual UnacceptedResponseContentTypeRejection(ContentType(`application/json`) :: Nil) + } + } + + "respondWithSingletonHeader-examples" in { + val respondWithMuppetHeader = + respondWithSingletonHeader(RawHeader("Funky-Muppet", "gonzo")) + + val route = + path("foo") { + respondWithMuppetHeader { + complete("beep") + } + } ~ + path("bar") { + respondWithMuppetHeader { + respondWithHeader(RawHeader("Funky-Muppet", "kermit")) { + complete("beep") + } + } + } + + Get("/foo") ~> route ~> check { + headers.filter(_.is("funky-muppet")) shouldEqual List(RawHeader("Funky-Muppet", "gonzo")) + responseAs[String] shouldEqual "beep" + } + + Get("/bar") ~> route ~> check { + headers.filter(_.is("funky-muppet")) shouldEqual List(RawHeader("Funky-Muppet", "kermit")) + responseAs[String] shouldEqual "beep" + } + } + + "respondWithStatus-examples" in { + val route = + path("foo") { + respondWithStatus(201) { + complete("beep") + } + } + + Get("/foo") ~> route ~> check { + status shouldEqual StatusCodes.Created + responseAs[String] shouldEqual "beep" + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/RouteDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/RouteDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..e7f7dc31fe --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/RouteDirectivesExamplesSpec.scala @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import spray.http.{ RequestProcessingException, HttpResponse, StatusCodes } +import spray.routing.ValidationRejection + +class RouteDirectivesExamplesSpec extends RoutingSpec { + + "complete-examples" in { + val route = + path("a") { + complete(HttpResponse(entity = "foo")) + } ~ + path("b") { + complete(StatusCodes.Created, "bar") + } ~ + (path("c") & complete("baz")) // `&` also works with `complete` as the 2nd argument + + Get("/a") ~> route ~> check { + status shouldEqual StatusCodes.OK + responseAs[String] shouldEqual "foo" + } + + Get("/b") ~> route ~> check { + status shouldEqual StatusCodes.Created + responseAs[String] shouldEqual "bar" + } + + Get("/c") ~> route ~> check { + status shouldEqual StatusCodes.OK + responseAs[String] shouldEqual "baz" + } + } + + "reject-examples" in { + val route = + path("a") { + reject // don't handle here, continue on + } ~ + path("a") { + complete("foo") + } ~ + path("b") { + // trigger a ValidationRejection explicitly + // rather than through the `validate` directive + reject(ValidationRejection("Restricted!")) + } + + Get("/a") ~> route ~> check { + responseAs[String] shouldEqual "foo" + } + + Get("/b") ~> route ~> check { + rejection shouldEqual ValidationRejection("Restricted!") + } + } + + "redirect-examples" in { + val route = + pathPrefix("foo") { + pathSingleSlash { + complete("yes") + } ~ + pathEnd { + redirect("/foo/", StatusCodes.PermanentRedirect) + } + } + + Get("/foo/") ~> route ~> check { + responseAs[String] shouldEqual "yes" + } + + Get("/foo") ~> route ~> check { + status shouldEqual StatusCodes.PermanentRedirect + responseAs[String] shouldEqual """The request, and all future requests should be repeated using this URI.""" + } + } + + "failwith-examples" in { + val route = + path("foo") { + failWith(new RequestProcessingException(StatusCodes.BandwidthLimitExceeded)) + } + + Get("/foo") ~> Route.seal(route) ~> check { + status shouldEqual StatusCodes.BandwidthLimitExceeded + responseAs[String] shouldEqual "Bandwidth limit has been exceeded." + } + } + +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/SchemeDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/SchemeDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..7eb7470536 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/SchemeDirectivesExamplesSpec.scala @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import akka.http.scaladsl.model._ + +class SchemeDirectivesExamplesSpec extends RoutingSpec { + "example-1" in { + val route = + schemeName { scheme => + complete(s"The scheme is '${scheme}'") + } + + Get("https://www.example.com/") ~> route ~> check { + responseAs[String] shouldEqual "The scheme is 'https'" + } + } + + "example-2" in { + val route = + scheme("http") { + extract(_.request.uri) { uri ⇒ + redirect(uri.copy(scheme = "https"), MovedPermanently) + } + } ~ + scheme("https") { + complete(s"Safe and secure!") + } + + Get("http://www.example.com/hello") ~> route ~> check { + status shouldEqual MovedPermanently + header[headers.Location] shouldEqual Some(headers.Location(Uri("https://www.example.com/hello"))) + } + + Get("https://www.example.com/hello") ~> route ~> check { + responseAs[String] shouldEqual "Safe and secure!" + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/SecurityDirectivesExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/SecurityDirectivesExamplesSpec.scala new file mode 100644 index 0000000000..afb7048ce9 --- /dev/null +++ b/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/directives/SecurityDirectivesExamplesSpec.scala @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package docs.http.scaladsl.server +package directives + +import com.typesafe.config.ConfigFactory +import scala.concurrent.Future +import akka.http.scaladsl.model._ +import headers._ + +class SecurityDirectivesExamplesSpec extends RoutingSpec { + "authenticate-custom-user-pass-authenticator" in { + def myUserPassAuthenticator(userPass: Option[UserPass]): Future[Option[String]] = + Future { + if (userPass.exists(up => up.user == "John" && up.pass == "p4ssw0rd")) Some("John") + else None + } + + val route = + Route.seal { + path("secured") { + authenticateBasic(BasicAuth(myUserPassAuthenticator _, realm = "secure site")) { userName => + complete(s"The user is '$userName'") + } + } + } + + Get("/secured") ~> route ~> check { + status shouldEqual StatusCodes.Unauthorized + responseAs[String] shouldEqual "The resource requires authentication, which was not supplied with the request" + header[`WWW-Authenticate`].get.challenges.head shouldEqual HttpChallenge("Basic", "secure site") + } + + val validCredentials = BasicHttpCredentials("John", "p4ssw0rd") + Get("/secured") ~> + addCredentials(validCredentials) ~> // adds Authorization header + route ~> check { + responseAs[String] shouldEqual "The user is 'John'" + } + + val invalidCredentials = BasicHttpCredentials("Peter", "pan") + Get("/secured") ~> + addCredentials(invalidCredentials) ~> // adds Authorization header + route ~> check { + status shouldEqual StatusCodes.Unauthorized + responseAs[String] shouldEqual "The supplied authentication is invalid" + header[`WWW-Authenticate`].get.challenges.head shouldEqual HttpChallenge("Basic", "secure site") + } + } + + "authenticate-from-config" in { + def extractUser(userPass: UserPass): String = userPass.user + val config = ConfigFactory.parseString("John = p4ssw0rd") + + val route = + Route.seal { + path("secured") { + authenticateBasic(BasicAuth(realm = "secure site", config = config, createUser = extractUser _)) { userName => + complete(s"The user is '$userName'") + } + } + } + + Get("/secured") ~> route ~> check { + status shouldEqual StatusCodes.Unauthorized + responseAs[String] shouldEqual "The resource requires authentication, which was not supplied with the request" + header[`WWW-Authenticate`].get.challenges.head shouldEqual HttpChallenge("Basic", "secure site") + } + + val validCredentials = BasicHttpCredentials("John", "p4ssw0rd") + Get("/secured") ~> + addCredentials(validCredentials) ~> // adds Authorization header + route ~> check { + responseAs[String] shouldEqual "The user is 'John'" + } + + val invalidCredentials = BasicHttpCredentials("Peter", "pan") + Get("/secured") ~> + addCredentials(invalidCredentials) ~> // adds Authorization header + route ~> check { + status shouldEqual StatusCodes.Unauthorized + responseAs[String] shouldEqual "The supplied authentication is invalid" + header[`WWW-Authenticate`].get.challenges.head shouldEqual HttpChallenge("Basic", "secure site") + } + } + + "authorize-1" in { + def extractUser(userPass: UserPass): String = userPass.user + val config = ConfigFactory.parseString("John = p4ssw0rd\nPeter = pan") + def hasPermissionToPetersLair(userName: String) = userName == "Peter" + + val route = + Route.seal { + authenticateBasic(BasicAuth(realm = "secure site", config = config, createUser = extractUser _)) { userName => + path("peters-lair") { + authorize(hasPermissionToPetersLair(userName)) { + complete(s"'$userName' visited Peter's lair") + } + } + } + } + + val johnsCred = BasicHttpCredentials("John", "p4ssw0rd") + Get("/peters-lair") ~> + addCredentials(johnsCred) ~> // adds Authorization header + route ~> check { + status shouldEqual StatusCodes.Forbidden + responseAs[String] shouldEqual "The supplied authentication is not authorized to access this resource" + } + + val petersCred = BasicHttpCredentials("Peter", "pan") + Get("/peters-lair") ~> + addCredentials(petersCred) ~> // adds Authorization header + route ~> check { + responseAs[String] shouldEqual "'Peter' visited Peter's lair" + } + } +} diff --git a/akka-docs-dev/rst/scala/code/docs/http/server/ExceptionHandlerExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/server/ExceptionHandlerExamplesSpec.scala deleted file mode 100644 index 6294aa685b..0000000000 --- a/akka-docs-dev/rst/scala/code/docs/http/server/ExceptionHandlerExamplesSpec.scala +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2009-2014 Typesafe Inc. - */ - -package docs.http.server - -import akka.actor.ActorSystem -import akka.http.scaladsl.server.Route -import akka.stream.ActorFlowMaterializer - -object MyHandler { - //# example-1 - import akka.http.scaladsl.model.HttpResponse - import akka.http.scaladsl.model.StatusCodes._ - import akka.http.scaladsl.server._ - import Directives._ - - implicit def myExceptionHandler = - ExceptionHandler { - case e: ArithmeticException => - extractUri { uri => - logWarning(s"Request to $uri could not be handled normally") - complete(HttpResponse(InternalServerError, entity = "Bad numbers, bad result!!!")) - } - } - - object MyApp { - implicit val system = ActorSystem() - import system.dispatcher - implicit val materializer = ActorFlowMaterializer() - - def handler = Route.handlerFlow(``) - } - //# - - def ``: Route = null - def logWarning(str: String): Unit = {} -} - -class ExceptionHandlerExamplesSpec extends RoutingSpec { - import MyHandler._ - - "example" in { - Get() ~> Route.seal(ctx => ctx.complete((1 / 0).toString)) ~> check { - responseAs[String] === "Bad numbers, bad result!!!" - } - } -} diff --git a/akka-docs-dev/rst/scala/code/docs/http/server/RejectionHandlerExamplesSpec.scala b/akka-docs-dev/rst/scala/code/docs/http/server/RejectionHandlerExamplesSpec.scala deleted file mode 100644 index 878ac7219e..0000000000 --- a/akka-docs-dev/rst/scala/code/docs/http/server/RejectionHandlerExamplesSpec.scala +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2009-2014 Typesafe Inc. - */ - -package docs.http.server - -import akka.actor.ActorSystem -import akka.stream.ActorFlowMaterializer - -import akka.http.scaladsl.server.{ Route, MissingCookieRejection } - -import scala.concurrent.ExecutionContext - -object MyRejectionHandler { - //# example-1 - import akka.http.scaladsl.model._ - import akka.http.scaladsl.server._ - import StatusCodes._ - import Directives._ - - implicit val myRejectionHandler = RejectionHandler.newBuilder() - .handle { - case MissingCookieRejection(cookieName) => - complete(HttpResponse(BadRequest, entity = "No cookies, no service!!!")) - } - .result() - - object MyApp { - implicit val system = ActorSystem() - import system.dispatcher - implicit val materializer = ActorFlowMaterializer() - - def handler = Route.handlerFlow(``) - } - //# - - def ``: Route = null -} - -class RejectionHandlerExamplesSpec extends RoutingSpec { - import MyRejectionHandler._ - - "example" in { - Get() ~> Route.seal(reject(MissingCookieRejection("abc"))) ~> check { - responseAs[String] === "No cookies, no service!!!" - } - } - - "example-2" in { - import akka.http.scaladsl.coding.Gzip - - val route = - path("order") { - get { - complete("Received GET") - } ~ - post { - decodeRequestWith(Gzip) { - complete("Received POST") - } - } - } - } -} 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 new file mode 100644 index 0000000000..9fa26f47e8 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/client-side/connection-level.rst @@ -0,0 +1,66 @@ +.. _ConnectionLevelApi: + +Connection-Level Client-Side API +================================ + +The connection-level API is the lowest-level client-side API Akka HTTP provides. It gives you full control over when +HTTP connections are opened and closed and how requests are to be send across which connection. As such it offers the +highest flexibility at the cost of providing the least convenience. + + +Opening HTTP Connections +------------------------ + +With the connection-level API you open a new HTTP connection by materializing a ``Flow`` returned by the +``Http.outgoingConnection(...)`` method. The target endpoint to which a connection is to be opened needs to be +specified as an argument to ``Http.outgoingConnection(...)``. Here is an example: + +.. includecode:: ../../code/docs/http/scaladsl/HttpClientExampleSpec.scala + :include: outgoing-connection-example + +Apart from the host name and port the ``Http.outgoingConnection(...)`` method also allows you to specify socket options +and a number of configuration settings for the connection. + +Note that no connection is attempted until the returned flow is actually materialized! If the flow is materialized +several times then several independent connections will be opened (one per materialization). +If the connection attempt fails, for whatever reason, the materialized flow will be immediately terminated with a +respective exception. + + +Request-Response Cycle +---------------------- + +Once the connection flow has been materialized it is ready to consume ``HttpRequest`` instances from the source it is +attached to. Each request is sent across the connection and incoming responses dispatched to the downstream pipeline. +Of course and as always, back-pressure is adequately maintained across all parts of the +connection. This means that, if the downstream pipeline consuming the HTTP responses is slow, the request source will +eventually be slowed down in sending requests. + +Any errors occurring on the underlying connection are surfaced as exceptions terminating the response stream (and +canceling the request source). + +Note that, if the source produces subsequent requests before the prior responses have arrived, these requests will be +pipelined__ across the connection, which is something that is not supported by all HTTP servers. +Also, if the server closes the connection before responses to all requests have been received this will result in the +response stream being terminated with a truncation error. + +__ http://en.wikipedia.org/wiki/HTTP_pipelining + + +Closing Connections +------------------- + +Akka HTTP actively closes an established connection upon reception of a response containing ``Connection: close`` header. +Of course the connection can also be closed by the server. + +An application can actively trigger the closing of the connection by completing the request stream. In this case the +underlying TCP connection will be closed when the last pending response has been received. + + +Timeouts +-------- + +Currently Akka HTTP doesn't implement client-side request timeout checking itself as this functionality can be regarded +as a more general purpose streaming infrastructure feature. +However, akka-stream should soon provide such a feature. + diff --git a/akka-docs-dev/rst/scala/http/client-side/host-level.rst b/akka-docs-dev/rst/scala/http/client-side/host-level.rst new file mode 100644 index 0000000000..0720c155b9 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/client-side/host-level.rst @@ -0,0 +1,147 @@ +.. _HostLevelApi: + +Host-Level Client-Side API +========================== + +As opposed to the :ref:`ConnectionLevelApi` the host-level API relieves you from manually managing individual HTTP +connections. It autonomously manages a configurable pool of connections to *one particular target endpoint* (i.e. +host/port combination). + + +Requesting a Host Connection Pool +--------------------------------- + +The best way to get a hold of a connection pool to a given target endpoint is the ``Http.cachedHostConnectionPool(...)`` +method, which returns a ``Flow`` that can be "baked" into an application-level stream setup. This flow is also called +a "pool client flow". + +The connection pool underlying a pool client flow is cached. For every ``ActorSystem``, target endpoint and pool +configuration there will never be more than a single pool live at any time. + +Also, the HTTP layer transparently manages idle shutdown and restarting of connection pools as configured. +The client flow instances therefore remain valid throughout the lifetime of the application, i.e. they can be +materialized as often as required and the time between individual materialization is of no importance. + +When you request a pool client flow with ``Http.cachedHostConnectionPool(...)`` Akka HTTP will immediately start +the pool, even before the first client flow materialization. However, this running pool will not actually open the +first connection to the target endpoint until the first request has arrived. + + +Configuring a Host Connection Pool +---------------------------------- + +Apart from the connection-level config settings and socket options there are a number of settings that allow you to +influence the behavior of the connection pool logic itself. +Check out the ``akka.http.client.host-connection-pool`` section of the Akka HTTP :ref:`akka-http-configuration` for +more information about which settings are available and what they mean. + +Note that, if you request pools with different configurations for the same target host you will get *independent* pools. +This means that, in total, your application might open more concurrent HTTP connections to the target endpoint than any +of the individual pool's ``max-connections`` settings allow! + +There is one setting that likely deserves a bit deeper explanation: ``max-open-requests``. +This setting limits the maximum number of requests that can be open at any time for a single connection pool. +If an application calls ``Http.cachedHostConnectionPool(...)`` 3 times (with the same endpoint and settings) it will get +back 3 different client flow instances for the same pool. If each of these client flows is then materialized 4 times +(concurrently) the application will have 12 concurrently running client flow materializations. +All of these share the resources of the single pool. + +This means that, if the pool's ``pipelining-limit`` is left at ``1``, no more than 12 requests can be open at any time. +With a ``pipelining-limit`` of ``8`` and 12 concurrent client flow materializations the theoretical open requests +maximum is 96. + +The ``max-open-requests`` config setting allows for applying a hard limit which serves mainly as a protection against +erroneous connection pool use, e.g. because the application is materializing too many client flows that all compete for +the same pooled connections. + +.. _using-a-host-connection-pool: + +Using a Host Connection Pool +---------------------------- + +The "pool client flow" returned by ``Http.cachedHostConnectionPool(...)`` has the following type:: + + Flow[(HttpRequest, T), (Try[HttpResponse], T), HostConnectionPool] + +This means it consumes tuples of type ``(HttpRequest, T)`` and produces tuples of type ``(Try[HttpResponse], T)`` +which might appear more complicated than necessary on first sight. +The reason why the pool API includes objects of custom type ``T`` on both ends lies in the fact that the underlying +transport usually comprises more than a single connection and as such the pool client flow often generates responses in +an order that doesn't directly match the consumed requests. +We could have built the pool logic in a way that reorders responses according to their requests before dispatching them +to the application, but this would have meant that a single slow response could block the delivery of potentially many +responses that would otherwise be ready for consumption by the application. + +In order to prevent unnecessary head-of-line blocking the pool client-flow is allowed to dispatch responses as soon as +they arrive, independently of the request order. Of course this means that there needs to be another way to associate a +response with its respective request. The way that this is done is by allowing the application to pass along a custom +"context" object with the request, which is then passed back to the application with the respective response. +This context object of type ``T`` is completely opaque to Akka HTTP, i.e. you can pick whatever works best for your +particular application scenario. + + +Connection Allocation Logic +--------------------------- + +This is how Akka HTTP allocates incoming requests to the available connection "slots": + +1. If there is a connection alive and currently idle then schedule the request across this connection. +2. If no connection is idle and there is still an unconnected slot then establish a new connection. +3. If all connections are already established and "loaded" with other requests then pick the connection with the least + open requests (< the configured ``pipelining-limit``) that only has requests with idempotent methods scheduled to it, + if there is one. +4. Otherwise apply back-pressure to the request source, i.e. stop accepting new requests. + +For more information about scheduling more than one request at a time across a single connection see +`this wikipedia entry on HTTP pipelining`__. + +__ http://en.wikipedia.org/wiki/HTTP_pipelining + + + +Retrying a Request +------------------ + +If the ``max-retries`` pool config setting is greater than zero the pool retries idempotent requests for which +a response could not be successfully retrieved. Idempotent requests are those whose HTTP method is defined to be +idempotent by the HTTP spec, which are all the ones currently modelled by Akka HTTP except for the ``POST``, ``PATCH`` +and ``CONNECT`` methods. + +When a response could not be received for a certain request there are essentially three possible error scenarios: + +1. The request got lost on the way to the server. +2. The server experiences a problem while processing the request. +3. The response from the server got lost on the way back. + +Since the host connector cannot know which one of these possible reasons caused the problem and therefore ``PATCH`` and +``POST`` requests could have already triggered a non-idempotent action on the server these requests cannot be retried. + +In these cases, as well as when all retries have not yielded a proper response, the pool produces a failed ``Try`` +(i.e. a ``scala.util.Failure``) together with the custom request context. + + +Pool Shutdown +------------- + +Completing a pool client flow will simply detach the flow from the pool. The connection pool itself will continue to run +as it may be serving other client flows concurrently or in the future. Only after the configured ``idle-timeout`` for +the pool has expired will Akka HTTP automatically terminate the pool and free all its resources. + +If a new client flow is requested with ``Http.cachedHostConnectionPool(...)`` or if an already existing client flow is +re-materialized the respective pool is automatically and transparently restarted. + +In addition to the automatic shutdown via the configured idle timeouts it's also possible to trigger the immediate +shutdown of specific pool by calling ``shutdown()`` on the ``Http.HostConnectionPool`` instance that a pool client +flow materializes into. This ``shutdown()`` call produces a ``Future[Unit]`` which is fulfilled when the pool +termination has been completed. + +It's also possible to trigger the immediate termination of *all* connection pools in the ``ActorSystem`` at the same +time by calling ``Http.shutdownAllConnectionPools()``. This call too produces a ``Future[Unit]`` which is fulfilled when +all pools have terminated. + + +Example +------- + +.. includecode:: ../../code/docs/http/scaladsl/HttpClientExampleSpec.scala + :include: host-level-example \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/client-side/https-support.rst b/akka-docs-dev/rst/scala/http/client-side/https-support.rst new file mode 100644 index 0000000000..06c18642a5 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/client-side/https-support.rst @@ -0,0 +1,4 @@ +Client-Side HTTPS Support +========================= + +TODO \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/client-side/index.rst b/akka-docs-dev/rst/scala/http/client-side/index.rst new file mode 100644 index 0000000000..d5be2b40d1 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/client-side/index.rst @@ -0,0 +1,31 @@ +.. _http-client-side: + +Consuming HTTP-based Services (Client-Side) +=========================================== + +All client-side functionality of Akka HTTP, for consuming HTTP-based services offered by other systems, is currently +provided by the ``akka-http-core`` module. + +Depending your application's specific needs you can choose from three different API levels: + +:ref:`ConnectionLevelApi` + for full-control over when HTTP connections are opened/closed and how requests are scheduled across them + +:ref:`HostLevelApi` + for letting Akka HTTP manage a connection-pool to *one specific* host/port endpoint + +:ref:`RequestLevelApi` + for letting Akka HTTP perform all connection management + +You can interact with different API levels at the same time and, independently of which API level you choose, +Akka HTTP will happily handle many thousand concurrent connections to a single or many different hosts. + + +.. toctree:: + :maxdepth: 2 + + connection-level + host-level + request-level + https-support + websocket-support \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/client-side/request-level.rst b/akka-docs-dev/rst/scala/http/client-side/request-level.rst new file mode 100644 index 0000000000..96f4abfa46 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/client-side/request-level.rst @@ -0,0 +1,48 @@ +.. _RequestLevelApi: + +Request-Level Client-Side API +============================= + +The request-level API is the most convenient way of using Akka HTTP's client-side. It internally builds upon the +:ref:`HostLevelApi` to provide you with a simple and easy-to-use way of retrieving HTTP responses from remote servers. +Depending on your preference you can pick the flow-based or the future-based variant. + + +Flow-Based Variant +------------------ + +The flow-based variant of the request-level client-side API is presented by the ``Http.superPool(...)`` method. +It creates a new "super connection pool flow", which routes incoming requests to a (cached) host connection pool +depending on their respective effective URI. + +The ``Flow`` returned by ``Http.superPool(...)`` is very similar to the one from the :ref:`HostLevelApi`, so the +:ref:`using-a-host-connection-pool` section also applies here. + +However, there is one notable difference between a "host connection pool client flow" for the host-level API and a +"super-pool flow": +Since in the former case the flow has an implicit target host context the requests it takes don't need to have absolute +URIs or a valid ``Host`` header. The host connection pool will automatically add a ``Host`` header if required. + +For a super-pool flow this is not the case. All requests to a super-pool must either have an absolute URI or a valid +``Host`` header, because otherwise it'd be impossible to find out which target endpoint to direct the request to. + + +Future-Based Variant +-------------------- + +Sometimes your HTTP client needs are very basic. You simply need the HTTP response for a certain request and don't +want to bother with setting up a full-blown streaming infrastructure. + +For these cases Akka HTTP offers the ``Http.singleRequest(...)`` method, which simply turns an ``HttpRequest`` instance +into ``Future[HttpResponse]``. Internally the request is dispatched across the (cached) host connection pool for the +request's effective URI. + +Just like in the case of the super-pool flow described above the request must have either an absolute URI or a valid +``Host`` header, otherwise the returned future will be completed with an error. + + +Example +------- + +.. includecode:: ../../code/docs/http/scaladsl/HttpClientExampleSpec.scala + :include: single-request-example \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/client-side/websocket-support.rst b/akka-docs-dev/rst/scala/http/client-side/websocket-support.rst new file mode 100644 index 0000000000..69cdb560eb --- /dev/null +++ b/akka-docs-dev/rst/scala/http/client-side/websocket-support.rst @@ -0,0 +1,4 @@ +Client-Side WebSocket Support +============================= + +TODO \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/client.rst b/akka-docs-dev/rst/scala/http/client.rst deleted file mode 100644 index 76cecbd12d..0000000000 --- a/akka-docs-dev/rst/scala/http/client.rst +++ /dev/null @@ -1,4 +0,0 @@ -Client API -========== - -(todo) \ 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 new file mode 100644 index 0000000000..c49b26f6c6 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/common/de-coding.rst @@ -0,0 +1,4 @@ +Encoding / Decoding +=================== + +... \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/common/http-model.rst b/akka-docs-dev/rst/scala/http/common/http-model.rst new file mode 100644 index 0000000000..8fc9fca17f --- /dev/null +++ b/akka-docs-dev/rst/scala/http/common/http-model.rst @@ -0,0 +1,230 @@ +.. _http-model-scala: + +HTTP Model +========== + +Akka HTTP model contains a deeply structured, fully immutable, case-class based model of all the major HTTP data +structures, like HTTP requests, responses and common headers. +It lives in the *akka-http-core* module and forms the basis for most of Akka HTTP's APIs. + +Overview +-------- + +Since akka-http-core provides the central HTTP data structures you will find the following import in quite a +few places around the code base (and probably your own code as well): + +.. includecode:: ../../code/docs/http/scaladsl/ModelSpec.scala + :include: import-model + +This brings all of the most relevant types in scope, mainly: + +- ``HttpRequest`` and ``HttpResponse``, the central message model +- ``headers``, the package containing all the predefined HTTP header models and supporting types +- Supporting types like ``Uri``, ``HttpMethods``, ``MediaTypes``, ``StatusCodes``, etc. + +A common pattern is that the model of a certain entity is represented by an immutable type (class or trait), +while the actual instances of the entity defined by the HTTP spec live in an accompanying object carrying the name of +the type plus a trailing plural 's'. + +For example: + +- Defined ``HttpMethod`` instances live in the ``HttpMethods`` object. +- Defined ``HttpCharset`` instances live in the ``HttpCharsets`` object. +- Defined ``HttpEncoding`` instances live in the ``HttpEncodings`` object. +- Defined ``HttpProtocol`` instances live in the ``HttpProtocols`` object. +- Defined ``MediaType`` instances live in the ``MediaTypes`` object. +- Defined ``StatusCode`` instances live in the ``StatusCodes`` object. + +HttpRequest +----------- + +``HttpRequest`` and ``HttpResponse`` are the basic case classes representing HTTP messages. + +An ``HttpRequest`` consists of + + - a method (GET, POST, etc.) + - a URI + - a seq of headers + - an entity (body data) + - a protocol + +Here are some examples how to construct an ``HttpRequest``: + +.. includecode:: ../../code/docs/http/scaladsl/ModelSpec.scala + :include: construct-request + +All parameters of ``HttpRequest.apply`` have default values set, so ``headers`` for example don't need to be specified +if there are none. Many of the parameters types (like ``HttpEntity`` and ``Uri``) define implicit conversions +for common use cases to simplify the creation of request and response instances. + +HttpResponse +------------ + +An ``HttpResponse`` consists of + + - a status code + - a seq of headers + - an entity (body data) + - a protocol + +Here are some examples how to construct an ``HttpResponse``: + +.. includecode:: ../../code/docs/http/scaladsl/ModelSpec.scala + :include: construct-response + +In addition to the simple ``HttpEntity`` constructors create an entity from a fixed ``String`` or ``ByteString`` shown +as here the Akka HTTP model defines a number of subclasses of ``HttpEntity`` which allow body data to be specified as a +stream of bytes. + + +.. _HttpEntity: + +HttpEntity +---------- + +An ``HttpEntity`` carries the data bytes of a message together with its Content-Type and, if known, its Content-Length. +In Akka HTTP there are five different kinds of entities which model the various ways that message content can be +received or sent: + +HttpEntity.Strict + The simplest entity, which is used when all the entity are already available in memory. + It wraps a plain ``ByteString`` and represents a standard, unchunked entity with a known ``Content-Length``. + + +HttpEntity.Default + The general, unchunked HTTP/1.1 message entity. + It has a known length and presents its data as a ``Source[ByteString]`` which can only materialized once. + It is an error if the provided source doesn't produce exactly as many bytes as specified. + On the wire, a ``Strict`` entity and a ``Default`` entity cannot be distinguished. + + +HttpEntity.Chunked + The model for HTTP/1.1 `chunked content`__ (i.e. sent with ``Transfer-Encoding: chunked``). + The content length is unknown and the individual chunks are presented as a ``Source[HttpEntity.ChunkStreamPart]``. + A ``ChunkStreamPart`` is either a non-empty ``Chunk`` or a ``LastChunk`` containing optional trailer headers. + The stream consists of zero or more ``Chunked`` parts and can be terminated by an optional ``LastChunk`` part. + + +HttpEntity.CloseDelimited + An unchunked entity of unknown length that is implicitly delimited by closing the connection (``Connection: close``). + The content data are presented as a ``Source[ByteString]``. + Since the connection must be closed after sending an entity of this type it can only be used on the server-side for + sending a response. + Also, the main purpose of ``CloseDelimited`` entities is compatibility with HTTP/1.0 peers, which do not support + chunked transfer encoding. If you are building a new application and are not constrained by legacy requirements you + shouldn't rely on ``CloseDelimited`` entities, since implicit terminate-by-connection-close is not a robust way of + signaling response end, especially in the presence of proxies. Additionally this type of entity prevents connection + reuse which can seriously degrade performance. Use ``HttpEntity.Chunked`` instead! + + +HttpEntity.IndefiniteLength + A streaming entity of unspecified length for use in a ``Multipart.BodyPart``. + +__ http://tools.ietf.org/html/rfc7230#section-4.1 + +Entity types ``Strict``, ``Default``, and ``Chunked`` are a subtype of ``HttpEntity.Regular`` which allows to use them +for requests and responses. In contrast, ``HttpEntity.CloseDelimited`` can only be used for responses. + +Streaming entity types (i.e. all but ``Strict``) cannot be shared or serialized. To create a strict, sharable copy of an +entity or message use ``HttpEntity.toStrict`` or ``HttpMessage.toStrict`` which returns a ``Future`` of the object with +the body data collected into a ``ByteString``. + +The ``HttpEntity`` companion object contains several helper constructors to create entities from common types easily. + +You can pattern match over the subtypes of ``HttpEntity`` if you want to provide special handling for each of the +subtypes. However, in many cases a recipient of an ``HttpEntity`` doesn't care about of which subtype an entity is +(and how data is transported exactly on the HTTP layer). Therefore, a general +``HttpEntity::dataBytes: Source[ByteString, Any]`` is provided which allows access to the data of an entity regardless +of its concrete subtype. + +.. note:: + + When to use which subtype? + - Use ``Strict`` if the amount of data is "small" and already available in memory (e.g. as a ``String`` or ``ByteString``) + - Use ``Default`` if the data is generated by a streaming data source and the size of the data is known + - Use ``Chunked`` for an entity of unknown length + - Use ``CloseDelimited`` for a response as a legacy alternative to ``Chunked`` if the client doesn't support + chunked transfer encoding. Otherwise use ``Chunked``! + - In a ``Multipart.Bodypart`` use ``IndefiniteLength`` for content of unknown length. + +.. caution:: + + When you receive a non-strict message from a connection then additional data are only read from the network when you + request them by consuming the entity data stream. This means that, if you *don't* consume the entity stream then the + connection will effectively be stalled. In particular no subsequent message (request or response) will be read from + the connection as the entity of the current message "blocks" the stream. + Therefore you must make sure that you always consume the entity data, even in the case that you are not actually + interested in it! + + +Header Model +------------ + +Akka HTTP contains a rich model of the most common HTTP headers. Parsing and rendering is done automatically so that +applications don't need to care for the actual syntax of headers. Headers not modelled explicitly are represented +as a ``RawHeader`` (which is essentially a String/String name/value pair). + +See these examples of how to deal with headers: + +.. includecode:: ../../code/docs/http/scaladsl/ModelSpec.scala + :include: headers + + +HTTP Headers +------------ + +When the Akka HTTP server receives an HTTP request it tries to parse all its headers into their respective +model classes. Independently of whether this succeeds or not, the HTTP layer will +always pass on all received headers to the application. Unknown headers as well as ones with invalid syntax (according +to the header parser) will be made available as ``RawHeader`` instances. For the ones exhibiting parsing errors a +warning message is logged depending on the value of the ``illegal-header-warnings`` config setting. + +Some headers have special status in HTTP and are therefore treated differently from "regular" headers: + +Content-Type + The Content-Type of an HTTP message is modeled as the ``contentType`` field of the ``HttpEntity``. + The ``Content-Type`` header therefore doesn't appear in the ``headers`` sequence of a message. + Also, a ``Content-Type`` header instance that is explicitly added to the ``headers`` of a request or response will + not be rendered onto the wire and trigger a warning being logged instead! + +Transfer-Encoding + Messages with ``Transfer-Encoding: chunked`` are represented via the ``HttpEntity.Chunked`` entity. + As such chunked messages that do not have another deeper nested transfer encoding will not have a ``Transfer-Encoding`` + header in their ``headers`` sequence. + Similarly, a ``Transfer-Encoding`` header instance that is explicitly added to the ``headers`` of a request or + response will not be rendered onto the wire and trigger a warning being logged instead! + +Content-Length + The content length of a message is modelled via its :ref:`HttpEntity`. As such no ``Content-Length`` header will ever + be part of a message's ``header`` sequence. + Similarly, a ``Content-Length`` header instance that is explicitly added to the ``headers`` of a request or + response will not be rendered onto the wire and trigger a warning being logged instead! + +Server + A ``Server`` header is usually added automatically to any response and its value can be configured via the + ``akka.http.server.server-header`` setting. Additionally an application can override the configured header with a + custom one by adding it to the response's ``header`` sequence. + +User-Agent + A ``User-Agent`` header is usually added automatically to any request and its value can be configured via the + ``akka.http.client.user-agent-header`` setting. Additionally an application can override the configured header with a + custom one by adding it to the request's ``header`` sequence. + +Date + The ``Date`` response header is added automatically but can be overridden by supplying it manually. + +Connection + On the server-side Akka HTTP watches for explicitly added ``Connection: close`` response headers and as such honors + the potential wish of the application to close the connection after the respective response has been sent out. + The actual logic for determining whether to close the connection is quite involved. It takes into account the + request's method, protocol and potential ``Connection`` header as well as the response's protocol, entity and + potential ``Connection`` header. See `this test`__ for a full table of what happens when. + +__ @github@/akka-http-core/src/test/scala/akka/http/impl/engine/rendering/ResponseRendererSpec.scala#L422 + + +Parsing / Rendering +------------------- + +Parsing and rendering of HTTP data structures is heavily optimized and for most types there's currently no public API +provided to parse (or render to) Strings or byte arrays. diff --git a/akka-docs-dev/rst/scala/http/common/index.rst b/akka-docs-dev/rst/scala/http/common/index.rst new file mode 100644 index 0000000000..2688e1f75a --- /dev/null +++ b/akka-docs-dev/rst/scala/http/common/index.rst @@ -0,0 +1,21 @@ +.. _http-scala-common: + +Common Abstractions (Client- and Server-Side) +============================================= + +HTTP and related specifications define a great number of concepts and functionality that is not specific to either +HTTP's client- or server-side since they are meaningful on both end of an HTTP connection. +The documentation for their counterparts in Akka HTTP lives in this section rather than in the ones for the +:ref:`Client-Side API `, :ref:`http-low-level-server-side-api` or :ref:`http-high-level-server-side-api`, +which are specific to one side only. + + +.. toctree:: + :maxdepth: 2 + + http-model + marshalling + unmarshalling + de-coding + json-support + xml-support \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/common/json-support.rst b/akka-docs-dev/rst/scala/http/common/json-support.rst new file mode 100644 index 0000000000..a98126977d --- /dev/null +++ b/akka-docs-dev/rst/scala/http/common/json-support.rst @@ -0,0 +1,4 @@ +JSON Support +============ + +... \ 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 new file mode 100644 index 0000000000..10674cf407 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/common/marshalling.rst @@ -0,0 +1,6 @@ +.. _http-marshalling-scala: + +Marshalling +=========== + +... \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/common/unmarshalling.rst b/akka-docs-dev/rst/scala/http/common/unmarshalling.rst new file mode 100644 index 0000000000..cc80ec53cc --- /dev/null +++ b/akka-docs-dev/rst/scala/http/common/unmarshalling.rst @@ -0,0 +1,6 @@ +.. _http-unmarshalling-scala: + +Unmarshalling +============= + +... \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/common/xml-support.rst b/akka-docs-dev/rst/scala/http/common/xml-support.rst new file mode 100644 index 0000000000..5c5b0b2581 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/common/xml-support.rst @@ -0,0 +1,4 @@ +XML Support +=========== + +... \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/configuration.rst b/akka-docs-dev/rst/scala/http/configuration.rst new file mode 100644 index 0000000000..f3061585d2 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/configuration.rst @@ -0,0 +1,28 @@ +.. _akka-http-configuration: + +Configuration +============= + +Just like any other Akka module Akka HTTP is configured via `Typesafe Config`_. +Usually this means that you provide an ``application.conf`` which contains all the application-specific settings that +differ from the default ones provided by the reference configuration files from the individual Akka modules. + +These are the relevant default configuration values for the Akka HTTP modules. + +akka-http-core +~~~~~~~~~~~~~~ + +.. literalinclude:: ../../../../akka-http-core/src/main/resources/reference.conf + :language: none + + +akka-http-core-scala +~~~~~~~~~~~~~~~~~~~~ + +.. literalinclude:: ../../../../akka-http-scala/src/main/resources/reference.conf + :language: none + + +The other Akka HTTP modules do not offer any configuration via `Typesafe Config`_. + +.. _Typesafe Config: https://github.com/typesafehub/config \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/directives.rst b/akka-docs-dev/rst/scala/http/directives.rst deleted file mode 100644 index 113854efcf..0000000000 --- a/akka-docs-dev/rst/scala/http/directives.rst +++ /dev/null @@ -1,138 +0,0 @@ -.. _Directives: - -Directives -========== - -A "Directive" is a small building block to construct arbitrarily complex route structures. -Here is a simple example of a route built from directives: - -.. includecode2:: ../code/docs/http/server/DirectiveExamplesSpec.scala - :snippet: example-1 - -The general anatomy of a directive is as follows:: - - name(arguments) { extractions => - ... // inner Route - } - -It has a name, zero or more arguments and optionally an inner Route. Additionally directives can "extract" a number of -values and make them available to their inner routes as function arguments. When seen "from the outside" a directive -with its inner Route form an expression of type ``Route``. - -What Directives do ------------------- - -A directive can do one or more of the following: - -.. rst-class:: wide - -* Transform the incoming ``RequestContext`` before passing it on to its inner Route -* Filter the ``RequestContext`` according to some logic, i.e. only pass on certain requests and reject all others -* Extract values from the ``RequestContext`` and make them available to its inner Route as "extractions" -* Complete the request - -The first point deserves some more discussion. The ``RequestContext`` is the central object that is passed on through a -route structure (also see :ref:`RequestContext`). When a directive (or better the Route it built) receives a ``RequestContext`` -it can decide to pass this instance on unchanged to its inner Route or it can create a copy of the ``RequestContext`` instance, -with one or more changes, and pass on this copy to its inner Route. Typically this is good for two things: - -* Transforming the ``HttpRequest`` instance -* "Hooking in" a response transformation function that changes the ``RouteResponse`` (and therefore the response). - -This means a ``Directive`` completely wraps the functionality of its inner routes and can apply arbitrarily complex -transformations, both (or either) on the request and on the response side. - -Composing Directives --------------------- - -As you have seen from the examples presented so far the "normal" way of composing directives is nesting. Let's take -another look at the example from above: - -.. includecode2:: ../code/docs/http/server/DirectiveExamplesSpec.scala - :snippet: example-2 - -Here the ``get`` and ``put`` directives are chained together with the ``~`` operator to form a higher-level route that -serves as the inner Route of the ``path`` directive. To make this structure more explicit you could also write the whole -thing like this: - -.. includecode2:: ../code/docs/http/server/DirectiveExamplesSpec.scala - :snippet: example-3 - -What you can't see from this snippet is that directives are not implemented as simple methods but rather as stand-alone -objects of type ``Directive``. This gives you more flexibility when composing directives. For example you can -also use the ``|`` operator on directives. Here is yet another way to write the example: - -.. includecode2:: ../code/docs/http/server/DirectiveExamplesSpec.scala - :snippet: example-4 - -If you have a larger route structure where the ``(get | put)`` snippet appears several times you could also factor it -out like this: - -.. includecode2:: ../code/docs/http/server/DirectiveExamplesSpec.scala - :snippet: example-5 - -As an alternative to nesting you can also use the `&` operator: - -.. includecode2:: ../code/docs/http/server/DirectiveExamplesSpec.scala - :snippet: example-6 - -And once again, you can factor things out if you want: - -.. includecode2:: ../code/docs/http/server/DirectiveExamplesSpec.scala - :snippet: example-7 - -This type of combining directives with the ``|`` and ``&`` operators as well as "saving" more complex directive -configurations as a ``val`` works across the board, with all directives taking inner routes. - -There is one more "ugly" thing remaining in our snippet: we have to fall back to the lowest-level route definition, -directly manipulating the ``RequestContext``, in order to get to the request method. It'd be nicer if we could somehow -"extract" the method name in a special directive, so that we can express our inner-most route with a simple -``complete``. As it turns out this is easy with the ``extract`` directive: - -.. includecode2:: ../code/docs/http/server/DirectiveExamplesSpec.scala - :snippet: example-8 - -Or differently: - -.. includecode2:: ../code/docs/http/server/DirectiveExamplesSpec.scala - :snippet: example-9 - -Now, pushing the "factoring out" of directive configurations to its extreme, we end up with this: - -.. includecode2:: ../code/docs/http/server/DirectiveExamplesSpec.scala - :snippet: example-A - -Note that going this far with "compressing" several directives into a single one probably doesn't result in the most -readable and therefore maintainable routing code. It might even be that the very first of this series of examples -is in fact the most readable one. - -Still, the purpose of the exercise presented here is to show you how flexible directives can be and how you can -use their power to define your web service behavior at the level of abstraction that is right for **your** application. - - -Type Safety of Directives -------------------------- - -When you combine directives with the ``|`` and ``&`` operators the routing DSL makes sure that all extractions work as -expected and logical constraints are enforced at compile-time. - -For example you cannot ``|`` a directive producing an extraction with one that doesn't:: - - val route = path("order" / IntNumber) | get // doesn't compile - -Also the number of extractions and their types have to match up:: - - val route = path("order" / IntNumber) | path("order" / DoubleNumber) // doesn't compile - val route = path("order" / IntNumber) | parameter('order.as[Int]) // ok - -When you combine directives producing extractions with the ``&`` operator all extractions will be properly gathered up:: - - val order = path("order" / IntNumber) & parameters('oem, 'expired ?) - val route = - order { (orderId, oem, expired) => - ... - } - -Directives offer a great way of constructing your web service logic from small building blocks in a plug and play -fashion while maintaining DRYness and full type-safety. If the large range of :ref:`Predefined Directives` does not -fully satisfy your needs you can also very easily create :ref:`Custom Directives`. diff --git a/akka-docs-dev/rst/scala/http/directives/alphabetically.rst b/akka-docs-dev/rst/scala/http/directives/alphabetically.rst deleted file mode 100644 index 787df8fde9..0000000000 --- a/akka-docs-dev/rst/scala/http/directives/alphabetically.rst +++ /dev/null @@ -1,161 +0,0 @@ -.. _Predefined Directives: - -Predefined Directives (alphabetically) -====================================== - -.. rst-class:: table table-striped - -====================================== ================================================================================= -Directive Description -====================================== ================================================================================= -:ref:`-cancelAllRejections-` Adds a ``TransformationRejection`` to rejections from its inner Route, which - cancels other rejections according to a predicate function -:ref:`-cancelRejection-` Adds a ``TransformationRejection`` cancelling all rejections equal to a given one -:ref:`-clientIP-` Extracts the IP address of the client from either the ``X-Forwarded-For``, - ``Remote-Address`` or ``X-Real-IP`` request header -:ref:`-complete-` Completes the request with a given response, several overloads -:ref:`-compressResponse-` Compresses responses coming back from its inner Route using either ``Gzip`` or - ``Deflate`` unless the request explicitly sets ``Accept-Encoding`` to ``identity``. -:ref:`-compressResponseIfRequested-` Compresses responses coming back from its inner Route using either ``Gzip`` or - ``Deflate``, but only when the request explicitly accepts one of them. -:ref:`-conditional-` Depending on the given ETag and Last-Modified values responds with - ``304 Not Modified`` if the request comes with the respective conditional headers. -:ref:`-cookie-` Extracts an ``HttpCookie`` with a given name or rejects if no such cookie is - present in the request -:ref:`-decodeRequest-` Decompresses incoming requests using a given Decoder -:ref:`-decompressRequest-` Decompresses incoming requests using either ``Gzip``, ``Deflate``, or ``NoEncoding`` -:ref:`-delete-` Rejects all non-DELETE requests -:ref:`-deleteCookie-` Adds a ``Set-Cookie`` header expiring the given cookie to all ``HttpResponse`` - replies of its inner Route -:ref:`-encodeResponse-` Compresses responses coming back from its inner Route using a given Encoder -:ref:`-entity-` Unmarshalls the requests entity according to a given definition, rejects in - case of problems -:ref:`-extract-` Extracts a single value from the ``RequestContext`` using a function - ``RequestContext => T`` -:ref:`-extractRequest-` Extracts the complete request -:ref:`-failWith-` Bubbles the given error up the response chain, where it is dealt with by the - closest :ref:`-handleExceptions-` directive and its ExceptionHandler -:ref:`-formField-` Extracts the value of an HTTP form field, rejects if the request doesn't come - with a field matching the definition -:ref:`-formFields-` Same as :ref:`-formField-`, except for several fields at once -:ref:`-get-` Rejects all non-GET requests -:ref:`-getFromBrowseableDirectories-` Same as :ref:`-getFromBrowseableDirectory-`, but allows for serving the "union" - of several directories as one single "virtual" one -:ref:`-getFromBrowseableDirectory-` Completes GET requests with the content of a file underneath a given directory, - renders directory contents as browsable listings -:ref:`-getFromDirectory-` Completes GET requests with the content of a file underneath a given directory -:ref:`-getFromFile-` Completes GET requests with the content of a given file -:ref:`-getFromResource-` Completes GET requests with the content of a given resource -:ref:`-getFromResourceDirectory-` Same as :ref:`-getFromDirectory-` except that the file is not fetched from the - file system but rather from a "resource directory" -:ref:`-handleExceptions-` Converts exceptions thrown during evaluation of its inner Route into - ``HttpResponse`` replies using a given ExceptionHandler -:ref:`-handleRejections-` Converts rejections produced by its inner Route into ``HttpResponse`` replies - using a given RejectionHandler -:ref:`-handleWith-` Completes the request using a given function. Uses the in-scope ``Unmarshaller`` - and ``Marshaller`` for converting to and from the function -:ref:`-head-` Rejects all non-HEAD requests -:ref:`-headerValue-` Extracts an HTTP header value using a given function, rejects if no value can - be extracted -:ref:`-headerValueByName-` Extracts an HTTP header value by selecting a header by name -:ref:`-headerValueByType-` Extracts an HTTP header value by selecting a header by type -:ref:`-headerValuePF-` Same as :ref:`-headerValue-`, but with a ``PartialFunction`` -:ref:`-host-` Rejects all requests with a hostname different from a given definition, - can extract the hostname using a regex pattern -:ref:`-hostName-` Extracts the hostname part of the requests ``Host`` header value -:ref:`-listDirectoryContents-` Completes GET requests with a unified listing of the contents of one or more - given directories -:ref:`-logRequest-` Produces a log entry for every incoming request -:ref:`-logRequestResult-` Produces a log entry for every response or rejection coming back from its inner - route, allowing for coalescing with the corresponding request -:ref:`-logResult-` Produces a log entry for every response or rejection coming back from its inner - route -:ref:`-mapResponse-` Transforms the ``HttpResponse`` coming back from its inner Route -:ref:`-mapResponseEntity-` Transforms the entity of the ``HttpResponse`` coming back from its inner Route -:ref:`-mapResponseHeaders-` Transforms the headers of the ``HttpResponse`` coming back from its inner Route -:ref:`-mapInnerRoute-` Transforms its inner Route with a ``Route => Route`` function -:ref:`-mapRejections-` Transforms all rejections coming back from its inner Route -:ref:`-mapRequest-` Transforms the incoming ``HttpRequest`` -:ref:`-mapRequestContext-` Transforms the ``RequestContext`` -:ref:`-mapRouteResult-` Transforms all responses coming back from its inner Route with a ``Any => Any`` - function -:ref:`-mapRouteResultPF-` Same as :ref:`-mapRouteResult-`, but with a ``PartialFunction`` -:ref:`-method-` Rejects if the request method does not match a given one -:ref:`-overrideMethodWithParameter-` Changes the HTTP method of the request to the value of the specified query string - parameter -:ref:`-onComplete-` "Unwraps" a ``Future[T]`` and runs its inner route after future completion with - the future's value as an extraction of type ``Try[T]`` -:ref:`-onFailure-` "Unwraps" a ``Future[T]`` and runs its inner route when the future has failed - with the future's failure exception as an extraction of type ``Throwable`` -:ref:`-onSuccess-` "Unwraps" a ``Future[T]`` and runs its inner route after future completion with - the future's value as an extraction of type ``T`` -:ref:`-optionalCookie-` Extracts an ``HttpCookie`` with a given name, if the cookie is not present in the - request extracts ``None`` -:ref:`-optionalHeaderValue-` Extracts an optional HTTP header value using a given function -:ref:`-optionalHeaderValueByName-` Extracts an optional HTTP header value by selecting a header by name -:ref:`-optionalHeaderValueByType-` Extracts an optional HTTP header value by selecting a header by type -:ref:`-optionalHeaderValuePF-` Extracts an optional HTTP header value using a given partial function -:ref:`-options-` Rejects all non-OPTIONS requests -:ref:`-parameter-` Extracts the value of a request query parameter, rejects if the request doesn't - come with a parameter matching the definition -:ref:`-parameterMap-` Extracts the requests query parameters as a ``Map[String, String]`` -:ref:`-parameterMultiMap-` Extracts the requests query parameters as a ``Map[String, List[String]]`` -:ref:`-parameters-` Same as :ref:`-parameter-`, except for several parameters at once -:ref:`-parameterSeq-` Extracts the requests query parameters as a ``Seq[(String, String)]`` -:ref:`-pass-` Does nothing, i.e. passes the ``RequestContext`` unchanged to its inner Route -:ref:`-patch-` Rejects all non-PATCH requests -:ref:`-path-` Extracts zero+ values from the ``unmatchedPath`` of the ``RequestContext`` - according to a given ``PathMatcher``, rejects if no match -:ref:`-pathEnd-` Only passes on the request to its inner route if the request path has been - matched completely, rejects otherwise -:ref:`-pathEndOrSingleSlash-` Only passes on the request to its inner route if the request path has been matched - completely or only consists of exactly one remaining slash, rejects otherwise -:ref:`-pathPrefix-` Same as :ref:`-path-`, but also matches (and consumes) prefixes of the unmatched - path (rather than only the complete unmatched path at once) -:ref:`-pathPrefixTest-` Like :ref:`-pathPrefix-` but without "consumption" of the matched path (prefix). -:ref:`-pathSingleSlash-` Only passes on the request to its inner route if the request path consists of - exactly one remaining slash -:ref:`-pathSuffix-` Like as :ref:`-pathPrefix-`, but for suffixes rather than prefixed of the - unmatched path -:ref:`-pathSuffixTest-` Like :ref:`-pathSuffix-` but without "consumption" of the matched path (suffix). -:ref:`-post-` Rejects all non-POST requests -:ref:`-produce-` Uses the in-scope marshaller to extract a function that can be used for - completing the request with an instance of a custom type -:ref:`-provide-` Injects a single value into a directive, which provides it as an extraction -:ref:`-put-` Rejects all non-PUT requests -:ref:`-rawPathPrefix-` Applies a given ``PathMatcher`` directly to the unmatched path of the - ``RequestContext``, i.e. without implicitly consuming a leading slash -:ref:`-rawPathPrefixTest-` Checks whether the unmatchedPath of the ``RequestContext`` has a prefix matched - by a ``PathMatcher`` -:ref:`-redirect-` Completes the request with redirection response of the given type to a given URI -:ref:`-reject-` Rejects the request with a given set of rejections -:ref:`-rejectEmptyResponse-` Converts responses with an empty entity into a rejection -:ref:`-requestEncodedWith-` Rejects the request if its encoding doesn't match a given one -:ref:`-requestEntityEmpty-` Rejects the request if its entity is not empty -:ref:`-requestEntityPresent-` Rejects the request if its entity is empty -:ref:`-requestUri-` Extracts the complete request URI -:ref:`-respondWithHeader-` Adds a given response header to all ``HttpResponse`` replies from its inner - Route -:ref:`-respondWithHeaders-` Same as :ref:`-respondWithHeader-`, but for several headers at once -:ref:`-respondWithMediaType-` Overrides the media-type of all ``HttpResponse`` replies from its inner Route, - rejects if the media-type is not accepted by the client -:ref:`-respondWithSingletonHeader-` Adds a given response header to all ``HttpResponse`` replies from its inner - Route, if a header with the same name is not yet present -:ref:`-respondWithSingletonHeaders-` Same as :ref:`-respondWithSingletonHeader-`, but for several headers at once -:ref:`-respondWithStatus-` Overrides the response status of all ``HttpResponse`` replies coming back from - its inner Route -:ref:`-responseEncodingAccepted-` Rejects the request if the client doesn't accept a given encoding for the - response -:ref:`-mapUnmatchedPath-` Transforms the ``unmatchedPath`` of the ``RequestContext`` using a given function -:ref:`-scheme-` Rejects a request if its Uri scheme does not match a given one -:ref:`-schemeName-` Extracts the request Uri scheme -:ref:`-setCookie-` Adds a ``Set-Cookie`` header to all ``HttpResponse`` replies of its inner Route -:ref:`-textract-` Extracts a ``TupleN`` of values from the ``RequestContext`` using a function -:ref:`-hprovide-` Injects a ``TupleN`` of values into a directive, which provides them as - extractions -:ref:`-unmatchedPath-` Extracts the unmatched path from the RequestContext -:ref:`-validate-` Passes or rejects the request depending on evaluation of a given conditional - expression -:ref:`-withRangeSupport-` Transforms the response from its inner route into a ``206 Partial Content`` - response if the client requested only part of the resource with a ``Range`` header. -====================================== ================================================================================= diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/index.rst b/akka-docs-dev/rst/scala/http/directives/basic-directives/index.rst deleted file mode 100644 index cf2c3e309f..0000000000 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/index.rst +++ /dev/null @@ -1,80 +0,0 @@ -.. _BasicDirectives: - -BasicDirectives -=============== - -Basic directives are building blocks for building :ref:`Custom Directives`. As such they -usually aren't used in a route directly but rather in the definition of new directives. - -.. _ProvideDirectives: - -Directives to provide values to inner routes --------------------------------------------- - -These directives allow to provide the inner routes with extractions. They can be distinguished -on two axes: a) provide a constant value or extract a value from the ``RequestContext`` b) provide -a single value or an HList of values. - - * :ref:`-extract-` - * :ref:`-textract-` - * :ref:`-provide-` - * :ref:`-tprovide-` - -.. _Request Transforming Directives: - -Directives transforming the request ------------------------------------ - - * :ref:`-mapRequestContext-` - * :ref:`-mapRequest-` - -.. _Response Transforming Directives: - -Directives transforming the response ------------------------------------- - -These directives allow to hook into the response path and transform the complete response or -the parts of a response or the list of rejections: - - * :ref:`-mapResponse-` - * :ref:`-mapResponseEntity-` - * :ref:`-mapResponseHeaders-` - * :ref:`-mapRejections-` - - -.. _Result Transformation Directives: - -Directives transforming the RouteResult ---------------------------------------- - -These directives allow to transform the RouteResult of the inner route. - - * :ref:`-mapRouteResult-` - * :ref:`-mapRouteResponsePF-` - -Directives changing the execution of the inner route ----------------------------------------------------- - - * :ref:`-mapInnerRoute-` - -Directives alphabetically -------------------------- - -.. toctree:: - :maxdepth: 1 - - extract - mapInnerRoute - mapRejections - mapRequest - mapRequestContext - mapResponse - mapResponseEntity - mapResponseHeaders - mapRouteResult - mapRouteResultPF - noop - pass - provide - textract - tprovide diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapResponse.rst b/akka-docs-dev/rst/scala/http/directives/basic-directives/mapResponse.rst deleted file mode 100644 index 91b20760c7..0000000000 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapResponse.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _-mapResponse-: - -mapResponse -=============== - -Changes the response that was generated by the inner route. - -Signature ---------- - -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala - :snippet: mapResponse - -Description ------------ - -The ``mapResponse`` directive is used as a building block for :ref:`Custom Directives` to transform a response that -was generated by the inner route. This directive transforms only complete responses. Use :ref:`-mapHttpResponsePart-`, -instead, to transform parts of chunked responses as well. - -See :ref:`Response Transforming Directives` for similar directives. - -Example -------- - -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala - :snippet: 0mapResponse diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRouteResultPF.rst b/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRouteResultPF.rst deleted file mode 100644 index e9229a0b36..0000000000 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRouteResultPF.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _-mapRouteResponsePF-: - -mapRouteResponsePF -================== - -Changes the message the inner route sends to the responder. - -Signature ---------- - -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala - :snippet: mapRouteResponsePF - -Description ------------ - -The ``mapRouteResponsePF`` directive is used as a building block for :ref:`Custom Directives` to transform what -the inner route sends to the responder (see :ref:`The Responder Chain`). It's similar to the :ref:`-mapRouteResult-` -directive but allows to specify a partial function that doesn't have to handle all the incoming response messages. - -See :ref:`Result Transformation Directives` for similar directives. - -Example -------- - -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala - :snippet: mapRouteResultPF diff --git a/akka-docs-dev/rst/scala/http/directives/coding-directives/compressResponse.rst b/akka-docs-dev/rst/scala/http/directives/coding-directives/compressResponse.rst deleted file mode 100644 index 1a5d74dfaa..0000000000 --- a/akka-docs-dev/rst/scala/http/directives/coding-directives/compressResponse.rst +++ /dev/null @@ -1,46 +0,0 @@ -.. _-compressResponse-: - -compressResponse -================ - -Uses the first of a given number of encodings that the client accepts. If none are accepted the request -is rejected with an ``UnacceptedResponseEncodingRejection``. - -Signature ---------- - -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala - :snippet: compressResponse - -Description ------------ - -The ``compressResponse`` directive allows to specify zero to three encoders to try in the specified order. -If none are specified the tried list is ``Gzip``, ``Deflate``, and then ``NoEncoding``. - -The ``compressResponse()`` directive (without an explicit list of encoders given) will therefore behave as follows: - -========================================= =============================== -``Accept-Encoding`` header resulting response -========================================= =============================== -``Accept-Encoding: gzip`` compressed with ``Gzip`` -``Accept-Encoding: deflate`` compressed with ``Deflate`` -``Accept-Encoding: deflate, gzip`` compressed with ``Gzip`` -``Accept-Encoding: identity`` uncompressed -no ``Accept-Encoding`` header present compressed with ``Gzip`` -========================================= =============================== - -For an overview of the different ``compressResponse`` directives see :ref:`WhenToUseWhichCompressResponseDirective`. - -Example -------- - -This example shows the behavior of ``compressResponse`` without any encoders specified: - -.. includecode2:: ../../../code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala - :snippet: compressResponse-0 - -This example shows the behaviour of ``compressResponse(Gzip)``: - -.. includecode2:: ../../../code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala - :snippet: compressResponse-1 diff --git a/akka-docs-dev/rst/scala/http/directives/coding-directives/compressResponseIfRequested.rst b/akka-docs-dev/rst/scala/http/directives/coding-directives/compressResponseIfRequested.rst deleted file mode 100644 index 782842c0e5..0000000000 --- a/akka-docs-dev/rst/scala/http/directives/coding-directives/compressResponseIfRequested.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. _-compressResponseIfRequested-: - -compressResponseIfRequested -=========================== - -Only compresses the response when specifically requested by the ``Accept-Encoding`` request header -(i.e. the default is "no compression"). - -Signature ---------- - -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala - :snippet: compressResponseIfRequested - -Description ------------ - -The ``compressResponseIfRequested`` directive is an alias for ``compressResponse(NoEncoding, Gzip, Deflate)`` and will -behave as follows: - -========================================= =============================== -``Accept-Encoding`` header resulting response -========================================= =============================== -``Accept-Encoding: gzip`` compressed with ``Gzip`` -``Accept-Encoding: deflate`` compressed with ``Deflate`` -``Accept-Encoding: deflate, gzip`` compressed with ``Gzip`` -``Accept-Encoding: identity`` uncompressed -no ``Accept-Encoding`` header present uncompressed -========================================= =============================== - -For an overview of the different ``compressResponse`` directives see :ref:`WhenToUseWhichCompressResponseDirective`. - -Example -------- - -.. includecode2:: ../../../code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala - :snippet: compressResponseIfRequested diff --git a/akka-docs-dev/rst/scala/http/directives/coding-directives/decompressRequest.rst b/akka-docs-dev/rst/scala/http/directives/coding-directives/decompressRequest.rst deleted file mode 100644 index 051d5d8309..0000000000 --- a/akka-docs-dev/rst/scala/http/directives/coding-directives/decompressRequest.rst +++ /dev/null @@ -1,46 +0,0 @@ -.. _-decompressRequest-: - -decompressRequest -================= - -Decompresses the request if it is can be decoded with one of the given decoders. Otherwise, -the request is rejected with an ``UnsupportedRequestEncodingRejection(supportedEncoding)``. - -Signature ---------- - -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala - :snippet: decompressRequest - -Description ------------ - -The ``decompressRequest`` directive allows either to specify a list of decoders or none at all. If -no ``Decoder`` is specified ``Gzip``, ``Deflate``, or ``NoEncoding`` will be tried. - -The ``decompressRequest`` directive will behave as follows: - -========================================= =============================== -``Content-Encoding`` header resulting request -========================================= =============================== -``Content-Encoding: gzip`` decompressed -``Content-Encoding: deflate`` decompressed -``Content-Encoding: identity`` unchanged -no ``Content-Encoding`` header present unchanged -========================================= =============================== - -For an overview of the different ``decompressRequest`` directives and which one to use when, -see :ref:`WhenToUseWhichDecompressRequestDirective`. - -Example -------- - -This example shows the behavior of ``decompressRequest()`` without any decoders specified: - -.. includecode2:: ../../../code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala - :snippet: decompressRequest-0 - -This example shows the behaviour of ``decompressRequest(Gzip, NoEncoding)``: - -.. includecode2:: ../../../code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala - :snippet: decompressRequest-1 diff --git a/akka-docs-dev/rst/scala/http/directives/coding-directives/index.rst b/akka-docs-dev/rst/scala/http/directives/coding-directives/index.rst deleted file mode 100644 index abdd9923f3..0000000000 --- a/akka-docs-dev/rst/scala/http/directives/coding-directives/index.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. _CodingDirectives: - -CodingDirectives -================ - -.. toctree:: - :maxdepth: 1 - - compressResponse - compressResponseIfRequested - decodeRequest - decompressRequest - encodeResponse - requestEncodedWith - responseEncodingAccepted - -.. _WhenToUseWhichCompressResponseDirective: - -When to use which compression directive? ----------------------------------------- - -There are three different directives for performing response compressing with slightly different behavior: - -:ref:`-encodeResponse-` - Always compresses the response with the one given encoding, rejects the request with an - ``UnacceptedResponseEncodingRejection`` if the client doesn't accept the given encoding. The other - compression directives are built upon this one. See its description for an overview how they - relate exactly. - -:ref:`-compressResponse-` - Uses the first of a given number of encodings that the client accepts. If none are accepted the request - is rejected. - -:ref:`-compressResponseIfRequested-` - Only compresses the response when specifically requested by the - ``Accept-Encoding`` request header (i.e. the default is "no compression"). - -See the individual directives for more detailed usage examples. - -.. _WhenToUseWhichDecompressRequestDirective: - -When to use which decompression directive? ------------------------------------------- - -There are two different directives for performing request decompressing with slightly different behavior: - -:ref:`-decodeRequest-` - Attempts to decompress the request using **the one given decoder**, rejects the request with an - ``UnsupportedRequestEncodingRejection`` if the request is not encoded with the given encoder. - -:ref:`-decompressRequest-` - Decompresses the request if it is encoded with **one of the given encoders**. - If the request's encoding doesn't match one of the given encoders it is rejected. - - -Combining compression and decompression ---------------------------------------- - -As with all Spray directives, the above single directives can be combined -using ``&`` to produce compound directives that will decompress requests and -compress responses in whatever combination required. Some examples: - -.. includecode2:: /../spray-routing-tests/src/test/scala/spray/routing/EncodingDirectivesSpec.scala - :snippet: decompress-compress-combination-example diff --git a/akka-docs-dev/rst/scala/http/exception-handling.rst b/akka-docs-dev/rst/scala/http/exception-handling.rst deleted file mode 100644 index 80269bd24c..0000000000 --- a/akka-docs-dev/rst/scala/http/exception-handling.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. _Exception Handling: - -Exception Handling -================== - -Exceptions thrown during route execution bubble up through the route structure to the next enclosing -:ref:`-handleExceptions-` directive, ``Route.seal`` or the ``onFailure`` callback of a -future created by ``detach``. - -Similarly to the way that :ref:`Rejections` are handled the :ref:`-handleExceptions-` directive delegates the actual job of -converting a list of rejections to its argument, an ExceptionHandler__, which is defined like this:: - - trait ExceptionHandler extends PartialFunction[Throwable, Route] - -__ @github@/akka-http/src/main/scala/akka/http/server/ExceptionHandler.scala - -:ref:`runRoute` defined in :ref:`HttpService` does the same but gets its ``ExceptionHandler`` instance -implicitly. - -Since an ``ExceptionHandler`` is a partial function it can choose, which exceptions it would like to handle and -which not. Unhandled exceptions will simply continue to bubble up in the route structure. The top-most -``ExceptionHandler`` applied by :ref:`runRoute` will handle *all* exceptions that reach it. - -So, if you'd like to customize the way certain exceptions are handled simply bring a custom ``ExceptionHandler`` into -implicit scope of :ref:`runRoute` or pass it to an explicit :ref:`-handleExceptions-` directive that you -have put somewhere into your route structure. - -Here is an example: - -.. includecode2:: ../code/docs/http/server/ExceptionHandlerExamplesSpec.scala - :snippet: example-1 diff --git a/akka-docs-dev/rst/scala/http/https.rst b/akka-docs-dev/rst/scala/http/https.rst deleted file mode 100644 index 3683882a58..0000000000 --- a/akka-docs-dev/rst/scala/http/https.rst +++ /dev/null @@ -1,6 +0,0 @@ -HTTPS -===== - -Is not yet supported. - -(todo) \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/index-client-server.rst b/akka-docs-dev/rst/scala/http/index-client-server.rst deleted file mode 100644 index 98fb7329dd..0000000000 --- a/akka-docs-dev/rst/scala/http/index-client-server.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _http-client-server-scala: - -HTTP Client & Server -==================== - -.. toctree:: - :maxdepth: 2 - - model - client - server - https diff --git a/akka-docs-dev/rst/scala/http/index-routing.rst b/akka-docs-dev/rst/scala/http/index-routing.rst deleted file mode 100644 index 48e8201e8e..0000000000 --- a/akka-docs-dev/rst/scala/http/index-routing.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _http-routing-index-scala: - -HTTP Routing -============ - -.. toctree:: - :maxdepth: 2 - - quick-start - routing - directives - rejections - exception-handling - path-matchers - marshalling - custom-directives - directives/alphabetically - directives/by-trait - diff --git a/akka-docs-dev/rst/scala/http/index-testkit.rst b/akka-docs-dev/rst/scala/http/index-testkit.rst deleted file mode 100644 index 328e28f729..0000000000 --- a/akka-docs-dev/rst/scala/http/index-testkit.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _http-testkit-scala: - -HTTP TestKit -============ - -.. note:: - - This part of the documentation has not yet been written, please stay tuned for updates. diff --git a/akka-docs-dev/rst/scala/http/index.rst b/akka-docs-dev/rst/scala/http/index.rst index ed019c16b7..154f89b34c 100644 --- a/akka-docs-dev/rst/scala/http/index.rst +++ b/akka-docs-dev/rst/scala/http/index.rst @@ -3,26 +3,13 @@ Akka HTTP ========= -The purpose of the Akka HTTP layer is to expose Actors to the web via HTTP and -to enable them to consume HTTP services as a client. It is not an HTTP -framework, it is an Actor-based toolkit for interacting with web services and -clients. This toolkit is structured into several layers: - - * ``akka-http-core``: A complete implementation of the HTTP standard, both as - client and server. - - * ``akka-http``: A convenient and powerful routing DSL for expressing web - services. - - * ``akka-http-testkit``: A test harness and set of utilities for verifying - your web service implementations. - -Additionally there are several integration modules with bindings for different -serialization and deserialization schemes for HTTP entities. - .. toctree:: :maxdepth: 2 - index-client-server - index-routing - index-testkit + introduction + configuration + client-side/index + low-level-server-side-api + routing-dsl/index + common/index + migration-from-spray diff --git a/akka-docs-dev/rst/scala/http/introduction.rst b/akka-docs-dev/rst/scala/http/introduction.rst new file mode 100644 index 0000000000..33e92e62e7 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/introduction.rst @@ -0,0 +1,32 @@ +Introduction +============ + +The Akka HTTP modules implement a full server- and client-side HTTP stack on top of *akka-actor* and *akka-stream*. It's +not a web-framework but rather a more general toolkit for providing and consuming HTTP-based services. While interaction +with a browser is of course also in scope it is not the primary focus of Akka HTTP. + +Akka HTTP follows a rather open design and many times offers several different API levels for "doing the same thing". +You get to pick the API level of abstraction that is most suitable for your application. +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 do write more application code. + +Akka HTTP is structured into several modules: + +akka-http-core + A complete, mostly low-level, server- and client-side implementation of HTTP (incl. WebSockets) + +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 + +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_ + +akka-http-xml + Predefined glue-code for (de)serializing custom types from/to XML with scala-xml_ + +.. _spray-json: https://github.com/spray/spray-json +.. _scala-xml: https://github.com/scala/scala-xml \ 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 new file mode 100644 index 0000000000..054a22d397 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/low-level-server-side-api.rst @@ -0,0 +1,135 @@ +.. _http-low-level-server-side-api: + +Low-Level Server-Side API +========================= + +Apart from the :ref:`HTTP Client ` Akka HTTP also provides an embedded, +`Reactive-Streams`_-based, fully asynchronous HTTP/1.1 server implemented on top of :ref:`Akka Stream `. + +It sports the following features: + +- Full support for `HTTP persistent connections`_ +- Full support for `HTTP pipelining`_ +- Full support for asynchronous HTTP streaming including "chunked" transfer encoding accessible through an idiomatic API +- Optional SSL/TLS encryption + +.. _HTTP persistent connections: http://en.wikipedia.org/wiki/HTTP_persistent_connection +.. _HTTP pipelining: http://en.wikipedia.org/wiki/HTTP_pipelining +.. _Reactive-Streams: http://www.reactive-streams.org/ + + +The server-side components of Akka HTTP are split into two layers: + +1. The basic low-level server implementation in the ``akka-http-core`` module +2. Higher-level functionality in the ``akka-http`` module + +The low-level server (1) is scoped with a clear focus on the essential functionality of an HTTP/1.1 server: + +- Connection management +- Parsing messages and headers +- Timeout management (for requests and connections) +- Response ordering (for transparent pipelining support) + +All non-core features of typical HTTP servers (like request routing, file serving, compression, etc.) are left to +the higher layers, they are not implemented by the ``akka-http-core``-level server itself. +Apart from general focus this design keeps the server core small and light-weight as well as easy to understand and +maintain. + +Depending on your needs you can either use the low-level API directly or rely on the high-level +:ref:`Routing DSL ` which can make the definition of more complex service logic much +easier. + + +Streams and HTTP +---------------- + +The Akka HTTP server is implemented on top of :ref:`Akka Stream ` and makes heavy use of it - in its +implementation as well as on all levels of its API. + +On the connection level Akka HTTP offers basically the same kind of interface as :ref:`Akka Stream IO `: +A socket binding is represented as a stream of incoming connections. The application pulls connections from this stream +source and, for each of them, provides a ``Flow[HttpRequest, HttpResponse, _]`` to "translate" requests into responses. + +Apart from regarding a socket bound on the server-side as a ``Source[IncomingConnection]`` and each connection as a +``Source[HttpRequest]`` with a ``Sink[HttpResponse]`` the stream abstraction is also present inside a single HTTP +message: The entities of HTTP requests and responses are generally modeled as a ``Source[ByteString]``. See also +the :ref:`http-model-scala` for more information on how HTTP messages are represented in Akka HTTP. + + +Starting and Stopping +--------------------- + +On the most basic level an Akka HTTP server is bound by invoking the ``bind`` method of the `akka.http.scaladsl.Http`_ +extension: + +.. includecode2:: ../code/docs/http/scaladsl/HttpServerExampleSpec.scala + :snippet: binding-example + +Arguments to the ``Http.bind`` method specify the interface and port to bind to and register interest in handling +incoming HTTP connections. Additionally, the method also allows for the definition of socket options as well as a larger +number of settings for configuring the server according to your needs. + +The result of the ``bind`` method is a ``Source[Http.IncomingConnection]`` which must be drained by the application in +order to accept incoming connections. +The actual binding is not performed before this source is materialized as part of a processing pipeline. In +case the bind fails (e.g. because the port is already busy) the materialized stream will immediately be terminated with +a respective exception. +The binding is released (i.e. the underlying socket unbound) when the subscriber of the incoming +connection source has cancelled its subscription. Alternatively one can use the ``unbind()`` method of the +``Http.ServerBinding`` instance that is created as part of the connection source's materialization process. +The ``Http.ServerBinding`` also provides a way to get a hold of the actual local address of the bound socket, which is +useful for example when binding to port zero (and thus letting the OS pick an available port). + +.. _akka.http.scaladsl.Http: @github@/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala + + +Request-Response Cycle +---------------------- + +When a new connection has been accepted it will be published as an ``Http.IncomingConnection`` which consists +of the remote address and methods to provide a ``Flow[HttpRequest, HttpResponse, _]`` to handle requests coming in over +this connection. + +Requests are handled by calling one of the ``handleWithXXX`` methods with a handler, which can either be + + - a ``Flow[HttpRequest, HttpResponse, _]`` for ``handleWith``, + - a function ``HttpRequest => HttpResponse`` for ``handleWithSyncHandler``, + - a function ``HttpRequest => Future[HttpResponse]`` for ``handleWithAsyncHandler``. + +Here is a complete example: + +.. includecode2:: ../code/docs/http/scaladsl/HttpServerExampleSpec.scala + :snippet: full-server-example + +In this example, a request is handled by transforming the request stream with a function ``HttpRequest => HttpResponse`` +using ``handleWithSyncHandler`` (or equivalently, Akka Stream's ``map`` operator). Depending on the use case many +other ways of providing a request handler are conceivable using Akka Stream's combinators. + +If the application provides a ``Flow`` it is also the responsibility of the application to generate exactly one response +for every request and that the ordering of responses matches the ordering of the associated requests (which is relevant +if HTTP pipelining is enabled where processing of multiple incoming requests may overlap). When relying on +``handleWithSyncHandler`` or ``handleWithAsyncHandler``, or the ``map`` or ``mapAsync`` stream operators, this +requirement will be automatically fulfilled. + + +Streaming Request/Response Entities +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Streaming of HTTP message entities is supported through subclasses of ``HttpEntity``. The application needs to be able +to deal with streamed entities when receiving a request as well as, in many cases, when constructing responses. +See :ref:`HttpEntity` for a description of the alternatives. + +If you rely on the :ref:`http-marshalling-scala` and/or :ref:`http-unmarshalling-scala` facilities provided by +Akka HTTP then the conversion of custom types to and from streamed entities can be quite convenient. + + +Closing a connection +~~~~~~~~~~~~~~~~~~~~ + +The HTTP connection will be closed when the handling ``Flow`` cancels its upstream subscription or the peer closes the +connection. An often times more convenient alternative is to explicitly add a ``Connection: close`` header to an +``HttpResponse``. This response will then be the last one on the connection and the server will actively close the +connection when it has been sent out. + + +// TODO: show an example of using the HTTP layer independently with a BidFlow join \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/marshalling.rst b/akka-docs-dev/rst/scala/http/marshalling.rst deleted file mode 100644 index b61045ba90..0000000000 --- a/akka-docs-dev/rst/scala/http/marshalling.rst +++ /dev/null @@ -1,4 +0,0 @@ -Marshalling -=========== - -(todo) \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/migration-from-spray.rst b/akka-docs-dev/rst/scala/http/migration-from-spray.rst new file mode 100644 index 0000000000..1c2098a97c --- /dev/null +++ b/akka-docs-dev/rst/scala/http/migration-from-spray.rst @@ -0,0 +1,4 @@ +Migration Guide from spray +========================== + +TODO \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/model.rst b/akka-docs-dev/rst/scala/http/model.rst deleted file mode 100644 index 4729991149..0000000000 --- a/akka-docs-dev/rst/scala/http/model.rst +++ /dev/null @@ -1,156 +0,0 @@ -.. _http-model-scala: - -Model -===== - -The akka HTTP model contains a mostly immutable, case-class based model of the major HTTP data structures, -like HTTP requests, responses and common headers. It also includes a parser for the latter, which is able to construct -the more structured header models from raw unstructured header name/value pairs. - -Overview --------- - -Since akka-http-core provides the central HTTP data structures you will find the following import in quite a -few places around the code base (and probably your own code as well): - -.. includecode:: ../code/docs/http/ModelSpec.scala - :include: import-model - -This brings in scope all of the relevant things that are defined here and that you’ll want to work with, mainly: - -- ``HttpRequest`` and ``HttpResponse``, the central message model -- ``headers``, the package containing all the predefined HTTP header models and supporting types -- Supporting types like ``Uri``, ``HttpMethods``, ``MediaTypes``, ``StatusCodes``, etc. - -A common pattern is that the model of a certain entity is represented by an immutable type (class or trait), -while the actual instances of the entity defined by the HTTP spec live in an accompanying object carrying the name of -the type plus a trailing plural 's'. - -For example: - -- Defined HttpMethod instances live in the HttpMethods object. -- Defined HttpCharset instances live in the HttpCharsets object. -- Defined HttpEncoding instances live in the HttpEncodings object. -- Defined HttpProtocol instances live in the HttpProtocols object. -- Defined MediaType instances live in the MediaTypes object. -- Defined StatusCode instances live in the StatusCodes object. - -HttpRequest / HttpResponse --------------------------- - -``HttpRequest`` and ``HttpResponse`` are the basic case classes representing HTTP messages. - -An ``HttpRequest`` consists of - - - method (GET, POST, etc.) - - URI - - protocol - - headers - - entity (body data) - -Here are some examples how to construct an ``HttpRequest``: - -.. includecode:: ../code/docs/http/ModelSpec.scala - :include: construct-request - -All parameters of ``HttpRequest`` have default values set, so e.g. ``headers`` don't need to be specified -if there are none. Many of the parameters types (like ``HttpEntity`` and ``Uri``) define implicit conversions -for common use cases to simplify the creation of request and response instances. - -An ``HttpResponse`` consists of - - - status code - - protocol - - headers - - entity - -Here are some examples how to construct an ``HttpResponse``: - -.. includecode:: ../code/docs/http/ModelSpec.scala - :include: construct-response - -Aside from the simple ``HttpEntity`` constructors to create an entity from a fixed ``ByteString`` shown here, -subclasses of ``HttpEntity`` allow data to be specified as a stream of data which is explained in the next section. - -.. _HttpEntity: - -HttpEntity ----------- - -An ``HttpEntity`` carries the content of a request together with its content-type which is needed to interpret the raw -byte data. - -Akka HTTP provides several kinds of entities to support static and streaming data for the different kinds of ways -to transport streaming data with HTTP. There are four subtypes of HttpEntity: - - -HttpEntity.Strict - An entity which wraps a static ``ByteString``. It represents a standard, non-chunked HTTP message with ``Content-Length`` - set. - - -HttpEntity.Default - A streaming entity which needs a predefined length and a ``Producer[ByteString]`` to produce the body data of - the message. It represents a standard, non-chunked HTTP message with ``Content-Length`` set. It is an error if the - provided ``Producer[ByteString]`` doesn't produce exactly as many bytes as specified. On the wire, a Strict entity - and a Default entity cannot be distinguished. However, they offer a valuable alternative in the API to distinguish - between strict and streamed data. - - -HttpEntity.Chunked - A streaming entity of unspecified length that uses `Chunked Transfer Coding`_ for transmitting data. Data is - represented by a ``Producer[ChunkStreamPart]``. A ``ChunkStreamPart`` is either a non-empty ``Chunk`` or a ``LastChunk`` - containing optional trailer headers. The stream must consist of 0..n ``Chunked`` parts and can be terminated by an - optional ``LastChunk`` part (which carries optional trailer headers). - - -HttpEntity.CloseDelimited - A streaming entity of unspecified length that is delimited by closing the connection ("Connection: close"). Note, - that this entity type can only be used in an ``HttpResponse``. - -HttpEntity.IndefiniteLength - A streaming entity of unspecified length that can be used as a ``BodyPart`` entity. - -Entity types ``Strict``, ``Default``, and ``Chunked`` are a subtype of ``HttpEntity.Regular`` which allows to use them for -requests and responses. In contrast, ``HttpEntity.CloseDelimited`` can only be used for responses. - -Streaming entity types (i.e. all but ``Strict``) cannot be shared or serialized. To create a strict, sharable copy of an -entity or message use ``HttpEntity.toStrict`` or ``HttpMessage.toStrict`` which returns a Future of the object with the -body data collected into a ``ByteString``. - -.. _Chunked Transfer Coding: http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-26#section-4.1 - -The ``HttpEntity`` companion object contains several helper constructors to create entities from common types easily. - -You can pattern match over the subtypes of ``HttpEntity`` if you want to provide special handling for each of the -subtypes. However, in many cases a recipient of an `HttpEntity` doesn't care about of which subtype an entity is -(and how data is transported exactly on the HTTP layer). Therefore, a general ``HttpEntity.dataBytes`` is provided -which allows access to the data of an entity regardless of its concrete subtype. - -.. note:: - - When to use which subtype? - - Use Strict if the amount of data is small and it is already in the heap (or even available as a ``ByteString``) - - Use Default if the data is generated by a streaming data source and the size of the data is fixed - - Use Chunked to support a data stream of unknown length - - Use CloseDelimited for a response as an alternative to Chunked e.g. if chunked transfer encoding isn't supported - by a client. - - Use IndefiniteLength instead of CloseDelimited in a BodyPart. - -Header model ------------- - -Akka HTTP contains a rich model of the common HTTP headers. Parsing and rendering is done automatically so that -applications don't need to care for the actual syntax of headers. Headers not modelled explicitly are represented -as a ``RawHeader``. - -See these examples of how to deal with headers: - -.. includecode:: ../code/docs/http/ModelSpec.scala - :include: headers - -Parsing / Rendering -------------------- - -Parsing and rendering of HTTP data structures is heavily optimized and for most types there's currently no public API -provided to parse (or render to) Strings or byte arrays. diff --git a/akka-docs-dev/rst/scala/http/quick-start.rst b/akka-docs-dev/rst/scala/http/quick-start.rst deleted file mode 100644 index 77449f4e0a..0000000000 --- a/akka-docs-dev/rst/scala/http/quick-start.rst +++ /dev/null @@ -1,4 +0,0 @@ -Quick-Start -=========== - -(todo) \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/rejections.rst b/akka-docs-dev/rst/scala/http/rejections.rst deleted file mode 100644 index 6d8cbebec8..0000000000 --- a/akka-docs-dev/rst/scala/http/rejections.rst +++ /dev/null @@ -1,100 +0,0 @@ -.. _Rejections: - -Rejections -========== - -In the chapter about constructing :ref:`Routes` the ``~`` operator was introduced, which connects two routes in a way -that allows a second route to get a go at a request if the first route "rejected" it. The concept of "rejections" is -used by Akka HTTP for maintaining a more functional overall architecture and in order to be able to properly -handle all kinds of error scenarios. - -When a filtering directive, like the :ref:`-get-` directive, cannot let the request pass through to its inner Route because -the filter condition is not satisfied (e.g. because the incoming request is not a GET request) the directive doesn't -immediately complete the request with an error response. Doing so would make it impossible for other routes chained in -after the failing filter to get a chance to handle the request. -Rather, failing filters "reject" the request in the same way as by explicitly calling ``requestContext.reject(...)``. - -After having been rejected by a route the request will continue to flow through the routing structure and possibly find -another route that can complete it. If there are more rejections all of them will be picked up and collected. - -If the request cannot be completed by (a branch of) the route structure an enclosing :ref:`-handleRejections-` directive -can be used to convert a set of rejections into an ``HttpResponse`` (which, in most cases, will be an error response). -``Route.seal`` internally wraps its argument route with the :ref:`-handleRejections-` directive in order to "catch" -and handle any rejection. - - -Predefined Rejections ---------------------- - -A rejection encapsulates a specific reason why a Route was not able to handle a request. It is modeled as an object of -type ``Rejection``. Akka HTTP comes with a set of `predefined rejections`__, which are used by various -:ref:`predefined directives `. - -Rejections are gathered up over the course of a Route evaluation and finally converted to ``HttpResponse`` replies by -the :ref:`-handleRejections-` directive if there was no way for the request to be completed. - -__ @github@/akka-http/src/main/scala/akka/http/server/Rejection.scala - - -.. _RejectionHandler: - -RejectionHandler ----------------- - -The :ref:`-handleRejections-` directive delegates the actual job of converting a list of rejections to its argument, a -RejectionHandler__, which is defined like this:: - - trait RejectionHandler extends PartialFunction[List[Rejection], Route] - -__ @github@/akka-http/src/main/scala/akka/http/server/RejectionHandler.scala - -Since a ``RejectionHandler`` is a partial function it can choose, which rejections it would like to handle and -which not. Unhandled rejections will simply continue to flow through the route structure. The top-most -``RejectionHandler`` applied by :ref:`runRoute` will handle *all* rejections that reach it. - -So, if you'd like to customize the way certain rejections are handled simply bring a custom ``RejectionHandler`` into -implicit scope of :ref:`runRoute` or pass it to an explicit :ref:`-handleRejections-` directive that you -have put somewhere into your route structure. - -Here is an example: - -.. includecode2:: ../code/docs/http/server/RejectionHandlerExamplesSpec.scala - :snippet: example-1 - - -Rejection Cancellation ----------------------- - -As you can see from its definition above the ``RejectionHandler`` handles not single rejections but a whole list of -them. This is because some route structure produce several "reasons" why a request could not be handled. - -Take this route structure for example: - -.. includecode2:: ../code/docs/http/server/RejectionHandlerExamplesSpec.scala - :snippet: example-2 - -For uncompressed POST requests this route structure could yield two rejections: - -- a ``MethodRejection`` produced by the :ref:`-get-` directive (which rejected because the request is not a GET request) -- an ``UnsupportedRequestEncodingRejection`` produced by the :ref:`-decodeRequest-` directive (which only accepts - gzip-compressed requests) - -In reality the route even generates one more rejection, a ``TransformationRejection`` produced by the :ref:`-post-` -directive. It "cancels" all other potentially existing *MethodRejections*, since they are invalid after the -:ref:`-post-` directive allowed the request to pass (after all, the route structure *can* deal with POST requests). -These types of rejection cancellations are resolved *before* a ``RejectionHandler`` sees the rejection list. -So, for the example above the ``RejectionHandler`` will be presented with only a single-element rejection list, -containing nothing but the ``UnsupportedRequestEncodingRejection``. - -.. _empty rejections: - -Empty Rejections ----------------- - -Since rejections are passed around in lists you might ask yourself what the semantics of an empty rejection list are. -In fact, empty rejection lists have well defined semantics. They signal that a request was not handled because the -respective resource could not be found. Akka HTTP reserves the special status of "empty rejection" to this most -common failure a service is likely to produce. - -So, for example, if the :ref:`-path-` directive rejects a request, it does so with an empty rejection list. The -:ref:`-host-` directive behaves in the same way. diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/case-class-extraction.rst b/akka-docs-dev/rst/scala/http/routing-dsl/case-class-extraction.rst new file mode 100644 index 0000000000..0df76efb50 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/case-class-extraction.rst @@ -0,0 +1,68 @@ +.. _Case Class Extraction: + +Case Class Extraction +===================== + +The value extraction performed by :ref:`Directives` is a nice way of providing your route logic with interesting request +properties, all with proper type-safety and error handling. However, in some case you might want even more. +Consider this example: + +.. includecode2:: ../../code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala + :snippet: example-1 + +Here the :ref:`-parameters-` directives is employed to extract three ``Int`` values, which are then used to construct an +instance of the ``Color`` case class. So far so good. However, if the model classes we'd like to work with have more +than just a few parameters the overhead introduced by capturing the arguments as extractions only to feed them into the +model class constructor directly afterwards can somewhat clutter up your route definitions. + +If your model classes are case classes, as in our example, Akka HTTP supports an even shorter and more concise +syntax. You can also write the example above like this: + +.. includecode2:: ../../code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala + :snippet: example-2 + +You can postfix any directive with extractions with an ``as(...)`` call. By simply passing the companion object of your +model case class to the ``as`` modifier method the underlying directive is transformed into an equivalent one, which +extracts only one value of the type of your model class. Note that there is no reflection involved and your case class +does not have to implement any special interfaces. The only requirement is that the directive you attach the ``as`` +call to produces the right number of extractions, with the right types and in the right order. + +If you'd like to construct a case class instance from extractions produced by *several* directives you can first join +the directives with the ``&`` operator before using the ``as`` call: + +.. includecode2:: ../../code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala + :snippet: example-3 + +Here the ``Color`` class has gotten another member, ``name``, which is supplied not as a parameter but as a path +element. By joining the ``path`` and ``parameters`` directives with ``&`` you create a directive extracting 4 values, +which directly fit the member list of the ``Color`` case class. Therefore you can use the ``as`` modifier to convert +the directive into one extracting only a single ``Color`` instance. + +Generally, when you have routes that work with, say, more than 3 extractions it's a good idea to introduce a case class +for these and resort to case class extraction. Especially since it supports another nice feature: validation. + + +.. caution:: There is one quirk to look out for when using case class extraction: If you create an explicit companion + object for your case class, no matter whether you actually add any members to it or not, the syntax presented above + will not (quite) work anymore. Instead of ``as(Color)`` you will then have to say ``as(Color.apply)``. This behavior + appears as if it's not really intended, so this might be improved in future Scala versions. + + +Case Class Validation +--------------------- + +In many cases your web service needs to verify input parameters according to some logic before actually working with +them. E.g. in the example above the restriction might be that all color component values must be between 0 and 255. +You could get this done with a few :ref:`-validate-` directives but this would quickly become cumbersome and hard to +read. + +If you use case class extraction you can put the verification logic into the constructor of your case class, where it +should be: + +.. includecode2:: ../../code/docs/http/scaladsl/server/CaseClassExtractionExamplesSpec.scala + :snippet: example-4 + +If you write your validations like this Akka HTTP's case class extraction logic will properly pick up all error +messages and generate a ``ValidationRejection`` if something goes wrong. By default, ``ValidationRejections`` are +converted into ``400 Bad Request`` error response by the default :ref:`RejectionHandler `, if no +subsequent route successfully handles the request. \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/alphabetically.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/alphabetically.rst new file mode 100644 index 0000000000..b96d3f5bcd --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/alphabetically.rst @@ -0,0 +1,138 @@ +.. _Predefined Directives: + +Predefined Directives (alphabetically) +====================================== + +=========================================== ============================================================================ +Directive Description +=========================================== ============================================================================ +:ref:`-authenticateBasic-` ... +:ref:`-authenticateBasicAsync-` ... +:ref:`-authenticateBasicPF-` ... +:ref:`-authenticateBasicPFAsync-` ... +:ref:`-authenticateOrRejectWithChallenge-` ... +:ref:`-authorize-` ... +:ref:`-cancelRejection-` ... +:ref:`-cancelRejections-` ... +:ref:`-complete-` ... +:ref:`-completeOrRecoverWith-` ... +:ref:`-completeWith-` ... +:ref:`-conditional-` ... +:ref:`-cookie-` ... +:ref:`-decodeRequest-` ... +:ref:`-decodeRequestWith-` ... +:ref:`-delete-` ... +:ref:`-deleteCookie-` ... +:ref:`-encodeResponse-` ... +:ref:`-encodeResponseWith-` ... +:ref:`-entity-` ... +:ref:`-extract-` ... +:ref:`-extractClientIP-` ... +:ref:`-extractCredentials-` ... +:ref:`-extractExecutionContext-` ... +:ref:`-extractFlowMaterializer-` ... +:ref:`-extractHost-` ... +:ref:`-extractLog-` ... +:ref:`-extractMethod-` ... +:ref:`-extractRequest-` ... +:ref:`-extractRequestContext-` ... +:ref:`-extractScheme-` ... +:ref:`-extractSettings-` ... +:ref:`-extractUnmatchedPath-` ... +:ref:`-extractUri-` ... +:ref:`-failWith-` ... +:ref:`-formField-` ... +:ref:`-formFields-` ... +:ref:`-get-` ... +:ref:`-getFromBrowseableDirectories-` ... +:ref:`-getFromBrowseableDirectory-` ... +:ref:`-getFromDirectory-` ... +:ref:`-getFromFile-` ... +:ref:`-getFromResource-` ... +:ref:`-getFromResourceDirectory-` ... +:ref:`-handleExceptions-` ... +:ref:`-handleRejections-` ... +:ref:`-handleWebsocketMessages-` ... +:ref:`-handleWith-` ... +:ref:`-head-` ... +:ref:`-headerValue-` ... +:ref:`-headerValueByName-` ... +:ref:`-headerValueByType-` ... +:ref:`-headerValuePF-` ... +:ref:`-host-` ... +:ref:`-listDirectoryContents-` ... +:ref:`-logRequest-` ... +:ref:`-logRequestResult-` ... +:ref:`-logResult-` ... +:ref:`-mapInnerRoute-` ... +:ref:`-mapRejections-` ... +:ref:`-mapRequest-` ... +:ref:`-mapRequestContext-` ... +:ref:`-mapResponse-` ... +:ref:`-mapResponseEntity-` ... +:ref:`-mapResponseHeaders-` ... +:ref:`-mapRouteResult-` ... +:ref:`-mapRouteResultFuture-` ... +:ref:`-mapRouteResultPF-` ... +:ref:`-mapRouteResultWith-` ... +:ref:`-mapRouteResultWithPF-` ... +:ref:`-mapSettings-` ... +:ref:`-mapUnmatchedPath-` ... +:ref:`-method-` ... +:ref:`-onComplete-` ... +:ref:`-onSuccess-` ... +:ref:`-optionalCookie-` ... +:ref:`-optionalHeaderValue-` ... +:ref:`-optionalHeaderValueByName-` ... +:ref:`-optionalHeaderValueByType-` ... +:ref:`-optionalHeaderValuePF-` ... +:ref:`-options-` ... +:ref:`-overrideMethodWithParameter-` ... +:ref:`-overrideStatusCode-` ... +:ref:`-parameter-` ... +:ref:`-parameterMap-` ... +:ref:`-parameterMultiMap-` ... +:ref:`-parameters-` ... +:ref:`-parameterSeq-` ... +:ref:`-pass-` ... +:ref:`-patch-` ... +:ref:`-path-` ... +:ref:`-pathEnd-` ... +:ref:`-pathEndOrSingleSlash-` ... +:ref:`-pathPrefix-` ... +:ref:`-pathPrefixTest-` ... +:ref:`-pathSingleSlash-` ... +:ref:`-pathSuffix-` ... +:ref:`-pathSuffixTest-` ... +:ref:`-post-` ... +:ref:`-provide-` ... +:ref:`-put-` ... +:ref:`-rawPathPrefix-` ... +:ref:`-rawPathPrefixTest-` ... +:ref:`-recoverRejections-` ... +:ref:`-recoverRejectionsWith-` ... +:ref:`-redirect-` ... +:ref:`-redirectToNoTrailingSlashIfPresent-` ... +:ref:`-redirectToTrailingSlashIfMissing-` ... +:ref:`-reject-` ... +:ref:`-rejectEmptyResponse-` ... +:ref:`-requestEncodedWith-` ... +:ref:`-requestEntityEmpty-` ... +:ref:`-requestEntityPresent-` ... +:ref:`-respondWithDefaultHeader-` ... +:ref:`-respondWithDefaultHeaders-` ... +:ref:`-respondWithHeader-` ... +:ref:`-respondWithHeaders-` ... +:ref:`-respondWithHeaders-` ... +:ref:`-responseEncodingAccepted-` ... +:ref:`-scheme-` ... +:ref:`-setCookie-` ... +:ref:`-textract-` ... +:ref:`-tprovide-` ... +:ref:`-validate-` ... +:ref:`-withExecutionContext-` ... +:ref:`-withFlowMaterializer-` ... +:ref:`-withLog-` ... +:ref:`-withRangeSupport-` ... +:ref:`-withSettings-` ... +=========================================== ============================================================================ diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/cancelRejection.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/cancelRejection.rst new file mode 100644 index 0000000000..0337d1d451 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/cancelRejection.rst @@ -0,0 +1,23 @@ +.. _-cancelRejection-: + +cancelRejection +=============== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: cancelRejection + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0cancelRejection diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/cancelRejections.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/cancelRejections.rst new file mode 100644 index 0000000000..1d348fad54 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/cancelRejections.rst @@ -0,0 +1,23 @@ +.. _-cancelRejections-: + +cancelRejections +================ + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: cancelRejections + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0cancelRejections diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/extract.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extract.rst similarity index 73% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/extract.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extract.rst index a8cbb2a056..2d8ec6851d 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/extract.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extract.rst @@ -8,7 +8,7 @@ Calculates a value from the request context and provides the value to the inner Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: extract Description @@ -23,5 +23,5 @@ See :ref:`ProvideDirectives` for an overview of similar directives. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: 0extract diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractExecutionContext.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractExecutionContext.rst new file mode 100644 index 0000000000..c6253ff6fc --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractExecutionContext.rst @@ -0,0 +1,23 @@ +.. _-extractExecutionContext-: + +extractExecutionContext +======================= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: extractExecutionContext + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0extractExecutionContext diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractFlowMaterializer.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractFlowMaterializer.rst new file mode 100644 index 0000000000..e78ee2b8cf --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractFlowMaterializer.rst @@ -0,0 +1,23 @@ +.. _-extractFlowMaterializer-: + +extractFlowMaterializer +======================= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: extractFlowMaterializer + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0extractFlowMaterializer diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractLog.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractLog.rst new file mode 100644 index 0000000000..78998b047e --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractLog.rst @@ -0,0 +1,23 @@ +.. _-extractLog-: + +extractLog +========== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: extractLog + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0extractLog diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractRequest.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractRequest.rst new file mode 100644 index 0000000000..860f88170a --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractRequest.rst @@ -0,0 +1,23 @@ +.. _-extractRequest-: + +extractRequest +============== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: extractRequest + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0extractRequest diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractRequestContext.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractRequestContext.rst new file mode 100644 index 0000000000..9933ba1486 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractRequestContext.rst @@ -0,0 +1,23 @@ +.. _-extractRequestContext-: + +extractRequestContext +===================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: extractRequestContext + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0extractRequestContext diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractSettings.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractSettings.rst new file mode 100644 index 0000000000..4278bfc57b --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractSettings.rst @@ -0,0 +1,23 @@ +.. _-extractSettings-: + +extractSettings +=============== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: extractSettings + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0extractSettings diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractUnmatchedPath.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractUnmatchedPath.rst new file mode 100644 index 0000000000..3475fbd2af --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractUnmatchedPath.rst @@ -0,0 +1,23 @@ +.. _-extractUnmatchedPath-: + +extractUnmatchedPath +==================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: extractUnmatchedPath + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0extractUnmatchedPath diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractUri.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractUri.rst new file mode 100644 index 0000000000..9858fd59da --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/extractUri.rst @@ -0,0 +1,23 @@ +.. _-extractUri-: + +extractUri +========== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: extractUri + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0extractUri diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/index.rst new file mode 100644 index 0000000000..77c79ac0ec --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/index.rst @@ -0,0 +1,127 @@ +.. _BasicDirectives: + +BasicDirectives +=============== + +Basic directives are building blocks for building :ref:`Custom Directives`. As such they +usually aren't used in a route directly but rather in the definition of new directives. + + +.. _ProvideDirectives: + +Providing Values to Inner Routes +-------------------------------- + +These directives provide values to the inner routes with extractions. They can be distinguished +on two axes: a) provide a constant value or extract a value from the ``RequestContext`` b) provide +a single value or a tuple of values. + + * :ref:`-extract-` + * :ref:`-extractExecutionContext-` + * :ref:`-extractFlowMaterializer-` + * :ref:`-extractLog-` + * :ref:`-extractRequest-` + * :ref:`-extractRequestContext-` + * :ref:`-extractSettings-` + * :ref:`-extractUnmatchedPath-` + * :ref:`-extractUri-` + * :ref:`-textract-` + * :ref:`-provide-` + * :ref:`-tprovide-` + + +.. _Request Transforming Directives: + +Transforming the Request(Context) +--------------------------------- + + * :ref:`-mapRequest-` + * :ref:`-mapRequestContext-` + * :ref:`-mapSettings-` + * :ref:`-mapUnmatchedPath-` + * :ref:`-withExecutionContext-` + * :ref:`-withFlowMaterializer-` + * :ref:`-withLog-` + * :ref:`-withSettings-` + + +.. _Response Transforming Directives: + +Transforming the Response +------------------------- + +These directives allow to hook into the response path and transform the complete response or +the parts of a response or the list of rejections: + + * :ref:`-mapResponse-` + * :ref:`-mapResponseEntity-` + * :ref:`-mapResponseHeaders-` + + +.. _Result Transformation Directives: + +Transforming the RouteResult +---------------------------- + +These directives allow to transform the RouteResult of the inner route. + + * :ref:`-cancelRejection-` + * :ref:`-cancelRejections-` + * :ref:`-mapRejections-` + * :ref:`-mapRouteResult-` + * :ref:`-mapRouteResultFuture-` + * :ref:`-mapRouteResultPF-` + * :ref:`-mapRouteResultWith-` + * :ref:`-mapRouteResultWithPF-` + * :ref:`-recoverRejections-` + * :ref:`-recoverRejectionsWith-` + + +Other +----- + + * :ref:`-mapInnerRoute-` + * :ref:`-pass-` + + +Alphabetically +-------------- + +.. toctree:: + :maxdepth: 1 + + cancelRejection + cancelRejections + extract + extractExecutionContext + extractFlowMaterializer + extractLog + extractRequest + extractRequestContext + extractSettings + extractUnmatchedPath + extractUri + mapInnerRoute + mapRejections + mapRequest + mapRequestContext + mapResponse + mapResponseEntity + mapResponseHeaders + mapRouteResult + mapRouteResultFuture + mapRouteResultPF + mapRouteResultWith + mapRouteResultWithPF + mapSettings + mapUnmatchedPath + pass + provide + recoverRejections + recoverRejectionsWith + textract + tprovide + withExecutionContext + withFlowMaterializer + withLog + withSettings diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapInnerRoute.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapInnerRoute.rst similarity index 68% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/mapInnerRoute.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapInnerRoute.rst index 8c98c93349..6d3d6e458a 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapInnerRoute.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapInnerRoute.rst @@ -8,7 +8,7 @@ Changes the execution model of the inner route by wrapping it with arbitrary log Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: mapInnerRoute Description @@ -20,5 +20,5 @@ with any other route. Usually, the returned route wraps the original one with cu Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: mapInnerRoute diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRejections.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRejections.rst similarity index 68% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/mapRejections.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRejections.rst index 56a9c6ebbe..32dffab7cd 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRejections.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRejections.rst @@ -8,7 +8,7 @@ Transforms the list of rejections the inner route produced. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: mapRejections Description @@ -22,5 +22,5 @@ See :ref:`Response Transforming Directives` for similar directives. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: mapRejections diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRequest.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRequest.rst similarity index 77% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/mapRequest.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRequest.rst index f8fd0ba5fa..5baa48dacc 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRequest.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRequest.rst @@ -8,7 +8,7 @@ Transforms the request before it is handled by the inner route. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: mapRequest Description @@ -24,5 +24,5 @@ See :ref:`Request Transforming Directives` for an overview of similar directives Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: 0mapRequest diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRequestContext.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRequestContext.rst similarity index 73% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/mapRequestContext.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRequestContext.rst index ef431a7854..3bb626cafa 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRequestContext.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRequestContext.rst @@ -8,7 +8,7 @@ Transforms the ``RequestContext`` before it is passed to the inner route. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: mapRequestContext Description @@ -23,5 +23,5 @@ See :ref:`Request Transforming Directives` for an overview of similar directives Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: mapRequestContext diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapResponse.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapResponse.rst new file mode 100644 index 0000000000..6b8b97970d --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapResponse.rst @@ -0,0 +1,27 @@ +.. _-mapResponse-: + +mapResponse +=========== + +Changes the response that was generated by the inner route. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: mapResponse + +Description +----------- + +The ``mapResponse`` directive is used as a building block for :ref:`Custom Directives` to transform a response that +was generated by the inner route. This directive transforms complete responses. + +See also :ref:`-mapResponseHeaders-` or :ref:`-mapResponseEntity-` for more specialized variants and +:ref:`Response Transforming Directives` for similar directives. + +Example +------- + +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0mapResponse diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapResponseEntity.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapResponseEntity.rst similarity index 66% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/mapResponseEntity.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapResponseEntity.rst index 279f463285..c5749f7d0e 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapResponseEntity.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapResponseEntity.rst @@ -1,14 +1,14 @@ .. _-mapResponseEntity-: mapResponseEntity -===================== +================= Changes the response entity that was generated by the inner route. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: mapResponseEntity Description @@ -22,5 +22,5 @@ See :ref:`Response Transforming Directives` for similar directives. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: mapResponseEntity diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapResponseHeaders.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapResponseHeaders.rst similarity index 67% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/mapResponseHeaders.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapResponseHeaders.rst index 975592cb81..f65feffc18 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapResponseHeaders.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapResponseHeaders.rst @@ -1,14 +1,14 @@ .. _-mapResponseHeaders-: mapResponseHeaders -====================== +================== Changes the list of response headers that was generated by the inner route. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: mapResponseHeaders Description @@ -22,5 +22,5 @@ See :ref:`Response Transforming Directives` for similar directives. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: mapResponseHeaders diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRouteResult.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResult.rst similarity index 51% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/mapRouteResult.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResult.rst index 86024af9f7..854f42c1d7 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/mapRouteResult.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResult.rst @@ -1,26 +1,26 @@ .. _-mapRouteResult-: mapRouteResult -================ +============== Changes the message the inner route sends to the responder. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: mapRouteResult Description ----------- -The ``mapRouteResult`` directive is used as a building block for :ref:`Custom Directives` to transform what -the inner route sends to the responder (see :ref:`The Responder Chain`). +The ``mapRouteResult`` directive is used as a building block for :ref:`Custom Directives` to transform the +:ref:`RouteResult` coming back from the inner route. See :ref:`Result Transformation Directives` for similar directives. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: 0mapRouteResult diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultFuture.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultFuture.rst new file mode 100644 index 0000000000..a5b5e514fe --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultFuture.rst @@ -0,0 +1,23 @@ +.. _-mapRouteResultFuture-: + +mapRouteResultFuture +==================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: mapRouteResultFuture + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0mapRouteResultFuture diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultPF.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultPF.rst new file mode 100644 index 0000000000..6f28944017 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultPF.rst @@ -0,0 +1,27 @@ +.. _-mapRouteResultPF-: + +mapRouteResultPF +================ + +Changes the message the inner route sends to the responder. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: mapRouteResultPF + +Description +----------- + +The ``mapRouteResult`` directive is used as a building block for :ref:`Custom Directives` to transform the +:ref:`RouteResult` coming back from the inner route. It's similar to the :ref:`-mapRouteResult-` directive but allows to +specify a partial function that doesn't have to handle all potential ``RouteResult`` instances. + +See :ref:`Result Transformation Directives` for similar directives. + +Example +------- + +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: mapRouteResultPF diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultWith.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultWith.rst new file mode 100644 index 0000000000..237451033f --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultWith.rst @@ -0,0 +1,23 @@ +.. _-mapRouteResultWith-: + +mapRouteResultWith +================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: mapRouteResultWith + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0mapRouteResultWith diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultWithPF.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultWithPF.rst new file mode 100644 index 0000000000..fad0084376 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapRouteResultWithPF.rst @@ -0,0 +1,23 @@ +.. _-mapRouteResultWithPF-: + +mapRouteResultWithPF +==================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: mapRouteResultWithPF + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0mapRouteResultWithPF diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapSettings.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapSettings.rst new file mode 100644 index 0000000000..4d979a29e1 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapSettings.rst @@ -0,0 +1,23 @@ +.. _-mapSettings-: + +mapSettings +=========== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: mapSettings + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0mapSettings diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapUnmatchedPath.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapUnmatchedPath.rst new file mode 100644 index 0000000000..c2706a7537 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/mapUnmatchedPath.rst @@ -0,0 +1,23 @@ +.. _-mapUnmatchedPath-: + +mapUnmatchedPath +================ + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: mapUnmatchedPath + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0mapUnmatchedPath diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/pass.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/pass.rst similarity index 56% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/pass.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/pass.rst index ac4a9c84ab..00a5c266d4 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/pass.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/pass.rst @@ -8,7 +8,7 @@ A directive that passes the request unchanged to its inner route. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: pass Description @@ -20,6 +20,6 @@ The directive is usually used as a "neutral element" when combining directives g Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: pass diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/provide.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/provide.rst similarity index 66% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/provide.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/provide.rst index 5b0a986eee..f2ea345e41 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/provide.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/provide.rst @@ -8,7 +8,7 @@ Provides a constant value to the inner route. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: provide Description @@ -22,5 +22,5 @@ See :ref:`ProvideDirectives` for an overview of similar directives. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: 0provide diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/recoverRejections.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/recoverRejections.rst new file mode 100644 index 0000000000..8d79bc1203 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/recoverRejections.rst @@ -0,0 +1,23 @@ +.. _-recoverRejections-: + +recoverRejections +================= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: recoverRejections + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0recoverRejections diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/recoverRejectionsWith.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/recoverRejectionsWith.rst new file mode 100644 index 0000000000..4fa93a3720 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/recoverRejectionsWith.rst @@ -0,0 +1,23 @@ +.. _-recoverRejectionsWith-: + +recoverRejectionsWith +===================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: recoverRejectionsWith + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0recoverRejectionsWith diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/textract.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/textract.rst similarity index 67% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/textract.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/textract.rst index 118a0e7505..4ce0a5b694 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/textract.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/textract.rst @@ -3,12 +3,12 @@ textract ======== -Calculates a Tuple of values from the request context and provides them to the inner route. +Calculates a tuple of values from the request context and provides them to the inner route. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: textract Description @@ -24,5 +24,5 @@ See :ref:`ProvideDirectives` for an overview of similar directives. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: textract diff --git a/akka-docs-dev/rst/scala/http/directives/basic-directives/tprovide.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/tprovide.rst similarity index 65% rename from akka-docs-dev/rst/scala/http/directives/basic-directives/tprovide.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/tprovide.rst index 555deb9c63..e0a442f4f5 100644 --- a/akka-docs-dev/rst/scala/http/directives/basic-directives/tprovide.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/tprovide.rst @@ -3,12 +3,12 @@ tprovide ======== -Provides an HList of values to the inner route. +Provides a tuple of values to the inner route. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala :snippet: tprovide Description @@ -24,5 +24,5 @@ See :ref:`ProvideDirectives` for an overview of similar directives. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala :snippet: tprovide diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withExecutionContext.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withExecutionContext.rst new file mode 100644 index 0000000000..a75f28223c --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withExecutionContext.rst @@ -0,0 +1,23 @@ +.. _-withExecutionContext-: + +withExecutionContext +==================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: withExecutionContext + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0withExecutionContext diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withFlowMaterializer.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withFlowMaterializer.rst new file mode 100644 index 0000000000..8054897939 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withFlowMaterializer.rst @@ -0,0 +1,23 @@ +.. _-withFlowMaterializer-: + +withFlowMaterializer +==================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: withFlowMaterializer + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0withFlowMaterializer diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withLog.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withLog.rst new file mode 100644 index 0000000000..d159760fab --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withLog.rst @@ -0,0 +1,23 @@ +.. _-withLog-: + +withLog +======= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: withLog + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0withLog diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withSettings.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withSettings.rst new file mode 100644 index 0000000000..1d0f76206f --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/basic-directives/withSettings.rst @@ -0,0 +1,23 @@ +.. _-withSettings-: + +withSettings +============ + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/BasicDirectives.scala + :snippet: withSettings + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/BasicDirectivesExamplesSpec.scala + :snippet: 0withSettings diff --git a/akka-docs-dev/rst/scala/http/directives/by-trait.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/by-trait.rst similarity index 95% rename from akka-docs-dev/rst/scala/http/directives/by-trait.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/by-trait.rst index 494aeec2bd..6d2aff8a15 100644 --- a/akka-docs-dev/rst/scala/http/directives/by-trait.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/by-trait.rst @@ -50,9 +50,6 @@ Directives creating or transforming the response :ref:`CacheConditionDirectives` Support for conditional requests (``304 Not Modified`` responses). -:ref:`ChunkingDirectives` - Automatically break a response into chunks. - :ref:`CookieDirectives` Set, modify, or delete cookies. @@ -83,8 +80,6 @@ List of predefined directives by trait basic-directives/index cache-condition-directives/index - caching-directives/index - chunking-directives/index coding-directives/index cookie-directives/index debugging-directives/index @@ -104,3 +99,4 @@ List of predefined directives by trait route-directives/index scheme-directives/index security-directives/index + websocket-directives/index diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/cache-condition-directives/conditional.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cache-condition-directives/conditional.rst new file mode 100644 index 0000000000..4723a1201b --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cache-condition-directives/conditional.rst @@ -0,0 +1,40 @@ +.. _-conditional-: + +conditional +=========== + +Wraps its inner route with support for Conditional Requests as defined +by http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-26. + + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CacheConditionDirectives.scala + :snippet: conditional + + +Description +----------- + +Depending on the given ``eTag`` and ``lastModified`` values this directive immediately responds with +``304 Not Modified`` or ``412 Precondition Failed`` (without calling its inner route) if the request comes with the +respective conditional headers. Otherwise the request is simply passed on to its inner route. + +The algorithm implemented by this directive closely follows what is defined in `this section`__ of the +`HTTPbis spec`__. + +All responses (the ones produces by this directive itself as well as the ones coming back from the inner route) are +augmented with respective ``ETag`` and ``Last-Modified`` response headers. + +Since this directive requires the ``EntityTag`` and ``lastModified`` time stamp for the resource as concrete arguments +it is usually used quite deep down in the route structure (i.e. close to the leaf-level), where the exact resource +targeted by the request has already been established and the respective ETag/Last-Modified values can be determined. + + +The :ref:`FileAndResourceDirectives` internally use the ``conditional`` directive for ETag and Last-Modified support +(if the ``spray.routing.file-get-conditional`` setting is enabled). + +__ http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-26#section-6 +__ https://datatracker.ietf.org/wg/httpbis/ + diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/cache-condition-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cache-condition-directives/index.rst new file mode 100644 index 0000000000..dc556082cd --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cache-condition-directives/index.rst @@ -0,0 +1,9 @@ +.. _CacheConditionDirectives: + +CacheConditionDirectives +======================== + +.. toctree:: + :maxdepth: 1 + + conditional \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/directives/coding-directives/decodeRequest.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/decodeRequest.rst similarity index 77% rename from akka-docs-dev/rst/scala/http/directives/coding-directives/decodeRequest.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/decodeRequest.rst index b7af31d17d..17b5c4fa75 100644 --- a/akka-docs-dev/rst/scala/http/directives/coding-directives/decodeRequest.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/decodeRequest.rst @@ -9,7 +9,7 @@ Tries to decode the request with the specified ``Decoder`` or rejects the reques Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala :snippet: decodeRequest Description @@ -26,5 +26,5 @@ The ``decodeRequest`` directive is the building block for the ``decompressReques Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/CodingDirectivesExamplesSpec.scala :snippet: decodeRequest diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/decodeRequestWith.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/decodeRequestWith.rst new file mode 100644 index 0000000000..598586aafc --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/decodeRequestWith.rst @@ -0,0 +1,23 @@ +.. _-decodeRequestWith-: + +decodeRequestWith +================= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala + :snippet: decodeRequestWith + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/CodingDirectivesExamplesSpec.scala + :snippet: 0decodeRequestWith diff --git a/akka-docs-dev/rst/scala/http/directives/coding-directives/encodeResponse.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/encodeResponse.rst similarity index 85% rename from akka-docs-dev/rst/scala/http/directives/coding-directives/encodeResponse.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/encodeResponse.rst index 9fa09027f0..b3c3f26f48 100644 --- a/akka-docs-dev/rst/scala/http/directives/coding-directives/encodeResponse.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/encodeResponse.rst @@ -9,7 +9,7 @@ Tries to encode the response with the specified ``Encoder`` or rejects the reque Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala :snippet: encodeResponse Description @@ -34,5 +34,5 @@ The ``encodeResponse`` directive is the building block for the ``compressRespons Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/CodingDirectivesExamplesSpec.scala :snippet: encodeResponse diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/encodeResponseWith.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/encodeResponseWith.rst new file mode 100644 index 0000000000..6f75cb9969 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/encodeResponseWith.rst @@ -0,0 +1,23 @@ +.. _-encodeResponseWith-: + +encodeResponseWith +================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala + :snippet: encodeResponseWith + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/CodingDirectivesExamplesSpec.scala + :snippet: 0encodeResponseWith diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/index.rst new file mode 100644 index 0000000000..c4661495e0 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/index.rst @@ -0,0 +1,14 @@ +.. _CodingDirectives: + +CodingDirectives +================ + +.. toctree:: + :maxdepth: 1 + + decodeRequest + decodeRequestWith + encodeResponse + encodeResponseWith + requestEncodedWith + responseEncodingAccepted \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/directives/coding-directives/requestEncodedWith.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/requestEncodedWith.rst similarity index 78% rename from akka-docs-dev/rst/scala/http/directives/coding-directives/requestEncodedWith.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/requestEncodedWith.rst index 7a544b89fe..ff19607ce6 100644 --- a/akka-docs-dev/rst/scala/http/directives/coding-directives/requestEncodedWith.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/requestEncodedWith.rst @@ -9,7 +9,7 @@ rejects the request with an ``UnacceptedRequestEncodingRejection(encoding)``. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala :snippet: requestEncodedWith Description diff --git a/akka-docs-dev/rst/scala/http/directives/coding-directives/responseEncodingAccepted.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/responseEncodingAccepted.rst similarity index 79% rename from akka-docs-dev/rst/scala/http/directives/coding-directives/responseEncodingAccepted.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/responseEncodingAccepted.rst index bf23437289..6a340bfffd 100644 --- a/akka-docs-dev/rst/scala/http/directives/coding-directives/responseEncodingAccepted.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/coding-directives/responseEncodingAccepted.rst @@ -9,7 +9,7 @@ rejects the request with an ``UnacceptedResponseEncodingRejection(encoding)``. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala :snippet: responseEncodingAccepted Description diff --git a/akka-docs-dev/rst/scala/http/directives/cookie-directives/cookie.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/cookie.rst similarity index 63% rename from akka-docs-dev/rst/scala/http/directives/cookie-directives/cookie.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/cookie.rst index 914d690775..17f6dfc77b 100644 --- a/akka-docs-dev/rst/scala/http/directives/cookie-directives/cookie.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/cookie.rst @@ -9,7 +9,7 @@ the cookie is missing. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CookieDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CookieDirectives.scala :snippet: cookie Description @@ -21,5 +21,5 @@ Use the :ref:`-optionalCookie-` directive instead if you want to support missing Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/CookieDirectivesExamplesSpec.scala :snippet: cookie diff --git a/akka-docs-dev/rst/scala/http/directives/cookie-directives/deleteCookie.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/deleteCookie.rst similarity index 59% rename from akka-docs-dev/rst/scala/http/directives/cookie-directives/deleteCookie.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/deleteCookie.rst index 089786f0c7..ec287b6873 100644 --- a/akka-docs-dev/rst/scala/http/directives/cookie-directives/deleteCookie.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/deleteCookie.rst @@ -8,7 +8,7 @@ Adds a header to the response to request the removal of the cookie with the give Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CookieDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CookieDirectives.scala :snippet: deleteCookie Description @@ -19,5 +19,5 @@ Use the :ref:`-setCookie-` directive to update a cookie. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/CookieDirectivesExamplesSpec.scala :snippet: deleteCookie diff --git a/akka-docs-dev/rst/scala/http/directives/cookie-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/index.rst similarity index 100% rename from akka-docs-dev/rst/scala/http/directives/cookie-directives/index.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/index.rst diff --git a/akka-docs-dev/rst/scala/http/directives/cookie-directives/optionalCookie.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/optionalCookie.rst similarity index 59% rename from akka-docs-dev/rst/scala/http/directives/cookie-directives/optionalCookie.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/optionalCookie.rst index 150df7f963..614204eb35 100644 --- a/akka-docs-dev/rst/scala/http/directives/cookie-directives/optionalCookie.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/optionalCookie.rst @@ -8,7 +8,7 @@ Extracts an optional cookie with a given name from a request. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CookieDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CookieDirectives.scala :snippet: optionalCookie Description @@ -20,5 +20,5 @@ Use the :ref:`-cookie-` directive instead if the inner route does not handle a m Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/CookieDirectivesExamplesSpec.scala :snippet: optionalCookie diff --git a/akka-docs-dev/rst/scala/http/directives/cookie-directives/setCookie.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/setCookie.rst similarity index 58% rename from akka-docs-dev/rst/scala/http/directives/cookie-directives/setCookie.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/setCookie.rst index 1b6e840fbe..d4afb2856a 100644 --- a/akka-docs-dev/rst/scala/http/directives/cookie-directives/setCookie.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/cookie-directives/setCookie.rst @@ -8,7 +8,7 @@ Adds a header to the response to request the update of the cookie with the given Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CookieDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/CookieDirectives.scala :snippet: setCookie Description @@ -20,5 +20,5 @@ Use the :ref:`-deleteCookie-` directive to delete a cookie. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/CookieDirectivesExamplesSpec.scala :snippet: setCookie diff --git a/akka-docs-dev/rst/scala/http/custom-directives.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/custom-directives.rst similarity index 89% rename from akka-docs-dev/rst/scala/http/custom-directives.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/custom-directives.rst index 4d8cafc5f4..b7f33f9208 100644 --- a/akka-docs-dev/rst/scala/http/custom-directives.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/custom-directives.rst @@ -3,4 +3,4 @@ Custom Directives ================= -*TODO* +... diff --git a/akka-docs-dev/rst/scala/http/directives/debugging-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/index.rst similarity index 100% rename from akka-docs-dev/rst/scala/http/directives/debugging-directives/index.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/index.rst diff --git a/akka-docs-dev/rst/scala/http/directives/debugging-directives/logRequest.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/logRequest.rst similarity index 93% rename from akka-docs-dev/rst/scala/http/directives/debugging-directives/logRequest.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/logRequest.rst index 954340c36d..e2caabb814 100644 --- a/akka-docs-dev/rst/scala/http/directives/debugging-directives/logRequest.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/logRequest.rst @@ -42,5 +42,5 @@ Use ``logResult`` for logging the response, or ``logRequestResult`` for logging Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/DebuggingDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/DebuggingDirectivesExamplesSpec.scala :snippet: logRequest-0 diff --git a/akka-docs-dev/rst/scala/http/directives/debugging-directives/logRequestResult.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/logRequestResult.rst similarity index 88% rename from akka-docs-dev/rst/scala/http/directives/debugging-directives/logRequestResult.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/logRequestResult.rst index afbdf9c85d..aa75d4876e 100644 --- a/akka-docs-dev/rst/scala/http/directives/debugging-directives/logRequestResult.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/logRequestResult.rst @@ -1,7 +1,7 @@ .. _-logRequestResult-: logRequestResult -================== +================ Logs request and response. @@ -30,5 +30,5 @@ how these directives work. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/DebuggingDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/DebuggingDirectivesExamplesSpec.scala :snippet: logRequestResult diff --git a/akka-docs-dev/rst/scala/http/directives/debugging-directives/logResult.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/logResult.rst similarity index 80% rename from akka-docs-dev/rst/scala/http/directives/debugging-directives/logResult.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/logResult.rst index 775b16a804..037bc52aba 100644 --- a/akka-docs-dev/rst/scala/http/directives/debugging-directives/logResult.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/debugging-directives/logResult.rst @@ -1,7 +1,7 @@ .. _-logResult-: logResult -=========== +========= Logs the response. @@ -26,13 +26,12 @@ Description See ``logRequest`` for the general description how these directives work. This directive is different as it requires a ``LoggingMagnet[Any => Unit]``. Instead of just logging ``HttpResponses``, ``logResult`` is able to -log anything passing through :ref:`The Responder Chain` (which can either be a ``HttpResponsePart`` or a ``Rejected`` -message reporting rejections). +log any :ref:`RouteResult` coming back from the inner route. Use ``logRequest`` for logging the request, or ``logRequestResult`` for logging both. Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/DebuggingDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/DebuggingDirectivesExamplesSpec.scala :snippet: logResult diff --git a/akka-docs-dev/rst/scala/http/directives/execution-directives/handleExceptions.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/execution-directives/handleExceptions.rst similarity index 69% rename from akka-docs-dev/rst/scala/http/directives/execution-directives/handleExceptions.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/execution-directives/handleExceptions.rst index 8d973df767..fb90d5cd55 100644 --- a/akka-docs-dev/rst/scala/http/directives/execution-directives/handleExceptions.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/execution-directives/handleExceptions.rst @@ -8,7 +8,7 @@ Catches exceptions thrown by the inner route and handles them using the specifie Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/ExecutionDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/ExecutionDirectives.scala :snippet: handleExceptions Description @@ -22,5 +22,5 @@ See :ref:`Exception Handling` for general information about options for handling Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/ExecutionDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ExecutionDirectivesExamplesSpec.scala :snippet: handleExceptions diff --git a/akka-docs-dev/rst/scala/http/directives/execution-directives/handleRejections.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/execution-directives/handleRejections.rst similarity index 69% rename from akka-docs-dev/rst/scala/http/directives/execution-directives/handleRejections.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/execution-directives/handleRejections.rst index 4494b360cd..7feb7a5ff7 100644 --- a/akka-docs-dev/rst/scala/http/directives/execution-directives/handleRejections.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/execution-directives/handleRejections.rst @@ -8,7 +8,7 @@ Handles rejections produced by the inner route and handles them using the specif Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/ExecutionDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/ExecutionDirectives.scala :snippet: handleRejections Description @@ -22,5 +22,5 @@ See :ref:`Rejections` for general information about options for handling rejecti Example ------- -.. includecode2:: ../../../code/docs/http/server/directives/ExecutionDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ExecutionDirectivesExamplesSpec.scala :snippet: handleRejections diff --git a/akka-docs-dev/rst/scala/http/directives/execution-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/execution-directives/index.rst similarity index 100% rename from akka-docs-dev/rst/scala/http/directives/execution-directives/index.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/execution-directives/index.rst diff --git a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromBrowseableDirectories.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromBrowseableDirectories.rst similarity index 85% rename from akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromBrowseableDirectories.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromBrowseableDirectories.rst index 50e931116d..7babd5422d 100644 --- a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromBrowseableDirectories.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromBrowseableDirectories.rst @@ -9,7 +9,7 @@ served as browsable listings. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala :snippet: getFromBrowseableDirectories Description diff --git a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromBrowseableDirectory.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromBrowseableDirectory.rst similarity index 64% rename from akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromBrowseableDirectory.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromBrowseableDirectory.rst index 447870c416..4cb815885d 100644 --- a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromBrowseableDirectory.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromBrowseableDirectory.rst @@ -8,6 +8,6 @@ The single-directory variant of :ref:`-getFromBrowseableDirectories-`. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala :snippet: getFromBrowseableDirectory diff --git a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromDirectory.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromDirectory.rst similarity index 87% rename from akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromDirectory.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromDirectory.rst index b2ce609b96..e75b5a7c7c 100644 --- a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromDirectory.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromDirectory.rst @@ -8,7 +8,7 @@ Completes GET requests with the content of a file underneath the given directory Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala :snippet: getFromDirectory Description diff --git a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromFile.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromFile.rst similarity index 83% rename from akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromFile.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromFile.rst index a207e8aa18..0031d1a94d 100644 --- a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromFile.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromFile.rst @@ -8,7 +8,7 @@ Completes GET requests with the content of the given file. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala :snippet: getFromFile Description diff --git a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromResource.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromResource.rst similarity index 84% rename from akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromResource.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromResource.rst index 05dc013553..8be3cf95fe 100644 --- a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromResource.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromResource.rst @@ -8,7 +8,7 @@ Completes GET requests with the content of the given classpath resource. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala :snippet: getFromResource Description diff --git a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromResourceDirectory.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromResourceDirectory.rst similarity index 85% rename from akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromResourceDirectory.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromResourceDirectory.rst index e6d0cc9a71..106578fe80 100644 --- a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/getFromResourceDirectory.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/getFromResourceDirectory.rst @@ -8,7 +8,7 @@ Completes GET requests with the content of the given classpath resource director Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala :snippet: getFromResourceDirectory Description diff --git a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/index.rst similarity index 100% rename from akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/index.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/index.rst diff --git a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/listDirectoryContents.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/listDirectoryContents.rst similarity index 86% rename from akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/listDirectoryContents.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/listDirectoryContents.rst index a7987ed69b..92530c5b8c 100644 --- a/akka-docs-dev/rst/scala/http/directives/file-and-resource-directives/listDirectoryContents.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/file-and-resource-directives/listDirectoryContents.rst @@ -9,7 +9,7 @@ directory contents is performed by the in-scope `Marshaller[DirectoryListing]`. Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FileAndResourceDirectives.scala :snippet: listDirectoryContents Description diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/form-field-directives/formField.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/form-field-directives/formField.rst new file mode 100644 index 0000000000..6d4ac3ef0f --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/form-field-directives/formField.rst @@ -0,0 +1,17 @@ +.. _-formField-: + +formField +========= + +An alias for :ref:`-formFields-`. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FormFieldDirectives.scala + :snippet: formField + +Description +----------- + +See :ref:`-formFields-`. diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/form-field-directives/formFields.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/form-field-directives/formFields.rst new file mode 100644 index 0000000000..889e0ad16f --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/form-field-directives/formFields.rst @@ -0,0 +1,98 @@ +.. _-formFields-: + +formFields +========== + +Extracts fields from POST requests generated by HTML forms. + +Signature +--------- + +:: + + def formFields(field: ): Directive1[T] + def formFields(fields: *): Directive[T_0 :: ... T_i ... :: HNil] + def formFields(fields: :: ... ... :: HNil): Directive[T_0 :: ... T_i ... :: HNil] + +The signature shown is simplified and written in pseudo-syntax, the real signature uses magnets. [1]_ The type +```` doesn't really exist but consists of the syntactic variants as shown in the description and the examples. + +.. [1] See `The Magnet Pattern`_ for an explanation of magnet-based overloading. +.. _`The Magnet Pattern`: /blog/2012-12-13-the-magnet-pattern/ + +Description +----------- + +Form fields can be either extracted as a String or can be converted to another type. The parameter name +can be supplied either as a String or as a Symbol. Form field extraction can be modified to mark a field +as required or optional or to filter requests where a form field has a certain value: + +``"color"`` + extract value of field "color" as ``String`` +``"color".?`` + extract optional value of field "color" as ``Option[String]`` +``"color" ? "red"`` + extract optional value of field "color" as ``String`` with default value ``"red"`` +``"color" ! "blue"`` + require value of field "color" to be ``"blue"`` and extract nothing +``"amount".as[Int]`` + extract value of field "amount" as ``Int``, you need a matching implicit ``Deserializer`` in scope for that to work + (see also :ref:`http-unmarshalling-scala`) +``"amount".as(deserializer)`` + extract value of field "amount" with an explicit ``Deserializer`` + +You can use :ref:`Case Class Extraction` to group several extracted values together into a case-class +instance. + +Requests missing a required field or field value will be rejected with an appropriate rejection. + +There's also a singular version, ``formField``. Query parameters can be handled in a similar way, see ``parameters``. If +you want unified handling for both query parameters and form fields, see ``anyParams``. + +Unmarshalling +------------- + +Data POSTed from `HTML forms`_ is either of type ``application/x-www-form-urlencoded`` or of type +``multipart/form-data``. The value of an url-encoded field is a ``String`` while the value of a +``multipart/form-data``-encoded field is a "body part" containing an entity. This means that different kind of deserializers are needed depending +on what the Content-Type of the request is: + + - A ``application/x-www-form-urlencoded`` encoded field needs an implicit ``Deserializer[Option[String], T]`` + - A ``multipart/form-data`` encoded field needs an implicit ``Deserializer[Option[BodyPart], T]`` + +For common data-types, these implicits are predefined so that you usually don't need to care. For custom data-types it +should usually suffice to create a ``Deserializer[String, T]`` if the value will be encoded as a ``String``. +This should be valid for all values generated by HTML forms apart from file uploads. + +Details +....... + +It should only be necessary to read and understand this paragraph if you have very special needs and need to process +arbitrary forms, especially ones not generated by HTML forms. + +The ``formFields`` directive contains this logic to find and decide how to deserialize a POSTed form field: + + - It tries to find implicits of both types at the definition site if possible or otherwise at least one of both. If + none is available compilation will fail with an "implicit not found" error. + - Depending on the ``Content-Type`` of the incoming request it first tries the matching (see above) one if available. + - If only a ``Deserializer[Option[String], T]`` is available when a request of type ``multipart/form-data`` is + received, this deserializer will be tried to deserialize the body part for a field if the entity is of type + ``text/plain`` or unspecified. + - If only a ``Deserializer[Option[BodyPart], T]`` is available when a request of type + ``application/x-www-form-urlencoded`` is received, this deserializer will be tried to deserialize the field value by + packing the field value into a body part with an entity of type ``text/plain``. Deserializing will only succeed if + the deserializer accepts entities of type ``text/plain``. + +If you need to handle encoded fields of a ``multipart/form-data``-encoded request for a custom type, you therefore need +to provide a ``Deserializer[Option[BodyPart], T]``. + +.. _HTML forms: http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4 + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/FormFieldDirectivesExamplesSpec.scala + :snippet: formFields + +For more examples about the way how fields can specified see the examples for the ``parameters`` directive. diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/form-field-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/form-field-directives/index.rst new file mode 100644 index 0000000000..80c461f02f --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/form-field-directives/index.rst @@ -0,0 +1,10 @@ +.. _FormFieldDirectives: + +FormFieldDirectives +=================== + +.. toctree:: + :maxdepth: 1 + + formField + formFields \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/completeOrRecoverWith.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/completeOrRecoverWith.rst new file mode 100644 index 0000000000..b7b7617d91 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/completeOrRecoverWith.rst @@ -0,0 +1,23 @@ +.. _-completeOrRecoverWith-: + +completeOrRecoverWith +===================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FutureDirectives.scala + :snippet: completeOrRecoverWith + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/FutureDirectivesExamplesSpec.scala + :snippet: 0completeOrRecoverWith diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/index.rst new file mode 100644 index 0000000000..55f98bbc45 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/index.rst @@ -0,0 +1,14 @@ +.. _FutureDirectives: + +FuturesDirectives +================= + +Future directives can be used to run inner routes once the provided ``Future[T]`` has been completed. + +.. toctree:: + :maxdepth: 1 + + onComplete + onSuccess + completeOrRecoverWith + diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/onComplete.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/onComplete.rst new file mode 100644 index 0000000000..8c62e96caf --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/onComplete.rst @@ -0,0 +1,23 @@ +.. _-onComplete-: + +onComplete +========== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FutureDirectives.scala + :snippet: onComplete + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/FutureDirectivesExamplesSpec.scala + :snippet: 0onComplete diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/onSuccess.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/onSuccess.rst new file mode 100644 index 0000000000..449dd71928 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/future-directives/onSuccess.rst @@ -0,0 +1,23 @@ +.. _-onSuccess-: + +onSuccess +========= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/FutureDirectives.scala + :snippet: onSuccess + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/FutureDirectivesExamplesSpec.scala + :snippet: 0onSuccess diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValue.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValue.rst new file mode 100644 index 0000000000..3e3efc5936 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValue.rst @@ -0,0 +1,30 @@ +.. _-headerValue-: + +headerValue +=========== + +Traverses the list of request headers with the specified function and extracts the first value the function returns as +``Some(value)``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala + :snippet: headerValue + +Description +----------- + +The ``headerValue`` directive is a mixture of ``map`` and ``find`` on the list of request headers. The specified function +is called once for each header until the function returns ``Some(value)``. This value is extracted and presented to the +inner route. If the function throws an exception the request is rejected with a ``MalformedHeaderRejection``. If the +function returns ``None`` for every header the request is rejected as "NotFound". + +This directive is the basis for building other request header related directives. See ``headerValuePF`` for a nicer +syntactic alternative. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HeaderDirectivesExamplesSpec.scala + :snippet: headerValue-0 diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValueByName.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValueByName.rst new file mode 100644 index 0000000000..6b245fdba5 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValueByName.rst @@ -0,0 +1,25 @@ +.. _-headerValueByName-: + +headerValueByName +================= + +Extracts the value of the HTTP request header with the given name. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala + :snippet: headerValueByName + +Description +----------- + +The name can be given as a ``String`` or as a ``Symbol``. If no header with a matching name is found the request +is rejected with a ``MissingHeaderRejection``. If the header is expected to be missing in some cases or to customize +handling when the header is missing use the :ref:`-optionalHeaderValueByName-` directive instead. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HeaderDirectivesExamplesSpec.scala + :snippet: headerValueByName-0 diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValueByType.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValueByType.rst new file mode 100644 index 0000000000..430c067ede --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValueByType.rst @@ -0,0 +1,32 @@ +.. _-headerValueByType-: + +headerValueByType +================= + +Traverses the list of request headers and extracts the first header of the given type. + +Signature +--------- + +:: + + def headerValueByType[T <: HttpHeader: ClassTag](): Directive1[T] + +The signature shown is simplified, the real signature uses magnets. [1]_ + +.. [1] See `The Magnet Pattern`_ for an explanation of magnet-based overloading. +.. _`The Magnet Pattern`: /blog/2012-12-13-the-magnet-pattern/ + +Description +----------- + +The ``headerValueByType`` directive finds a header of the given type in the list of request header. If no header of +the given type is found the request is rejected with a ``MissingHeaderRejection``. If the header is expected to be +missing in some cases or to customize handling when the header is missing use the ``optionalHeaderValueByType`` +directive instead. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HeaderDirectivesExamplesSpec.scala + :snippet: headerValueByType-0 diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValuePF.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValuePF.rst new file mode 100644 index 0000000000..2cc2d63528 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/headerValuePF.rst @@ -0,0 +1,26 @@ +.. _-headerValuePF-: + +headerValuePF +============= + +Calls the specified partial function with the first request header the function is ``isDefinedAt`` and extracts the +result of calling the function. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala + :snippet: headerValuePF + +Description +----------- + +The ``headerValuePF`` directive is an alternative syntax version of ``headerValue``. If the function throws an +exception the request is rejected with a ``MalformedHeaderRejection``. If the function is not defined for +any header the request is rejected as "NotFound". + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HeaderDirectivesExamplesSpec.scala + :snippet: headerValuePF-0 diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/index.rst new file mode 100644 index 0000000000..0e08cd0350 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/index.rst @@ -0,0 +1,19 @@ +.. _HeaderDirectives: + +HeaderDirectives +================ + +Header directives can be used to extract header values from the request. To change +response headers use one of the :ref:`RespondWithDirectives`. + +.. toctree:: + :maxdepth: 1 + + headerValue + headerValueByName + headerValueByType + headerValuePF + optionalHeaderValue + optionalHeaderValueByName + optionalHeaderValueByType + optionalHeaderValuePF diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValue.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValue.rst new file mode 100644 index 0000000000..dce0415dcd --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValue.rst @@ -0,0 +1,19 @@ +.. _-optionalHeaderValue-: + +optionalHeaderValue +=================== + +Traverses the list of request headers with the specified function and extracts the first value the function returns as +``Some(value)``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala + :snippet: optionalHeaderValue + +Description +----------- + +The ``optionalHeaderValue`` directive is similar to the ``headerValue`` directive but always extracts an ``Option`` +value instead of rejecting the request if no matching header could be found. diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValueByName.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValueByName.rst new file mode 100644 index 0000000000..64bf605387 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValueByName.rst @@ -0,0 +1,18 @@ +.. _-optionalHeaderValueByName-: + +optionalHeaderValueByName +========================= + +Optionally extracts the value of the HTTP request header with the given name. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala + :snippet: optionalHeaderValueByName + +Description +----------- + +The ``optionalHeaderValueByName`` directive is similar to the ``headerValueByName`` directive but always extracts +an ``Option`` value instead of rejecting the request if no matching header could be found. diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValueByType.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValueByType.rst new file mode 100644 index 0000000000..864e9c201e --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValueByType.rst @@ -0,0 +1,30 @@ +.. _-optionalHeaderValueByType-: + +optionalHeaderValueByType +========================= + +Optionally extracts the value of the HTTP request header of the given type. + +Signature +--------- + +:: + + def optionalHeaderValueByType[T <: HttpHeader: ClassTag](): Directive1[Option[T]] + +The signature shown is simplified, the real signature uses magnets. [1]_ + +.. [1] See `The Magnet Pattern`_ for an explanation of magnet-based overloading. +.. _`The Magnet Pattern`: /blog/2012-12-13-the-magnet-pattern/ + +Description +----------- + +The ``optionalHeaderValueByType`` directive is similar to the ``headerValueByType`` directive but always extracts +an ``Option`` value instead of rejecting the request if no matching header could be found. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HeaderDirectivesExamplesSpec.scala + :snippet: optionalHeaderValueByType-0 diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValuePF.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValuePF.rst new file mode 100644 index 0000000000..248ff86555 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/header-directives/optionalHeaderValuePF.rst @@ -0,0 +1,19 @@ +.. _-optionalHeaderValuePF-: + +optionalHeaderValuePF +===================== + +Calls the specified partial function with the first request header the function is ``isDefinedAt`` and extracts the +result of calling the function. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala + :snippet: optionalHeaderValuePF + +Description +----------- + +The ``optionalHeaderValuePF`` directive is similar to the ``headerValuePF`` directive but always extracts an ``Option`` +value instead of rejecting the request if no matching header could be found. diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/host-directives/extractHost.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/host-directives/extractHost.rst new file mode 100644 index 0000000000..c814c454f1 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/host-directives/extractHost.rst @@ -0,0 +1,27 @@ +.. _-extractHost-: + +extractHost +=========== + +Extracts the hostname part of the Host header value in the request. + + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/HostDirectives.scala + :snippet: extractHost + + +Description +----------- + +Extract the hostname part of the ``Host`` request header and expose it as a ``String`` extraction +to its inner route. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HostExamplesSpec.scala + :snippet: extract-hostname \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/host-directives/host.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/host-directives/host.rst new file mode 100644 index 0000000000..270b308bab --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/host-directives/host.rst @@ -0,0 +1,58 @@ +.. _-host-: + +host +==== + +Filter requests matching conditions against the hostname part of the Host header value +in the request. + + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/HostDirectives.scala + :snippet: host + + +Description +----------- + +The ``def host(hostNames: String*)`` overload rejects all requests with a hostname different from the given ones. + +The ``def host(predicate: String ⇒ Boolean)`` overload rejects all requests for which the hostname does +not satisfy the given predicate. + +The ``def host(regex: Regex)`` overload works a little bit different: it rejects all requests with a hostname +that doesn't have a prefix matching the given regular expression and also extracts a ``String`` to its +inner route following this rules: + + * For all matching requests the prefix string matching the regex is extracted and passed to the inner route. + * If the regex contains a capturing group only the string matched by this group is extracted. + * If the regex contains more than one capturing group an ``IllegalArgumentException`` is thrown. + + +Example +------- + +Matching a list of hosts: + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HostExamplesSpec.scala + :snippet: list-of-hosts + +Making sure the host satisfies the given predicate + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HostExamplesSpec.scala + :snippet: predicate + +Using a regular expressions: + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HostExamplesSpec.scala + :snippet: using-regex + +Beware that in the case of introducing multiple capturing groups in the regex such as in the case bellow, the +directive will fail at runtime, at the moment the route tree is evaluated for the first time. This might cause +your http handler actor to enter in a fail/restart loop depending on your supervision strategy. + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HostExamplesSpec.scala + :snippet: failing-regex + diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/host-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/host-directives/index.rst new file mode 100644 index 0000000000..2bd2f44252 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/host-directives/index.rst @@ -0,0 +1,13 @@ +.. _HostDirectives: + +HostDirectives +============== + +HostDirectives allow you to filter requests based on the hostname part of the ``Host`` header +contained in incoming requests as well as extracting its value for usage in inner routes. + +.. toctree:: + :maxdepth: 1 + + extractHost + host diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/index.rst new file mode 100644 index 0000000000..19cb5815ec --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/index.rst @@ -0,0 +1,224 @@ +.. _Directives: + +Directives +========== + +A "Directive" is a small building block used for creating arbitrarily complex :ref:`route structures `. +Akka HTTP already pre-defines a large number of directives and you can easily construct your own: + +.. toctree:: + :maxdepth: 1 + + alphabetically + by-trait + custom-directives + + +Basics +------ + +Directives create :ref:`Routes`. To understand how directives work it is helpful to contrast them with the "primitive" +way of creating routes. + +Since ``Route`` is just a type alias for a function type ``Route`` instances can be written in any way in which function +instances can be written, e.g. as a function literal:: + + val route: Route = { ctx => ctx.complete("yeah") } + +or shorter:: + + val route: Route = _.complete("yeah") + +With the :ref:`-complete-` directive this becomes even shorter:: + + val route = complete("yeah") + +These three ways of writing this ``Route`` are fully equivalent, the created ``route`` will behave identically in all +cases. + +Let's look at a slightly more complicated example to highlight one important point in particular. +Consider these two routes:: + + val a: Route = { + println("MARK") + ctx => ctx.complete("yeah") + } + + val b: Route = { ctx => + println("MARK") + ctx.complete("yeah") + } + +The difference between ``a`` and ``b`` is when the ``println`` statement is executed. +In the case of ``a`` it is executed *once*, when the route is constructed, whereas in the case of ``b`` it is executed +every time the route is *run*. + +Using the :ref:`-complete-` directive the same effects are achieved like this:: + + val a = { + println("MARK") + complete("yeah") + } + + val b = complete { + println("MARK") + "yeah" + } + +This works because the argument to the :ref:`-complete-` directive is evaluated *by-name*, i.e. it is re-evaluated +every time the produced route is run. + +Let's take things one step further:: + + val route: Route = { ctx => + if (ctx.request.method == HttpMethods.GET) + ctx.complete("Received GET") + else + ctx.complete("Received something else") + } + +Using the :ref:`-get-` and :ref:`-complete-` directives we can write this route like this:: + + val route = + get { + complete("Received GET") + } ~ + complete("Received something else") + +Again, the produced routes will behave identically in all cases. + +Note that, if you wish, you can also mix the two styles of route creation:: + + val route = + get { ctx => + ctx.complete("Received GET") + } ~ + complete("Received something else") + +Here, the inner route of the :ref:`-get-` directive is written as an explicit function literal. + +However, as you can see from these examples, building routes with directives rather than "manually" results in code that +is a lot more concise and as such more readable and maintainable. In addition it provides for better composability (as +you will see in the coming sections). So, when using Akka HTTP's Routing DSL you should almost never have to fall back +to creating routes via ``Route`` function literals that directly manipulate the :ref:`RequestContext`. + + +Structure +--------- + +The general anatomy of a directive is as follows:: + + name(arguments) { extractions => + ... // inner route + } + +It has a name, zero or more arguments and optionally an inner route (The :ref:`RouteDirectives` are special in that they +are always used at the leaf-level and as such cannot have inner routes). +Additionally directives can "extract" a number of values and make them available to their inner routes as function +arguments. When seen "from the outside" a directive with its inner route form an expression of type ``Route``. + + +What Directives do +------------------ + +A directive can do one or more of the following: + +.. rst-class:: wide + +* Transform the incoming ``RequestContext`` before passing it on to its inner route (i.e. modify the request) +* Filter the ``RequestContext`` according to some logic, i.e. only pass on certain requests and reject others +* Extract values from the ``RequestContext`` and make them available to its inner route as "extractions" +* Chain some logic into the :ref:`RouteResult` future transformation chain (i.e. modify the response or rejection) +* Complete the request + +This means a ``Directive`` completely wraps the functionality of its inner route and can apply arbitrarily complex +transformations, both (or either) on the request and on the response side. + + +Composing Directives +-------------------- + +As you have seen from the examples presented so far the "normal" way of composing directives is nesting. +Let's take a look at this concrete example: + +.. includecode2:: ../../../code/docs/http/scaladsl/server/DirectiveExamplesSpec.scala + :snippet: example-1 + +Here the ``get`` and ``put`` directives are chained together with the ``~`` operator to form a higher-level route that +serves as the inner route of the ``path`` directive. To make this structure more explicit you could also write the whole +thing like this: + +.. includecode2:: ../../../code/docs/http/scaladsl/server/DirectiveExamplesSpec.scala + :snippet: example-2 + +What you can't see from this snippet is that directives are not implemented as simple methods but rather as stand-alone +objects of type ``Directive``. This gives you more flexibility when composing directives. For example you can +also use the ``|`` operator on directives. Here is yet another way to write the example: + +.. includecode2:: ../../../code/docs/http/scaladsl/server/DirectiveExamplesSpec.scala + :snippet: example-3 + +Or better (without dropping down to writing an explicit ``Route`` function manually): + +.. includecode2:: ../../../code/docs/http/scaladsl/server/DirectiveExamplesSpec.scala + :snippet: example-4 + +If you have a larger route structure where the ``(get | put)`` snippet appears several times you could also factor it +out like this: + +.. includecode2:: ../../../code/docs/http/scaladsl/server/DirectiveExamplesSpec.scala + :snippet: example-5 + +Note that, because ``getOrPut`` doesn't take any parameters, it can be a ``val`` here. + +As an alternative to nesting you can also use the `&` operator: + +.. includecode2:: ../../../code/docs/http/scaladsl/server/DirectiveExamplesSpec.scala + :snippet: example-6 + +Here you can see that, when directives producing extractions are combined with ``&``, the resulting "super-directive" +simply extracts the concatenation of its sub-extractions. + +And once again, you can factor things out if you want, thereby pushing the "factoring out" of directive configurations +to its extreme: + +.. includecode2:: ../../../code/docs/http/scaladsl/server/DirectiveExamplesSpec.scala + :snippet: example-7 + +This type of combining directives with the ``|`` and ``&`` operators as well as "saving" more complex directive +configurations as a ``val`` works across the board, with all directives taking inner routes. + +Note that going this far with "compressing" several directives into a single one probably doesn't result in the most +readable and therefore maintainable routing code. It might even be that the very first of this series of examples +is in fact the most readable one. + +Still, the purpose of the exercise presented here is to show you how flexible directives can be and how you can +use their power to define your web service behavior at the level of abstraction that is right for **your** application. + + +Type Safety of Directives +------------------------- + +When you combine directives with the ``|`` and ``&`` operators the routing DSL makes sure that all extractions work as +expected and logical constraints are enforced at compile-time. + +For example you cannot ``|`` a directive producing an extraction with one that doesn't:: + + val route = path("order" / IntNumber) | get // doesn't compile + +Also the number of extractions and their types have to match up:: + + val route = path("order" / IntNumber) | path("order" / DoubleNumber) // doesn't compile + val route = path("order" / IntNumber) | parameter('order.as[Int]) // ok + +When you combine directives producing extractions with the ``&`` operator all extractions will be properly gathered up:: + + val order = path("order" / IntNumber) & parameters('oem, 'expired ?) + val route = + order { (orderId, oem, expired) => + ... + } + +Directives offer a great way of constructing your web service logic from small building blocks in a plug and play +fashion while maintaining DRYness and full type-safety. If the large range of :ref:`Predefined Directives` does not +fully satisfy your needs you can also very easily create :ref:`Custom Directives`. diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/completeWith.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/completeWith.rst new file mode 100644 index 0000000000..9343aeac10 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/completeWith.rst @@ -0,0 +1,46 @@ +.. _-completeWith-: + +completeWith +============ + +Uses the marshaller for a given type to produce a completion function that is passed to its +inner route. You can use it to decouple marshaller resolution from request completion. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MarshallingDirectives.scala + :snippet: completeWith[T] + +Description +----------- + +The ``completeWith`` directive works in conjuction with ``instanceOf`` and ``spray.httpx.marshalling`` +to convert higher-level (object) structure into some lower-level serialized "wire format". +:ref:`The marshalling documentation ` explains this process in detail. +This directive simplifies exposing types to clients via a route while providing some +form of access to the current context. + +``completeWith`` is similar to ``handleWith``. The main difference is with ``completeWith`` you must eventually call +the completion function generated by ``completeWith``. ``handleWith`` will automatically call ``complete`` when the +``handleWith`` function returns. + +Examples +-------- + +The following example uses ``spray-json`` to marshall a simple ``Person`` class to a json +response. It utilizes ``SprayJsonSupport`` via the ``PersonJsonSupport`` object as the in-scope +unmarshaller. + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala + :snippet: person-json-support + + ... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala + :snippet: person-case-class + +The ``findPerson`` takes an argument of type ``Person => Unit`` which is generated by the ``completeWith`` +call. We can handle any logic we want in ``findPerson`` and call our completion function to +complete the request. + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala + :snippet: example-completeWith-with-json diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/entity.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/entity.rst new file mode 100644 index 0000000000..51ffdec320 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/entity.rst @@ -0,0 +1,52 @@ +.. _-entity-: + +entity +====== + +Unmarshalls the request entity to the given type and passes it to its inner Route. An unmarshaller +returns an ``Either`` with ``Right(value)`` if successful or ``Left(exception)`` for a failure. +The ``entity`` method will either pass the ``value`` to the inner route or map the ``exception`` to a +``spray.routing.Rejection``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MarshallingDirectives.scala + :snippet: entity + +Description +----------- + +The ``entity`` directive works in conjuction with ``as`` and ``spray.httpx.unmarshalling`` to +convert some serialized "wire format" value into a higher-level object structure. +:ref:`The unmarshalling documentation ` explains this process in detail. +This directive simplifies extraction and error handling to the specified type from the request. + +An unmarshaller will return a ``Left(exception)`` in the case of an error. This is converted to a +``spray.routing.Rejection`` within the ``entity`` directive. The following table lists how exceptions +are mapped to rejections: + +========================== ============ +Left(exception) Rejection +-------------------------- ------------ +``ContentExpected`` ``RequestEntityExpectedRejection`` +``UnsupportedContentType`` ``UnsupportedRequestContentTypeRejection``, which lists the supported types +``MaformedContent`` ``MalformedRequestContentRejection``, with an error message and cause +========================== ============ + +Examples +-------- + +The following example uses ``spray-json`` to unmarshall a json request into a simple ``Person`` +class. It utilizes ``SprayJsonSupport`` via the ``PersonJsonSupport`` object as the in-scope unmarshaller. + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala + :snippet: person-case-class + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala + :snippet: person-json-support + + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala + :snippet: example-entity-with-json + diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/handleWith.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/handleWith.rst new file mode 100644 index 0000000000..edd3ed3b05 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/handleWith.rst @@ -0,0 +1,48 @@ +.. _-handleWith-: + +handleWith +========== + +Completes the request using the given function. The input to the function is produced with +the in-scope entity unmarshaller and the result value of the function is marshalled with +the in-scope marshaller. ``handleWith`` can be a convenient method combining ``entity`` with +``complete``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MarshallingDirectives.scala + :snippet: handleWith + +Description +----------- + +The ``handleWith`` directive is used when you want to handle a route with a given function of +type A ⇒ B. ``handleWith`` will use both an in-scope unmarshaller to convert a request into +type A and an in-scope marshaller to convert type B into a response. This is helpful when your +core business logic resides in some other class or you want your business logic to be independent +of *Spray*. You can use ``handleWith`` to "hand off" processing to a given function without requiring +any spray-specific functionality. + +``handleWith`` is similar to ``produce``. The main difference is ``handleWith`` automatically +calls ``complete`` when the function passed to ``handleWith`` returns. Using ``produce`` you +must explicity call the completion function passed from the ``produce`` function. + +See :ref:`marshalling ` and :ref:`unmarshalling ` for guidance +on marshalling entities with Spray. + +Examples +-------- + +The following example uses an ``updatePerson`` function with a ``Person`` case class as an input and output. We plug this function into our route using ``handleWith``. + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala + :snippet: person-case-class + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala + :snippet: example-handleWith-with-json + +The PersonJsonSupport object handles both marshalling and unmarshalling of the Person case class. + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MarshallingDirectivesExamplesSpec.scala + :snippet: person-json-support diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/index.rst new file mode 100644 index 0000000000..0a3f89a275 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/marshalling-directives/index.rst @@ -0,0 +1,34 @@ +.. _MarshallingDirectives: + +Marshalling Directives +====================== + +Marshalling directives work in conjunction with ``spray.httpx.marshalling`` and ``spray.httpx.unmarshalling`` to convert +a request entity to a specific type or a type to a response. + +See :ref:`marshalling ` and :ref:`unmarshalling ` for specific +serialization (also known as pickling) guidance. + +Marshalling directives usually rely on an in-scope implicit marshaller to handle conversion. + +.. toctree:: + :maxdepth: 1 + + completeWith + entity + handleWith + +Understanding Specific Marshalling Directives +--------------------------------------------- + +======================================= ======================================= +directive behavior +======================================= ======================================= +:ref:`-completeWith-` Uses a marshaller for a given type to produce a completion function for an inner route. Used in conjuction with *instanceOf* to format responses. +:ref:`-entity-` Unmarshalls the request entity to the given type and passes it to its inner route. Used in conjection with *as* to convert requests to objects. +:ref:`-handleWith-` Completes a request with a given function, using an in-scope unmarshaller for an input and in-scope marshaller for the output. +======================================= ======================================= + + + + diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/delete.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/delete.rst new file mode 100644 index 0000000000..820343967f --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/delete.rst @@ -0,0 +1,28 @@ +.. _-delete-: + +delete +====== + +Matches requests with HTTP method ``DELETE``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala + :snippet: delete + + +Description +----------- + +This directive filters an incoming request by its HTTP method. Only requests with +method ``DELETE`` are passed on to the inner route. All others are rejected with a +``MethodRejection``, which is translated into a ``405 Method Not Allowed`` response +by the default :ref:`RejectionHandler `. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala + :snippet: delete-method diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/extractMethod.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/extractMethod.rst new file mode 100644 index 0000000000..5f9085175d --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/extractMethod.rst @@ -0,0 +1,23 @@ +.. _-extractMethod-: + +extractMethod +============= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala + :snippet: extractMethod + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala + :snippet: 0extractMethod diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/get.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/get.rst new file mode 100644 index 0000000000..c71fcba590 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/get.rst @@ -0,0 +1,27 @@ +.. _-get-: + +get +=== + +Matches requests with HTTP method ``GET``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala + :snippet: get + +Description +----------- + +This directive filters the incoming request by its HTTP method. Only requests with +method ``GET`` are passed on to the inner route. All others are rejected with a +``MethodRejection``, which is translated into a ``405 Method Not Allowed`` response +by the default :ref:`RejectionHandler `. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala + :snippet: get-method diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/head.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/head.rst new file mode 100644 index 0000000000..68a810b51c --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/head.rst @@ -0,0 +1,30 @@ +.. _-head-: + +head +==== + +Matches requests with HTTP method ``HEAD``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala + :snippet: head + +Description +----------- + +This directive filters the incoming request by its HTTP method. Only requests with +method ``HEAD`` are passed on to the inner route. All others are rejected with a +``MethodRejection``, which is translated into a ``405 Method Not Allowed`` response +by the default :ref:`RejectionHandler `. + +.. note:: By default, spray-can handles HEAD-requests transparently by dispatching a GET-request to the handler and + stripping of the result body. See the ``spray.can.server.transparent-head-requests`` setting for how to disable + this behavior. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala + :snippet: head-method diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/index.rst new file mode 100644 index 0000000000..e5241a42f2 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/index.rst @@ -0,0 +1,18 @@ +.. _MethodDirectives: + +MethodDirectives +================ + +.. toctree:: + :maxdepth: 1 + + delete + extractMethod + get + head + method + options + overrideMethodWithParameter + patch + post + put diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/method.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/method.rst new file mode 100644 index 0000000000..7e20531c58 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/method.rst @@ -0,0 +1,26 @@ +.. _-method-: + +method +====== + +Matches HTTP requests based on their method. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala + :snippet: method + +Description +----------- + +This directive filters the incoming request by its HTTP method. Only requests with +the specified method are passed on to the inner route. All others are rejected with a +``MethodRejection``, which is translated into a ``405 Method Not Allowed`` response +by the default :ref:`RejectionHandler `. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala + :snippet: method-example diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/options.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/options.rst new file mode 100644 index 0000000000..1bee7f153d --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/options.rst @@ -0,0 +1,26 @@ +.. _-options-: + +options +======= + +Matches requests with HTTP method ``OPTIONS``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala + :snippet: options + +Description +----------- + +This directive filters the incoming request by its HTTP method. Only requests with +method ``OPTIONS`` are passed on to the inner route. All others are rejected with a +``MethodRejection``, which is translated into a ``405 Method Not Allowed`` response +by the default :ref:`RejectionHandler `. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala + :snippet: options-method diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/overrideMethodWithParameter.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/overrideMethodWithParameter.rst new file mode 100644 index 0000000000..1c91b96b49 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/overrideMethodWithParameter.rst @@ -0,0 +1,23 @@ +.. _-overrideMethodWithParameter-: + +overrideMethodWithParameter +=========================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala + :snippet: overrideMethodWithParameter + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala + :snippet: 0overrideMethodWithParameter diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/patch.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/patch.rst new file mode 100644 index 0000000000..ac3e3d21d1 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/patch.rst @@ -0,0 +1,27 @@ +.. _-patch-: + +patch +===== + +Matches requests with HTTP method ``PATCH``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala + :snippet: patch + +Description +----------- + +This directive filters the incoming request by its HTTP method. Only requests with +method ``PATCH`` are passed on to the inner route. All others are rejected with a +``MethodRejection``, which is translated into a ``405 Method Not Allowed`` response +by the default :ref:`RejectionHandler `. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala + :snippet: patch-method diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/post.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/post.rst new file mode 100644 index 0000000000..5e4fca5de5 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/post.rst @@ -0,0 +1,27 @@ +.. _-post-: + +post +==== + +Matches requests with HTTP method ``POST``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala + :snippet: post + +Description +----------- + +This directive filters the incoming request by its HTTP method. Only requests with +method ``POST`` are passed on to the inner route. All others are rejected with a +``MethodRejection``, which is translated into a ``405 Method Not Allowed`` response +by the default :ref:`RejectionHandler `. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala + :snippet: post-method diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/put.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/put.rst new file mode 100644 index 0000000000..4e30f7458c --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/method-directives/put.rst @@ -0,0 +1,26 @@ +.. _-put-: + +put +=== + +Matches requests with HTTP method ``PUT``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MethodDirectives.scala + :snippet: put + +Description +----------- + +This directive filters the incoming request by its HTTP method. Only requests with +method ``PUT`` are passed on to the inner route. All others are rejected with a +``MethodRejection``, which is translated into a ``405 Method Not Allowed`` response +by the default :ref:`RejectionHandler `. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MethodDirectivesExamplesSpec.scala + :snippet: put-method diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/extractClientIP.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/extractClientIP.rst new file mode 100644 index 0000000000..7240a56575 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/extractClientIP.rst @@ -0,0 +1,27 @@ +.. _-extractClientIP-: + +extractClientIP +=============== + +Provides the value of ``X-Forwarded-For``, ``Remote-Address``, or ``X-Real-IP`` headers as an instance of +``HttpIp``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MiscDirectives.scala + :snippet: extractClientIP + +Description +----------- + +spray-can and spray-servlet adds the ``Remote-Address`` header to every request automatically if the respective +setting ``spray.can.server.remote-address-header`` or ``spray.servlet.remote-address-header`` is set to ``on``. +Per default it is set to ``off``. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MiscDirectivesExamplesSpec.scala + :snippet: extractClientIP-example + diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/index.rst new file mode 100644 index 0000000000..ecbd69f162 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/index.rst @@ -0,0 +1,13 @@ +.. _MiscDirectives: + +MiscDirectives +============== + +.. toctree:: + :maxdepth: 1 + + extractClientIP + rejectEmptyResponse + requestEntityEmpty + requestEntityPresent + validate \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/rejectEmptyResponse.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/rejectEmptyResponse.rst new file mode 100644 index 0000000000..1774338769 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/rejectEmptyResponse.rst @@ -0,0 +1,26 @@ +.. _-rejectEmptyResponse-: + +rejectEmptyResponse +=================== + +Replaces a response with no content with an empty rejection. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MiscDirectives.scala + :snippet: rejectEmptyResponse + + +Description +----------- + +The ``rejectEmptyResponse`` directive is mostly used with marshalling ``Option[T]`` instances. The value ``None`` is +usually marshalled to an empty but successful result. In many cases ``None`` should instead be handled as +``404 Not Found`` which is the effect of using ``rejectEmptyResponse``. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MiscDirectivesExamplesSpec.scala + :snippet: rejectEmptyResponse-example diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/requestEntityEmpty.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/requestEntityEmpty.rst new file mode 100644 index 0000000000..f9e1528ec1 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/requestEntityEmpty.rst @@ -0,0 +1,27 @@ +.. _-requestEntityEmpty-: + +requestEntityEmpty +================== + +A filter that checks if the request entity is empty and only then passes processing to the inner route. +Otherwise, the request is rejected. + + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MiscDirectives.scala + :snippet: requestEntityEmpty + + +Description +----------- + +The opposite filter is available as ``requestEntityPresent``. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MiscDirectivesExamplesSpec.scala + :snippet: requestEntityEmptyPresent-example diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/requestEntityPresent.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/requestEntityPresent.rst new file mode 100644 index 0000000000..78ae2b416e --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/requestEntityPresent.rst @@ -0,0 +1,27 @@ +.. _-requestEntityPresent-: + +requestEntityPresent +==================== + +A simple filter that checks if the request entity is present and only then passes processing to the inner route. +Otherwise, the request is rejected. + + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MiscDirectives.scala + :snippet: requestEntityPresent + + +Description +----------- + +The opposite filter is available as ``requestEntityEmpty``. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MiscDirectivesExamplesSpec.scala + :snippet: requestEntityEmptyPresent-example diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/validate.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/validate.rst new file mode 100644 index 0000000000..66aecd3e28 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/misc-directives/validate.rst @@ -0,0 +1,20 @@ +.. _-validate-: + +validate +======== + +Checks an arbitrary condition and passes control to the inner route if it returns ``true``. Otherwise, rejects the +request with a ``ValidationRejection`` containing the given error message. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/MiscDirectives.scala + :snippet: validate + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/MiscDirectivesExamplesSpec.scala + :snippet: validate-example diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/index.rst new file mode 100644 index 0000000000..f2009af52b --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/index.rst @@ -0,0 +1,43 @@ +.. _ParameterDirectives: + +ParameterDirectives +=================== + +.. toctree:: + :maxdepth: 1 + + parameter + parameterMap + parameterMultiMap + parameters + parameterSeq + +.. _which-parameter-directive: + +When to use which parameter directive? +-------------------------------------- + +Usually, you want to use the high-level :ref:`-parameters-` directive. When you need +more low-level access you can use the table below to decide which directive +to use which shows properties of different parameter directives. + +========================== ====== ======== ===== +directive level ordering multi +========================== ====== ======== ===== +:ref:`-parameter-` high no no +:ref:`-parameters-` high no no +:ref:`-parameterMap-` low no no +:ref:`-parameterMultiMap-` low no yes +:ref:`-parameterSeq-` low yes yes +========================== ====== ======== ===== + +level + high-level parameter directives extract subset of all parameters by name and allow conversions + and automatically report errors if expectations are not met, low-level directives give you + all parameters at once, leaving all further processing to you + +ordering + original ordering from request URL is preserved + +multi + multiple values per parameter name are possible diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameter.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameter.rst new file mode 100644 index 0000000000..26e8b5f9f8 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameter.rst @@ -0,0 +1,23 @@ +.. _-parameter-: + +parameter +========= + +An alias for :ref:`-parameters-`. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/ParameterDirectives.scala + :snippet: parameter + +Description +----------- + +See :ref:`-parameters-` + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala + :snippet: example-1 diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameterMap.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameterMap.rst new file mode 100644 index 0000000000..89984f0beb --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameterMap.rst @@ -0,0 +1,28 @@ +.. _-parameterMap-: + +parameterMap +============ + +Extracts all parameters at once as a ``Map[String, String]`` mapping parameter names to +parameter values. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/ParameterDirectives.scala + :snippet: parameterMap + +Description +----------- + +If a query contains a parameter value several times, the map will contain the last one. + +See :ref:`which-parameter-directive` for other +choices. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala + :snippet: parameterMap diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameterMultiMap.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameterMultiMap.rst new file mode 100644 index 0000000000..5a1cab1b05 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameterMultiMap.rst @@ -0,0 +1,27 @@ +.. _-parameterMultiMap-: + +parameterMultiMap +================= + +Extracts all parameters at once as a multi-map of type ``Map[String, List[String]`` mapping +a parameter name to a list of all its values. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/ParameterDirectives.scala + :snippet: parameterMultiMap + +Description +----------- + +This directive can be used if parameters can occur several times. The order of values is +not specified. + +See :ref:`which-parameter-directive` for other choices. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala + :snippet: parameterMultiMap diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameterSeq.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameterSeq.rst new file mode 100644 index 0000000000..d2f5e349ad --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameterSeq.rst @@ -0,0 +1,26 @@ +.. _-parameterSeq-: + +parameterSeq +============ + +Extracts all parameters at once in the original order as (name, value) tuples of type ``(String, String)``. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/ParameterDirectives.scala + :snippet: parameterSeq + +Description +----------- + +This directive can be used if the exact order of parameters is important or if parameters can +occur several times. + +See :ref:`which-parameter-directive` for other choices. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala + :snippet: parameterSeq diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameters.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameters.rst new file mode 100644 index 0000000000..4d875587e2 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/parameter-directives/parameters.rst @@ -0,0 +1,82 @@ +.. _-parameters-: + +parameters +========== + +The parameters directive filters on the existence of several query parameters and extract their values. + +Signature +--------- + +:: + + def parameters(param: ): Directive1[T] + def parameters(params: *): Directive[T_0 :: ... T_i ... :: HNil] + def parameters(params: :: ... ... :: HNil): Directive[T_0 :: ... T_i ... :: HNil] + +The signature shown is simplified and written in pseudo-syntax, the real signature uses magnets. [1]_ The type +```` doesn't really exist but consists of the syntactic variants as shown in the description and the examples. + +.. [1] See `The Magnet Pattern`_ for an explanation of magnet-based overloading. +.. _`The Magnet Pattern`: /blog/2012-12-13-the-magnet-pattern/ + +Description +----------- +Query parameters can be either extracted as a String or can be converted to another type. The parameter name +can be supplied either as a String or as a Symbol. Parameter extraction can be modified to mark a query parameter +as required or optional or to filter requests where a parameter has a certain value: + +``"color"`` + extract value of parameter "color" as ``String`` +``"color".?`` + extract optional value of parameter "color" as ``Option[String]`` +``"color" ? "red"`` + extract optional value of parameter "color" as ``String`` with default value ``"red"`` +``"color" ! "blue"`` + require value of parameter "color" to be ``"blue"`` and extract nothing +``"amount".as[Int]`` + extract value of parameter "amount" as ``Int``, you need a matching ``Deserializer`` in scope for that to work + (see also :ref:`http-unmarshalling-scala`) +``"amount".as(deserializer)`` + extract value of parameter "amount" with an explicit ``Deserializer`` + +You can use :ref:`Case Class Extraction` to group several extracted values together into a case-class +instance. + +Requests missing a required parameter or parameter value will be rejected with an appropriate rejection. + +There's also a singular version, :ref:`-parameter-`. Form fields can be handled in a similar way, see ``formFields``. If +you want unified handling for both query parameters and form fields, see ``anyParams``. + +Examples +-------- + +Required parameter +++++++++++++++++++ + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala + :snippet: required-1 + +Optional parameter +++++++++++++++++++ + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala + :snippet: optional + +Optional parameter with default value ++++++++++++++++++++++++++++++++++++++ + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala + :snippet: optional-with-default + +Parameter with required value ++++++++++++++++++++++++++++++ + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala + :snippet: required-value + +Deserialized parameter +++++++++++++++++++++++ + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/ParameterDirectivesExamplesSpec.scala + :snippet: mapped-value diff --git a/akka-docs-dev/rst/scala/http/directives/path-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/path-directives/index.rst similarity index 78% rename from akka-docs-dev/rst/scala/http/directives/path-directives/index.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/path-directives/index.rst index 443f710c96..1a126e783d 100644 --- a/akka-docs-dev/rst/scala/http/directives/path-directives/index.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/path-directives/index.rst @@ -16,5 +16,6 @@ PathDirectives pathSuffixTest rawPathPrefix rawPathPrefixTest - + redirectToNoTrailingSlashIfPresent + redirectToTrailingSlashIfMissing ../../path-matchers diff --git a/akka-docs-dev/rst/scala/http/directives/path-directives/path.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/path-directives/path.rst similarity index 88% rename from akka-docs-dev/rst/scala/http/directives/path-directives/path.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/directives/path-directives/path.rst index 98e3b505ca..a4b4273198 100644 --- a/akka-docs-dev/rst/scala/http/directives/path-directives/path.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/path-directives/path.rst @@ -10,7 +10,7 @@ one or more values (depending on the type of the argument). Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/PathDirectives.scala :snippet: path @@ -37,5 +37,5 @@ If the match fails the request is rejected with an :ref:`empty rejection set `_ for an explanation of magnet-based overloading. + + +Description +----------- + +``complete`` uses the given arguments to construct a ``Route`` which simply calls ``complete`` on the ``RequestContext`` +with the respective ``HttpResponse`` instance. +Completing the request will send the response "back up" the route structure where all the logic runs that wrapping +directives have potentially chained into the :ref:`RouteResult` future transformation chain. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/RouteDirectivesExamplesSpec.scala + :snippet: complete-examples \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/failWith.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/failWith.rst new file mode 100644 index 0000000000..80e7923ac2 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/failWith.rst @@ -0,0 +1,38 @@ +.. _-failWith-: + +failWith +======== + +Bubbles up the given error through the route structure where it is dealt with by the closest ``handleExceptions`` +directive and its ``ExceptionHandler``. + + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/RouteDirectives.scala + :snippet: failWith + + +Description +----------- + +``failWith`` explicitly raises an exception that gets bubbled up through the route structure to be picked up by the +nearest ``handleExceptions`` directive. Using ``failWith`` rather than simply throwing an exception enables the route +structure's :ref:`Exception Handling` mechanism to deal with the exception even if the current route is executed +asynchronously on another thread (e.g. in a ``Future`` or separate actor). + +If no ``handleExceptions`` is present above the respective location in the +route structure the top-level routing logic will handle the exception and translate it into a corresponding +``HttpResponse`` using the in-scope ``ExceptionHandler`` (see also the :ref:`Exception Handling` chapter). + +There is one notable special case: If the given exception is a ``RejectionError`` exception it is *not* bubbled up, +but rather the wrapped exception is unpacked and "executed". This allows the "tunneling" of a rejection via an +exception. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/RouteDirectivesExamplesSpec.scala + :snippet: failwith-examples \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/index.rst new file mode 100644 index 0000000000..9f72611fe5 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/index.rst @@ -0,0 +1,21 @@ +.. _RouteDirectives: + +RouteDirectives +=============== + +The ``RouteDirectives`` have a special role in spray's routing DSL. Contrary to all other directives (except most +:ref:`FileAndResourceDirectives`) they do not produce instances of type ``Directive[L <: HList]`` but rather "plain" +routes of type ``Route``. +The reason is that the ``RouteDirectives`` are not meant for wrapping an inner route (like most other directives, as +intermediate-level elements of a route structure, do) but rather form the leaves of the actual route structure **leaves**. + +So in most cases the inner-most element of a route structure branch is one of the ``RouteDirectives`` (or +:ref:`FileAndResourceDirectives`): + +.. toctree:: + :maxdepth: 1 + + complete + failWith + redirect + reject \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/redirect.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/redirect.rst new file mode 100644 index 0000000000..af8e475c98 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/redirect.rst @@ -0,0 +1,30 @@ +.. _-redirect-: + +redirect +======== + +Completes the request with a redirection response to a given targer URI and of a given redirection type (status code). + + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/RouteDirectives.scala + :snippet: redirect + + +Description +----------- + +``redirect`` is a convenience helper for completing the request with a redirection response. +It is equivalent to this snippet relying on the ``complete`` directive: + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/RouteDirectives.scala + :snippet: red-impl + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/RouteDirectivesExamplesSpec.scala + :snippet: redirect-examples \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/reject.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/reject.rst new file mode 100644 index 0000000000..ba1150c1f4 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/route-directives/reject.rst @@ -0,0 +1,33 @@ +.. _-reject-: + +reject +====== + +Explicitly rejects the request optionally using the given rejection(s). + + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/RouteDirectives.scala + :snippet: reject + + +Description +----------- + +``reject`` uses the given rejection instances (which might be the empty ``Seq``) to construct a ``Route`` which simply +calls ``requestContext.reject``. See the chapter on :ref:`Rejections` for more information on what this means. + +After the request has been rejected at the respective point it will continue to flow through the routing structure in +the search for a route that is able to complete it. + +The explicit ``reject`` directive is used mostly when building :ref:`Custom Directives`, e.g. inside of a ``flatMap`` +modifier for "filtering out" certain cases. + + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/RouteDirectivesExamplesSpec.scala + :snippet: reject-examples \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/scheme-directives/extractScheme.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/scheme-directives/extractScheme.rst new file mode 100644 index 0000000000..3258174a5f --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/scheme-directives/extractScheme.rst @@ -0,0 +1,26 @@ +.. _-extractScheme-: + +extractScheme +============= + +Extracts the value of the request Uri scheme. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/SchemeDirectives.scala + :snippet: extractScheme + +Description +----------- + +The ``extractScheme`` directive can be used to determine the Uri scheme (i.e. "http", "https", etc.) +for an incoming request. + +For rejecting a request if it doesn't match a specified scheme name, see the :ref:`-scheme-` directive. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/SchemeDirectivesExamplesSpec.scala + :snippet: example-1 diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/scheme-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/scheme-directives/index.rst new file mode 100644 index 0000000000..b9328f3e4b --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/scheme-directives/index.rst @@ -0,0 +1,13 @@ +.. _SchemeDirectives: + +SchemeDirectives +================ + +Scheme directives can be used to extract the Uri scheme (i.e. "http", "https", etc.) +from requests or to reject any request that does not match a specified scheme name. + +.. toctree:: + :maxdepth: 1 + + extractScheme + scheme diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/scheme-directives/scheme.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/scheme-directives/scheme.rst new file mode 100644 index 0000000000..62ce57693c --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/scheme-directives/scheme.rst @@ -0,0 +1,31 @@ +.. _-scheme-: + +scheme +====== + +Rejects a request if its Uri scheme does not match a given one. + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/SchemeDirectives.scala + :snippet: scheme + +Description +----------- + +The ``scheme`` directive can be used to match requests by their Uri scheme, only passing +through requests that match the specified scheme and rejecting all others. + +A typical use case for the ``scheme`` directive would be to reject requests coming in over +http instead of https, or to redirect such requests to the matching https URI with a +``MovedPermanently``. + +For simply extracting the scheme name, see the :ref:`-extractScheme-` directive. + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/SchemeDirectivesExamplesSpec.scala + :snippet: example-2 + diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasic.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasic.rst new file mode 100644 index 0000000000..927ea6aca4 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasic.rst @@ -0,0 +1,23 @@ +.. _-authenticateBasic-: + +authenticateBasic +================= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala + :snippet: authenticateBasic + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/SecurityDirectivesExamplesSpec.scala + :snippet: 0authenticateBasic diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasicAsync.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasicAsync.rst new file mode 100644 index 0000000000..7548ec8758 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasicAsync.rst @@ -0,0 +1,23 @@ +.. _-authenticateBasicAsync-: + +authenticateBasicAsync +======================= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala + :snippet: authenticateBasicAsync + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/SecurityDirectivesExamplesSpec.scala + :snippet: 0authenticateBasicAsync diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasicPF.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasicPF.rst new file mode 100644 index 0000000000..ca353b70d9 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasicPF.rst @@ -0,0 +1,23 @@ +.. _-authenticateBasicPF-: + +authenticateBasicPF +=================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala + :snippet: authenticateBasicPF + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/SecurityDirectivesExamplesSpec.scala + :snippet: 0authenticateBasicPF diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasicPFAsync.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasicPFAsync.rst new file mode 100644 index 0000000000..8d1eab0a0d --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateBasicPFAsync.rst @@ -0,0 +1,23 @@ +.. _-authenticateBasicPFAsync-: + +authenticateBasicPFAsync +========================= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala + :snippet: authenticateBasicPFAsync + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/SecurityDirectivesExamplesSpec.scala + :snippet: 0authenticateBasicPFAsync diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateOrRejectWithChallenge.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateOrRejectWithChallenge.rst new file mode 100644 index 0000000000..890998c024 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authenticateOrRejectWithChallenge.rst @@ -0,0 +1,23 @@ +.. _-authenticateOrRejectWithChallenge-: + +authenticateOrRejectWithChallenge +================================= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala + :snippet: authenticateOrRejectWithChallenge + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/SecurityDirectivesExamplesSpec.scala + :snippet: 0authenticateOrRejectWithChallenge diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authorize.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authorize.rst new file mode 100644 index 0000000000..4ac5890969 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/authorize.rst @@ -0,0 +1,23 @@ +.. _-authorize-: + +authorize +========= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala + :snippet: authorize + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/SecurityDirectivesExamplesSpec.scala + :snippet: 0authorize diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/extractCredentials.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/extractCredentials.rst new file mode 100644 index 0000000000..a073fbf863 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/extractCredentials.rst @@ -0,0 +1,23 @@ +.. _-extractCredentials-: + +extractCredentials +================== + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/SecurityDirectives.scala + :snippet: extractCredentials + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/SecurityDirectivesExamplesSpec.scala + :snippet: 0extractCredentials 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 new file mode 100644 index 0000000000..8342283170 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/security-directives/index.rst @@ -0,0 +1,39 @@ +.. _SecurityDirectives: + +SecurityDirectives +================== + +.. toctree:: + :maxdepth: 1 + + authenticateBasic + authenticateBasicAsync + authenticateBasicPF + authenticateBasicPFAsync + authenticateOrRejectWithChallenge + authorize + extractCredentials + + +Authentication vs. Authorization +-------------------------------- + +*Authentication* is the process of establishing a known identity for the user, whereby 'identity' is defined in the +context of the application. This may be done with a username/password combination, a cookie, a pre-defined IP or some +other mechanism. After authentication the system believes that it knows who the user is. + +*Authorization* is the process of determining, whether a given user is allowed access to a given resource or not. In +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 +*members*". + +Authentication and authorization may happen at the same time, e.g. when everyone who can properly be authenticated is +also allowed access (which is often a very simple and somewhat implicit authorization logic). In other cases the +system might have one mechanism for authentication (e.g. establishing user identity via an LDAP lookup) and another one +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 diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebsocketMessages.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebsocketMessages.rst new file mode 100644 index 0000000000..291fb0415e --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebsocketMessages.rst @@ -0,0 +1,23 @@ +.. _-handleWebsocketMessages-: + +handleWebsocketMessages +======================= + +... + +Signature +--------- + +.. includecode2:: /../../akka-http-scala/src/main/scala/akka/http/scaladsl/server/directives/WebsocketDirectives.scala + :snippet: handleWebsocketMessages + +Description +----------- + +... + +Example +------- + +... includecode2:: ../../../../code/docs/http/scaladsl/server/directives/WebsocketDirectivesExamplesSpec.scala + :snippet: 0handleWebsocketMessages diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/directives/websocket-directives/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/directives/websocket-directives/index.rst new file mode 100644 index 0000000000..c4c65ec684 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/directives/websocket-directives/index.rst @@ -0,0 +1,9 @@ +.. _WebsocketDirectives: + +WebsocketDirectives +=================== + +.. toctree:: + :maxdepth: 1 + + handleWebsocketMessages diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/exception-handling.rst b/akka-docs-dev/rst/scala/http/routing-dsl/exception-handling.rst new file mode 100644 index 0000000000..6aefc1ffa3 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/exception-handling.rst @@ -0,0 +1,45 @@ +.. _Exception Handling: + +Exception Handling +================== + +Exceptions thrown during route execution bubble up through the route structure to the next enclosing +:ref:`-handleExceptions-` directive or the top of your route structure. + +Similarly to the way that :ref:`Rejections` are handled the :ref:`-handleExceptions-` directive delegates the actual job +of converting an exception to its argument, an ExceptionHandler__, which is defined like this:: + + trait ExceptionHandler extends PartialFunction[Throwable, Route] + +__ @github@/akka-http-scala/src/main/scala/akka/http/scaladsl/server/ExceptionHandler.scala + +Since an ``ExceptionHandler`` is a partial function it can choose, which exceptions it would like to handle and +which not. Unhandled exceptions will simply continue to bubble up in the route structure. +At the root of the route tree any still unhandled exception will be dealt with by the top-level handler which always +handles *all* exceptions. + +``Route.seal`` internally wraps its argument route with the :ref:`-handleExceptions-` directive in order to "catch" and +handle any exception. + +So, if you'd like to customize the way certain exceptions are handled you need to write a custom ``ExceptionHandler``. +Once you have defined your custom ``ExceptionHandler`` you have two options for "activating" it: + +1. Bring it into implicit scope at the top-level. +2. Supply it as argument to the :ref:`-handleExceptions-` directive. + +In the first case your handler will be "sealed" (which means that it will receive the default handler as a fallback for +all cases your handler doesn't handle itself) and used for all exceptions that are not handled within the route +structure itself. + +The second case allows you to restrict the applicability of your handler to certain branches of your route structure. + +Here is an example for wiring up a custom handler via :ref:`-handleExceptions-`: + +.. includecode2:: ../../code/docs/http/scaladsl/server/ExceptionHandlerExamplesSpec.scala + :snippet: explicit-handler-example + + +And this is how to do it implicitly: + +.. includecode2:: ../../code/docs/http/scaladsl/server/ExceptionHandlerExamplesSpec.scala + :snippet: implicit-handler-example \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/https-support.rst b/akka-docs-dev/rst/scala/http/routing-dsl/https-support.rst new file mode 100644 index 0000000000..ad9883d95b --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/https-support.rst @@ -0,0 +1,4 @@ +Server-Side HTTPS Support +========================= + +TODO \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/index.rst b/akka-docs-dev/rst/scala/http/routing-dsl/index.rst new file mode 100644 index 0000000000..72801b7f78 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/index.rst @@ -0,0 +1,47 @@ +.. _http-high-level-server-side-api: + +High-level Server-Side API +========================== + +In addition to the :ref:`http-low-level-server-side-api` Akka HTTP provides a very flexible "Routing DSL" for elegantly +defining RESTful web services. It picks up where the low-level API leaves off and offers much of the higher-level +functionality of typical web servers or frameworks, like deconstruction of URIs, content negotiation or +static content serving. + +.. toctree:: + :maxdepth: 1 + + overview + routes + directives/index + rejections + exception-handling + path-matchers + case-class-extraction + testkit + https-support + websocket-support + + +Minimal Example +--------------- + +This is a complete, very basic Akka HTTP application relying on the Routing DSL: + +.. includecode2:: ../../code/docs/http/scaladsl/HttpServerExampleSpec.scala + :snippet: minimal-routing-example + +It starts an HTTP Server on localhost and replies to GET requests to ``/hello`` with a simple response. + + +.. _Long Example: + +Longer Example +-------------- + +The following is an Akka HTTP route definition that tries to show off a few features. The resulting service does +not really do anything useful but its definition should give you a feel for what an actual API definition with +the :ref:`http-high-level-server-side-api` will look like: + +.. includecode2:: ../../code/docs/http/scaladsl/HttpServerExampleSpec.scala + :snippet: long-routing-example \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/overview.rst b/akka-docs-dev/rst/scala/http/routing-dsl/overview.rst new file mode 100644 index 0000000000..4ddc54d999 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/overview.rst @@ -0,0 +1,41 @@ +Routing DSL Overview +==================== + +The Akka HTTP :ref:`http-low-level-server-side-api` provides a ``Flow``- or ``Function``-level interface that allows +an application to respond to incoming HTTP requests by simply mapping requests to responses: + +.. includecode2:: ../../code/docs/http/scaladsl/HttpServerExampleSpec.scala + :snippet: low-level-server-example + +While it'd be perfectly possible to define a complete REST API service purely by pattern-matching against the incoming +``HttpRequest`` (maybe with the help of a few extractors in the way of `Unfiltered`_) this approach becomes somewhat +unwieldy for larger services due to the amount of syntax "ceremony" required. Also, it doesn't help in keeping your +service definition as DRY_ as you might like. + +As an alternative Akka HTTP provides a flexible DSL for expressing your service behavior as a structure of +composable elements (called :ref:`Directives`) in a concise and readable way. Directives are assembled into a so called +*route structure* which, at its top-level, forms a handler ``Flow`` (or, alternatively, an async handler function) that +can be directly supplied to a ``bind`` call. + +For example, the service definition from above, written using the routing DSL, would look like this: + +.. includecode2:: ../../code/docs/http/scaladsl/HttpServerExampleSpec.scala + :snippet: high-level-server-example + +The core of the Routing DSL becomes available with a single import:: + + import akka.http.scaladsl.server.Directives._ + +This example also relies on the pre-defined support for Scala XML with:: + + import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._ + +The very short example shown here is certainly not the best for illustrating the savings in "ceremony" and improvements +in conciseness and readability that the Routing DSL promises. The :ref:`Long Example` might do a better job in this +regard. + +For learning how to work with the Routing DSL you should first understand the concept of :ref:`Routes`. + + +.. _Unfiltered: http://unfiltered.databinder.net/ +.. _DRY: http://en.wikipedia.org/wiki/Don%27t_repeat_yourself \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/path-matchers.rst b/akka-docs-dev/rst/scala/http/routing-dsl/path-matchers.rst similarity index 81% rename from akka-docs-dev/rst/scala/http/path-matchers.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/path-matchers.rst index 7ac98c2cb2..3aae7cc97e 100644 --- a/akka-docs-dev/rst/scala/http/path-matchers.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/path-matchers.rst @@ -11,8 +11,8 @@ Overview When a request (or rather the respective ``RequestContext`` instance) enters the route structure it has an "unmatched path" that is identical to the ``request.uri.path``. As it descends the routing tree and passes through one -or more :ref:`-pathPrefix-`/:ref:`-path-` directives the "unmatched path" progressively gets "eaten into" from the left -until, in most cases, it eventually has been consumed completely. +or more :ref:`-pathPrefix-` or :ref:`-path-` directives the "unmatched path" progressively gets "eaten into" from the +left until, in most cases, it eventually has been consumed completely. What exactly gets matched and consumed as well as extracted from the unmatched path in each directive is defined with the patch matching DSL, which is built around these types:: @@ -22,13 +22,13 @@ the patch matching DSL, which is built around these types:: type PathMatcher1[T] = PathMatcher[Tuple1[T]] The number and types of the values extracted by a ``PathMatcher`` instance is represented by the ``L`` type -parameter which needs to be one of Scala's TupleN types or Unit (which is designated by the ``Tuple`` context bound). +parameter which needs to be one of Scala's TupleN types or ``Unit`` (which is designated by the ``Tuple`` context bound). The convenience alias ``PathMatcher0`` can be used for all matchers which don't extract anything while ``PathMatcher1[T]`` defines a matcher which only extracts a single value of type ``T``. Here is an example of a more complex ``PathMatcher`` expression: -.. includecode2:: ../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala +.. includecode2:: ../../code/docs/http/scaladsl/server/directives/PathDirectivesExamplesSpec.scala :snippet: path-matcher This will match paths like ``foo/bar/X42/edit`` or ``foo/bar/X/create``. @@ -44,78 +44,78 @@ Basic PathMatchers A complex ``PathMatcher`` can be constructed by combining or modifying more basic ones. Here are the basic matchers that Akka HTTP already provides for you: -``String`` +String You can use a ``String`` instance as a ``PathMatcher0``. Strings simply match themselves and extract no value. Note that strings are interpreted as the decoded representation of the path, so if they include a '/' character this character will match "%2F" in the encoded raw URI! -``Regex`` +Regex You can use a ``Regex`` instance as a ``PathMatcher1[String]``, which matches whatever the regex matches and extracts one ``String`` value. A ``PathMatcher`` created from a regular expression extracts either the complete match (if the regex doesn't contain a capture group) or the capture group (if the regex contains exactly one capture group). If the regex contains more than one capture group an ``IllegalArgumentException`` will be thrown. -``Map[String, T]`` +Map[String, T] You can use a ``Map[String, T]`` instance as a ``PathMatcher1[T]``, which matches any of the keys and extracts the respective map value for it. -``Slash: PathMatcher0`` +Slash: PathMatcher0 Matches exactly one path-separating slash (``/``) character and extracts nothing. -``Segment: PathMatcher1[String]`` +Segment: PathMatcher1[String] Matches if the unmatched path starts with a path segment (i.e. not a slash). If so the path segment is extracted as a ``String`` instance. -``PathEnd: PathMatcher0`` +PathEnd: PathMatcher0 Matches the very end of the path, similar to ``$`` in regular expressions and extracts nothing. -``Rest: PathMatcher1[String]`` +Rest: PathMatcher1[String] Matches and extracts the complete remaining unmatched part of the request's URI path as an (encoded!) String. If you need access to the remaining *decoded* elements of the path use ``RestPath`` instead. -``RestPath: PathMatcher1[Path]`` +RestPath: PathMatcher1[Path] Matches and extracts the complete remaining, unmatched part of the request's URI path. -``IntNumber: PathMatcher1[Int]`` - Efficiently matches a number of decimal digits and extracts their (non-negative) ``Int`` value. The matcher will not - match zero digits or a sequence of digits that would represent an ``Int`` value larger than ``Int.MaxValue``. +IntNumber: PathMatcher1[Int] + Efficiently matches a number of decimal digits (unsigned) and extracts their (non-negative) ``Int`` value. The matcher + will not match zero digits or a sequence of digits that would represent an ``Int`` value larger than ``Int.MaxValue``. -``LongNumber: PathMatcher1[Long]`` - Efficiently matches a number of decimal digits and extracts their (non-negative) ``Long`` value. The matcher will not - match zero digits or a sequence of digits that would represent an ``Long`` value larger than ``Long.MaxValue``. +LongNumber: PathMatcher1[Long] + Efficiently matches a number of decimal digits (unsigned) and extracts their (non-negative) ``Long`` value. The matcher + will not match zero digits or a sequence of digits that would represent an ``Long`` value larger than ``Long.MaxValue``. -``HexIntNumber: PathMatcher1[Int]`` +HexIntNumber: PathMatcher1[Int] Efficiently matches a number of hex digits and extracts their (non-negative) ``Int`` value. The matcher will not match zero digits or a sequence of digits that would represent an ``Int`` value larger than ``Int.MaxValue``. -``HexLongNumber: PathMatcher1[Long]`` +HexLongNumber: PathMatcher1[Long] Efficiently matches a number of hex digits and extracts their (non-negative) ``Long`` value. The matcher will not match zero digits or a sequence of digits that would represent an ``Long`` value larger than ``Long.MaxValue``. -``DoubleNumber: PathMatcher1[Double]`` +DoubleNumber: PathMatcher1[Double] Matches and extracts a ``Double`` value. The matched string representation is the pure decimal, optionally signed form of a double value, i.e. without exponent. -``JavaUUID: PathMatcher1[UUID]`` +JavaUUID: PathMatcher1[UUID] Matches and extracts a ``java.util.UUID`` instance. -``Neutral: PathMatcher0`` +Neutral: PathMatcher0 A matcher that always matches, doesn't consume anything and extracts nothing. Serves mainly as a neutral element in ``PathMatcher`` composition. -``Segments: PathMatcher1[List[String]]`` +Segments: PathMatcher1[List[String]] Matches all remaining segments as a list of strings. Note that this can also be "no segments" resulting in the empty list. If the path has a trailing slash this slash will *not* be matched, i.e. remain unmatched and to be consumed by potentially nested directives. -``separateOnSlashes(string: String): PathMatcher0`` +separateOnSlashes(string: String): PathMatcher0 Converts a path string containing slashes into a ``PathMatcher0`` that interprets slashes as path segment separators. This means that a matcher matching "%2F" cannot be constructed with this helper. -``provide[L: Tuple](extractions: L): PathMatcher[L]`` +provide[L: Tuple](extractions: L): PathMatcher[L] Always matches, consumes nothing and extracts the given ``TupleX`` of values. -``PathMatcher[L: Tuple](prefix: Path, extractions: L): PathMatcher[L]`` +PathMatcher[L: Tuple](prefix: Path, extractions: L): PathMatcher[L] Matches and consumes the given path prefix and extracts the given list of extractions. If the given prefix is empty the returned matcher matches always and consumes nothing. @@ -145,17 +145,15 @@ Modifiers Path matcher instances can be transformed with these modifier methods: -``/`` +/ The slash operator cannot only be used as combinator for combining two matcher instances, it can also be used as a postfix call. ``matcher /`` is identical to ``matcher ~ Slash`` but shorter and easier to read. -``?`` +? By postfixing a matcher with ``?`` you can turn any ``PathMatcher`` into one that always matches, optionally consumes and potentially extracts an ``Option`` of the underlying matchers extraction. The result type depends on the type of the underlying matcher: - .. rst-class:: table table-striped - =========================== ============================= If a ``matcher`` is of type then ``matcher.?`` is of type =========================== ============================= @@ -165,13 +163,11 @@ Path matcher instances can be transformed with these modifier methods: =========================== ============================= -``repeat(separator: PathMatcher0 = PathMatchers.Neutral)`` +repeat(separator: PathMatcher0 = PathMatchers.Neutral) By postfixing a matcher with ``repeat(separator)`` you can turn any ``PathMatcher`` into one that always matches, consumes zero or more times (with the given separator) and potentially extracts a ``List`` of the underlying matcher's extractions. The result type depends on the type of the underlying matcher: - .. rst-class:: table table-striped - =========================== ======================================= If a ``matcher`` is of type then ``matcher.repeat(...)`` is of type =========================== ======================================= @@ -186,7 +182,7 @@ Path matcher instances can be transformed with these modifier methods: does *not* match and vice versa. -``transform`` / ``(h)flatMap`` / ``(h)map`` +transform / (h)flatMap / (h)map These modifiers allow you to append your own "post-application" logic to another matcher in order to form a custom one. You can map over the extraction(s), turn mismatches into matches or vice-versa or do anything else with the results of the underlying matcher. Take a look at the method signatures and implementations for more guidance as to @@ -196,5 +192,5 @@ Path matcher instances can be transformed with these modifier methods: Examples -------- -.. includecode2:: ../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala +.. includecode2:: ../../code/docs/http/scaladsl/server/directives/PathDirectivesExamplesSpec.scala :snippet: path-dsl \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/rejections.rst b/akka-docs-dev/rst/scala/http/routing-dsl/rejections.rst new file mode 100644 index 0000000000..e0be338634 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/rejections.rst @@ -0,0 +1,138 @@ +.. _Rejections: + +Rejections +========== + +In the chapter about constructing :ref:`Routes` the ``~`` operator was introduced, which connects two routes in a way +that allows a second route to get a go at a request if the first route "rejected" it. The concept of "rejections" is +used by Akka HTTP for maintaining a more functional overall architecture and in order to be able to properly +handle all kinds of error scenarios. + +When a filtering directive, like the :ref:`-get-` directive, cannot let the request pass through to its inner route because +the filter condition is not satisfied (e.g. because the incoming request is not a GET request) the directive doesn't +immediately complete the request with an error response. Doing so would make it impossible for other routes chained in +after the failing filter to get a chance to handle the request. +Rather, failing filters "reject" the request in the same way as by explicitly calling ``requestContext.reject(...)``. + +After having been rejected by a route the request will continue to flow through the routing structure and possibly find +another route that can complete it. If there are more rejections all of them will be picked up and collected. + +If the request cannot be completed by (a branch of) the route structure an enclosing :ref:`-handleRejections-` directive +can be used to convert a set of rejections into an ``HttpResponse`` (which, in most cases, will be an error response). +``Route.seal`` internally wraps its argument route with the :ref:`-handleRejections-` directive in order to "catch" +and handle any rejection. + + +Predefined Rejections +--------------------- + +A rejection encapsulates a specific reason why a route was not able to handle a request. It is modeled as an object of +type ``Rejection``. Akka HTTP comes with a set of `predefined rejections`__, which are used by the many +:ref:`predefined directives `. + +Rejections are gathered up over the course of a Route evaluation and finally converted to ``HttpResponse`` replies by +the :ref:`-handleRejections-` directive if there was no way for the request to be completed. + +__ @github@/akka-http-scala/src/main/scala/akka/http/scaladsl/server/Rejection.scala + + +.. _The RejectionHandler: + +The RejectionHandler +-------------------- + +The :ref:`-handleRejections-` directive delegates the actual job of converting a list of rejections to its argument, a +RejectionHandler__, which is defined like this:: + + trait RejectionHandler extends (immutable.Seq[Rejection] ⇒ Option[Route]) + +__ @github@/akka-http-scala/src/main/scala/akka/http/scaladsl/server/RejectionHandler.scala + +Since a ``RejectionHandler`` returns an ``Option[Route]`` it can choose whether it would like to handle the current set +of rejections or not. If it returns ``None`` the rejections will simply continue to flow through the route structure. + +The default ``RejectionHandler`` applied by the top-level glue code that turns a ``Route`` into a +``Flow`` or async handler function for the :ref:`low-level API ` (via +``Route.handlerFlow`` or ``Route.asyncHandler``) will handle *all* rejections that reach it. + + +Rejection Cancellation +---------------------- + +As you can see from its definition above the ``RejectionHandler`` doesn't handle single rejections but a whole list of +them. This is because some route structure produce several "reasons" why a request could not be handled. + +Take this route structure for example: + +.. includecode2:: ../../code/docs/http/scaladsl/server/RejectionHandlerExamplesSpec.scala + :snippet: example-1 + +For uncompressed POST requests this route structure would initially yield two rejections: + +- a ``MethodRejection`` produced by the :ref:`-get-` directive (which rejected because the request is not a GET request) +- an ``UnsupportedRequestEncodingRejection`` produced by the :ref:`-decodeRequestWith-` directive (which only accepts + gzip-compressed requests here) + +In reality the route even generates one more rejection, a ``TransformationRejection`` produced by the :ref:`-post-` +directive. It "cancels" all other potentially existing *MethodRejections*, since they are invalid after the +:ref:`-post-` directive allowed the request to pass (after all, the route structure *can* deal with POST requests). +These types of rejection cancellations are resolved *before* a ``RejectionHandler`` sees the rejection list. +So, for the example above the ``RejectionHandler`` will be presented with only a single-element rejection list, +containing nothing but the ``UnsupportedRequestEncodingRejection``. + + +.. _Empty Rejections: + +Empty Rejections +---------------- + +Since rejections are passed around in a list (or rather immutable ``Seq``) you might ask yourself what the semantics of +an empty rejection list are. In fact, empty rejection lists have well defined semantics. They signal that a request was +not handled because the respective resource could not be found. Akka HTTP reserves the special status of "empty +rejection" to this most common failure a service is likely to produce. + +So, for example, if the :ref:`-path-` directive rejects a request it does so with an empty rejection list. The +:ref:`-host-` directive behaves in the same way. + + +Customizing Rejection Handling +------------------------------ + +If you'd like to customize the way certain rejections are handled you'll have to write a custom +:ref:`RejectionHandler `. Here is an example: + +.. includecode2:: ../../code/docs/http/scaladsl/server/RejectionHandlerExamplesSpec.scala + :snippet: custom-handler-example + +The easiest way to construct a ``RejectionHandler`` is via the ``RejectionHandler.Builder`` that Akka HTTP provides. +After having created a new ``Builder`` instance with ``RejectionHandler.newBuilder()`` +you can attach handling logic for certain types of rejections through three helper methods: + +handle + Handles certain rejections with the given partial function. The partial function simply produces a ``Route`` which is + run when the rejection is "caught". This makes the full power of the Routing DSL available for defining rejection + handlers and even allows for recursing back into the main route structure if required. + +handleAll[T <: Rejection] + Handles all rejections of a certain type at the same time. This is useful for cases where your need access to more + than the first rejection of a certain type, e.g. for producing the error message to an unsupported request method. + +handleNotFound + As described :ref:`above ` "Resource Not Found" is special as it is represented with an empty + rejection set. The ``handleNotFound`` helper let's you specify the "recovery route" for this case. + +Even though you could handle several different rejection types in a single partial function supplied to ``handle`` +it is recommended to split these up into distinct ``handle`` attachments instead. +This way the priority between rejections is properly defined via the order of your ``handle`` clauses rather than the +(sometimes hard to predict or control) order of rejections in the rejection set. + +Once you have defined your custom ``RejectionHandler`` you have two options for "activating" it: + +1. Bring it into implicit scope at the top-level. +2. Supply it as argument to the :ref:`-handleRejections-` directive. + +In the first case your handler will be "sealed" (which means that it will receive the default handler as a fallback for +all cases your handler doesn't handle itself) and used for all rejections that are not handled within the route structure +itself. + +The second case allows you to restrict the applicability of your handler to certain branches of your route structure. diff --git a/akka-docs-dev/rst/scala/http/routing.rst b/akka-docs-dev/rst/scala/http/routing-dsl/routes.rst similarity index 51% rename from akka-docs-dev/rst/scala/http/routing.rst rename to akka-docs-dev/rst/scala/http/routing-dsl/routes.rst index 53046cef67..3543ef547c 100644 --- a/akka-docs-dev/rst/scala/http/routing.rst +++ b/akka-docs-dev/rst/scala/http/routing-dsl/routes.rst @@ -1,68 +1,87 @@ -.. _http-routing-scala: - -The Routing DSL -=============== - .. _Routes: Routes ------- +====== -The "Route" is the central concept of the routing DSL since all structures you can build with it are instances of -a ``Route``. The type Route is defined like this:: +The "Route" is the central concept of Akka HTTP's Routing DSL. All the structures you build with the DSL, no matter +whether they consists of a single line or span several hundred lines, are instances of this type:: - type Route = RequestContext => Future[RouteResult] + type Route = RequestContext ⇒ Future[RouteResult] -It's a simple alias for a function taking a ``RequestContext`` as parameter and returning a ``Future[RouteResult]``. +It's a simple alias for a function turning a ``RequestContext`` into a ``Future[RouteResult]``. Generally when a route receives a request (or rather a ``RequestContext`` for it) it can do one of these things: -- Complete the request by returning the value of ``requestContext.complete(...)`` +- Complete the request by returning the value of ``requestContext.complete(...)`` - Reject the request by returning the value of ``requestContext.reject(...)`` (see :ref:`Rejections`) - Fail the request by returning the value of ``requestContext.fail(...)`` or by just throwing an exception (see :ref:`Exception Handling`) -- Do any kind of asynchronous processing and instantly return a ``Future[RouteResult]`` to be eventually completed later on +- Do any kind of asynchronous processing and instantly return a ``Future[RouteResult]`` to be eventually completed later The first case is pretty clear, by calling ``complete`` a given response is sent to the client as reaction to the request. In the second case "reject" means that the route does not want to handle the request. You'll see further down in the section about route composition what this is good for. -A ``Route`` can be sealed using ``Route.seal`` and by supplying a ``RejectionHandler`` and an ``ExceptionHandler`` which -converts rejection results and exceptional results into appropriate HTTP responses for the peer. +A ``Route`` can be "sealed" using ``Route.seal``, which relies on the in-scope ``RejectionHandler`` and ``ExceptionHandler`` +instances to convert rejections and exceptions into appropriate HTTP responses for the client. + +Using ``Route.handlerFlow`` or ``Route.asyncHandler`` a ``Route`` can be lifted into a handler ``Flow`` or async handler +function to be used with a ``bindAndHandleXXX`` call from the :ref:`http-low-level-server-side-api`. + +Note: There is also an implicit conversion from ``Route`` to ``Flow[HttpRequest, HttpResponse, Unit]`` defined in the +``RouteResult`` companion, which relies on ``Route.handlerFlow``. -A ``Route`` can be lifted into a handler to be used with the http-core API using ``Route.handlerFlow`` or -``Route.asyncHandler``. .. _RequestContext: RequestContext -------------- -The request context wraps a request together with additional contextual information to be passed through the route tree. -Also, it provides the only way of creating a ``RouteResult`` by calling one of the above methods. +The request context wraps an ``HttpRequest`` instance to enrich it with additional information that are typically +required by the routing logic, like an ``ExecutionContext``, ``FlowMaterializer``, ``LoggingAdapter`` and the configured +``RoutingSettings``. It also contains the ``unmatchedPath``, a value that describes how much of the request URI has not +yet been matched by a :ref:`Path Directive `. -In addition to the request it contains the ``unmatchedPath``, a value that describes how much of the request URI has not -yet been matched and instances of several configuration instances like a ``LoggingAdapter``, an ``ExecutionContext``, and -``RoutingSettings``, so that they don't have to be passed around explicitly. +The ``RequestContext`` itself is immutable but contains several helper methods which allow for convenient creation of +modified copies. + + +.. _RouteResult: + +RouteResult +----------- + +``RouteResult`` is a simple abstract data type (ADT) that models the possible non-error results of a ``Route``. +It is defined as such:: + + sealed trait RouteResult + + object RouteResult { + final case class Complete(response: HttpResponse) extends RouteResult + final case class Rejected(rejections: immutable.Seq[Rejection]) extends RouteResult + } + +Usually you don't create any ``RouteResult`` instances yourself, but rather rely on the pre-defined :ref:`RouteDirectives` +(like :ref:`-complete-`, :ref:`-reject-` or :ref:`-redirect-`) or the respective methods on the :ref:`RequestContext` +instead. -The ``RequestContext`` itself is immutable but contains several helper methods to create updated versions. Composing Routes ---------------- There are three basic operations we need for building more complex routes from simpler ones: -.. rst-class:: wide - - Route transformation, which delegates processing to another, "inner" route but in the process changes some properties of either the incoming request, the outgoing response or both - Route filtering, which only lets requests satisfying a given filter condition pass and rejects all others - Route chaining, which tries a second route if a given first one was rejected -The last point is achieved with the concatenation operator ``~``, which is an extension method provided by an implicit in -``RouteConcatenation``. The first two points are provided by so-called :ref:`Directives`, of which a large number is -already predefined by Akka HTTP and which you can also easily create yourself. +The last point is achieved with the concatenation operator ``~``, which is an extension method that becomes available +when you ``import akka.http.scaladsl.server.Directives._``. +The first two points are provided by so-called :ref:`Directives` of which a large number is already predefined by Akka +HTTP and which you can also easily create yourself. :ref:`Directives` deliver most of Akka HTTP's power and flexibility. + .. _The Routing Tree: The Routing Tree @@ -92,8 +111,6 @@ Consider this schematic example:: Here five directives form a routing tree. -.. rst-class:: wide - - Route 1 will only be reached if directives ``a``, ``b`` and ``c`` all let the request pass through. - Route 2 will run if ``a`` and ``b`` pass, ``c`` rejects and ``d`` passes. - Route 3 will run if ``a`` and ``b`` pass, but ``c`` and ``d`` reject. @@ -101,5 +118,3 @@ Here five directives form a routing tree. Route 3 can therefore be seen as a "catch-all" route that only kicks in, if routes chained into preceding positions reject. This mechanism can make complex filtering logic quite easy to implement: simply put the most specific cases up front and the most general cases in the back. - - diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/testkit.rst b/akka-docs-dev/rst/scala/http/routing-dsl/testkit.rst new file mode 100644 index 0000000000..9f051a0083 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/testkit.rst @@ -0,0 +1,107 @@ +Route TestKit +============= + +One of Akka HTTP's design goals is good testability of the created services. +For services built with the Routing DSL Akka HTTP provides a dedicated testkit that makes efficient testing of +route logic easy and convenient. This "route test DSL" is made available with the *akka-http-testkit-scala* module. + + +Usage +----- + +Here is an example of what a simple test with the routing testkit might look like (using the built-in support for +scalatest_): + +.. includecode2:: ../../code/docs/http/scaladsl/server/FullTestKitExampleSpec.scala + :snippet: source-quote + +The basic structure of a test built with the testkit is this (expression placeholder in all-caps):: + + REQUEST ~> ROUTE ~> check { + ASSERTIONS + } + +In this template *REQUEST* is an expression evaluating to an ``HttpRequest`` instance. +In most cases your test will, in one way or another, extend from ``RouteTest`` which itself mixes in the +``akka.http.scaladsl.client.RequestBuilding`` trait, which gives you a concise and convenient way of constructing +test requests. [1]_ + +*ROUTE* is an expression evaluating to a :ref:`Route `. You can specify one inline or simply refer to the +route structure defined in your service. + +The final element of the ``~>`` chain is a ``check`` call, which takes a block of assertions as parameter. In this block +you define your requirements onto the result produced by your route after having processed the given request. Typically +you use one of the defined "inspectors" to retrieve a particular element of the routes response and express assertions +against it using the test DSL provided by your test framework. For example, with scalatest_, in order to verify that +your route responds to the request with a status 200 response, you'd use the ``status`` inspector and express an +assertion like this:: + + status shouldEqual 200 + +The following inspectors are defined: + +================================================ ======================================================================= +Inspector Description +================================================ ======================================================================= +``charset: HttpCharset`` Identical to ``contentType.charset`` +``chunks: Seq[HttpEntity.ChunkStreamPart]`` Returns the entity chunks produced by the route. If the entity is not + ``chunked`` returns ``Nil``. +``closingExtension: String`` Returns chunk extensions the route produced with its last response + chunk. If the response entity is unchunked returns the empty string. +``contentType: ContentType`` Identical to ``responseEntity.contentType`` +``definedCharset: Option[HttpCharset]`` Identical to ``contentType.definedCharset`` +``entityAs[T :FromEntityUnmarshaller]: T`` Unmarshals the response entity using the in-scope + ``FromEntityUnmarshaller`` for the given type. Any errors in the + process trigger a test failure. +``handled: Boolean`` Indicates whether the route produced an ``HttpResponse`` for the + request. If the route rejected the request ``handled`` evaluates to + ``false``. +``header(name: String): Option[HttpHeader]`` Returns the response header with the given name or ``None`` if no such + header is present in the response. +``header[T <: HttpHeader]: Option[T]`` Identical to ``response.header[T]`` +``headers: Seq[HttpHeader]`` Identical to ``response.headers`` +``mediaType: MediaType`` Identical to ``contentType.mediaType`` +``rejection: Rejection`` The rejection produced by the route. If the route did not produce + exactly one rejection a test failure is triggered. +``rejections: Seq[Rejection]`` The rejections produced by the route. If the route did not reject the + request a test failure is triggered. +``response: HttpResponse`` The ``HttpResponse`` returned by the route. If the route did not return + an ``HttpResponse`` instance (e.g. because it rejected the request) a + test failure is triggered. +``responseAs[T: FromResponseUnmarshaller]: T`` Unmarshals the response entity using the in-scope + ``FromResponseUnmarshaller`` for the given type. Any errors in the + process trigger a test failure. +``responseEntity: HttpEntity`` Returns the response entity. +``status: StatusCode`` Identical to ``response.status`` +``trailer: Seq[HttpHeader]`` Returns the list of trailer headers the route produced with its last + chunk. If the response entity is unchunked returns ``Nil``. +================================================ ======================================================================= + +.. [1] If the request URI is relative it will be made absolute using an implicitly available instance of + ``DefaultHostInfo`` whose value is "http://example.com" by default. This mirrors the behavior of akka-http-core + which always produces absolute URIs for incoming request based on the request URI and the ``Host``-header of + the request. You can customize this behavior by bringing a custom instance of ``DefaultHostInfo`` into scope. + + +Sealing Routes +-------------- + +The section above describes how to test a "regular" branch of your route structure, which reacts to incoming requests +with HTTP response parts or rejections. Sometimes, however, you will want to verify that your service also translates +:ref:`Rejections` to HTTP responses in the way you expect. + +You do this by wrapping your route with the ``akka.http.scaladsl.server.Route.seal``. +The ``seal`` wrapper applies the logic of the in-scope :ref:`ExceptionHandler ` and +:ref:`RejectionHandler ` to all exceptions and rejections coming back from the route, +and translates them to the respective ``HttpResponse``. + + +Examples +-------- + +A great pool of examples are the tests for all the predefined directives in Akka HTTP. +They can be found here__. + +__ @github@/akka-http-tests-scala/src/test/scala/akka/http/scaladsl/server/directives/ + +.. _scalatest: http://www.scalatest.org \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/routing-dsl/websocket-support.rst b/akka-docs-dev/rst/scala/http/routing-dsl/websocket-support.rst new file mode 100644 index 0000000000..123201efd8 --- /dev/null +++ b/akka-docs-dev/rst/scala/http/routing-dsl/websocket-support.rst @@ -0,0 +1,4 @@ +Server-Side WebSocket Support +============================= + +TODO \ No newline at end of file diff --git a/akka-docs-dev/rst/scala/http/server.rst b/akka-docs-dev/rst/scala/http/server.rst deleted file mode 100644 index 7b9c25f339..0000000000 --- a/akka-docs-dev/rst/scala/http/server.rst +++ /dev/null @@ -1,156 +0,0 @@ -.. _http-core-server-scala: - -Server API -========== - -The Akka HTTP server is an embedded, stream-based, fully asynchronous, low-overhead -HTTP/1.1 server implemented on top of :ref:`streams-scala`. - -It sports the following features: - -- Full support for `HTTP persistent connections`_ -- Full support for `HTTP pipelining`_ -- Full support for asynchronous HTTP streaming including "chunked" transfer encoding accessible through an idiomatic - reactive streams API -- Optional SSL/TLS encryption - -.. _HTTP persistent connections: http://en.wikipedia.org/wiki/HTTP_persistent_connection -.. _HTTP pipelining: http://en.wikipedia.org/wiki/HTTP_pipelining - - -Design Philosophy ------------------ - -Akka HTTP server is scoped with a clear focus on the essential functionality of an HTTP/1.1 server: - -- Connection management -- Parsing messages and headers -- Timeout management (for requests and connections) -- Response ordering (for transparent pipelining support) - -All non-core features of typical HTTP servers (like request routing, file serving, compression, etc.) are left to -the next-higher layer in the application stack, they are not implemented by the HTTP server itself. -Apart from general focus this design keeps the server small and light-weight as well as easy to understand and -maintain. - - -Basic Architecture ------------------- - -Akka HTTP server is implemented on top of Akka streams and makes heavy use of them - in its -implementation and also on all levels of its API. - -On the connection level Akka HTTP supports basically the same interface as Akka streams IO: A socket binding is -represented as a stream of incoming connections. The application needs to provide a ``Flow[HttpRequest, HttpResponse]`` -to "translate" requests into responses. - -Streaming is also supported for single message entities itself. Particular kinds of ``HttpEntity`` -subclasses provide support for fixed or streamed message entities. - - -Starting and Stopping ---------------------- - -An Akka HTTP server is bound by invoking the ``bind`` method of the `akka.http.Http`_ extension: - -.. includecode:: ../code/docs/http/HttpServerExampleSpec.scala - :include: bind-example - -Arguments to the ``Http.bind`` method specify the interface and port to bind to and register interest in handling incoming -HTTP connections. Additionally, the method also allows you to define socket options as well as a larger number -of settings for configuring the server according to your needs. - -The result of the ``bind`` method is a ``Source[IncomingConnection]`` which is used to handle incoming connections. -The actual binding is only done when this source is materialized as part of a bigger processing pipeline. In case the -bind fails (e.g. because the port is already busy) the error will be reported by flagging an error on the materialized -stream. The binding is released and the underlying listening socket is closed when all subscribers of the -source have cancelled their subscription. - -Connections are handled by materializing a pipeline which uses the ``Source[IncomingConnection]``. This source -materializes to ``Future[ServerBinding]`` which is completed when server successfully binds to the specified port. -After materialization ``ServerBinding.localAddress`` returns the actual local address of the bound socket. -``ServerBinding.unbind()`` can be used to asynchronously trigger unbinding of the server port. - -(todo: explain even lower level serverFlowToTransport API) - -.. _akka.http.Http: @github@/akka-http-core/src/main/scala/akka/http/Http.scala - - -Request-Response Cycle ----------------------- - -When a new connection has been accepted it will be published as an ``Http.IncomingConnection`` which consists -of the remote address, and methods to provide a ``Flow[HttpRequest, HttpResponse]`` to handle requests coming in over -this connection. - -Requests are handled by calling one of the ``IncomingConnection.handleWithX`` methods with a handler, which can either be - - - a ``Flow[HttpRequest, HttpResponse]`` for ``handleWith``, - - a function ``HttpRequest => HttpResponse`` for ``handleWithSyncHandler``, - - or a function ``HttpRequest => Future[HttpResponse]`` for ``handleWithAsyncHandler``. - -.. includecode:: ../code/docs/http/HttpServerExampleSpec.scala - :include: full-server-example - -In this case, a request is handled by transforming the request stream with a function ``HttpRequest => HttpResponse`` -using ``handleWithSyncHandler`` (or equivalently, Akka stream's ``map`` operator). Depending on the use case, arbitrary -other ways of connecting are conceivable using Akka stream's combinators. - -If the application provides a ``Flow``, it is also the responsibility of the application to generate exactly one response -for every request and that the ordering of responses matches the ordering of the associated requests (which is relevant -if HTTP pipelining is enabled where processing of multiple incoming requests may overlap). Using ``handleWithSyncHandler`` -or ``handleWithAsyncHandler`` or, instead, if using stream operators like ``map`` or ``mapFuture`` this requirement -will automatically be fulfilled. - -Streaming request/response entities -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Streaming of HTTP message entities is supported through subclasses of ``HttpEntity``. You need to be able to deal -with streamed entities when receiving a request as well as when constructing responses. See :ref:`HttpEntity` for -a description of the alternatives. - -(todo): Link to :ref:`http-routing-scala` for (un-)marshalling facilities. - - -Closing a connection -~~~~~~~~~~~~~~~~~~~~ - -The HTTP connection will be closed when the handling ``Flow`` cancel its upstream subscription or the peer closes the -connection. - -You can also use the value of the ``Connection`` header of a response as described below to give a hint to the -implementation to close the connection after the completion of the response. - -HTTP Headers ------------- - -When the Akka HTTP server receives an HTTP request it tries to parse all its headers into their respective -model classes. No matter whether this succeeds or not, the connection actor will always pass on all -received headers to the application. Unknown headers as well as ones with invalid syntax (according to the header -parser) will be made available as ``RawHeader`` instances. For the ones exhibiting parsing errors a warning message is -logged depending on the value of the ``illegal-header-warnings`` config setting. - -Some common headers are treated specially in the model and in the implementation and should not occur in the ``headers`` -field of an HTTP message: - -- ``Content-Type``: Use the ``contentType`` field of the ``HttpEntity`` subclasses to set or determine the content-type - on an entity. -- ``Transfer-Encoding``: The ``Transfer-Encoding`` is represented by subclasses of ``HttpEntity``. -- ``Content-Length``: The ``Content-Length`` header is represented implicitly by the choice of an ``HttpEntity`` subclass: - A Strict entity determines the Content-Length by the length of the data provided. A Default entity has an explicit - ``contentLength`` field which specifies the amount of data the streaming producer will produce. Chunked and CloseDelimited - entities don't need to define a length. -- ``Server``: The ``Server`` header is usually added automatically and it's value can be configured. An application can - decide to provide a custom ``Server`` header by including an explicit instance in the response. -- ``Date``: The ``Date`` header is added automatically and can be overridden by supplying it manually. -- ``Connection``: When sending out responses the connection actor watches for a ``Connection`` header set by the - application and acts accordingly, i.e. you can force the connection actor to close the connection after having sent - the response by including a ``Connection("close")`` header. To unconditionally force a connection keep-alive you can - explicitly set a ``Connection("Keep-Alive")`` header. If you don't set an explicit ``Connection`` header the - connection actor will keep the connection alive if the client supports this (i.e. it either sent a - ``Connection: Keep-Alive`` header or advertised HTTP/1.1 capabilities without sending a ``Connection: close`` header). - -SSL Support ------------ - -(todo) diff --git a/akka-docs-dev/rst/scala/stream-flows-and-basics.rst b/akka-docs-dev/rst/scala/stream-flows-and-basics.rst index 9856a42321..b642f6ac93 100644 --- a/akka-docs-dev/rst/scala/stream-flows-and-basics.rst +++ b/akka-docs-dev/rst/scala/stream-flows-and-basics.rst @@ -198,7 +198,7 @@ and ``runWith()`` methods defined on flow elements as well as a small number of well-known sinks, such as ``runForeach(el => )`` (being an alias to ``runWith(Sink.foreach(el => ))``. Materialization is currently performed synchronously on the materializing thread. -Tha actual stream processing is handled by :ref:`Actors actor-scala` started up during the streams materialization, +The actual stream processing is handled by actors started up during the streams materialization, which will be running on the thread pools they have been configured to run on - which defaults to the dispatcher set in :class:`MaterializationSettings` while constructing the :class:`ActorFlowMaterializer`. diff --git a/akka-docs-dev/rst/stages-overview.rst b/akka-docs-dev/rst/stages-overview.rst index 914ad846dd..ce79a57f03 100644 --- a/akka-docs-dev/rst/stages-overview.rst +++ b/akka-docs-dev/rst/stages-overview.rst @@ -70,6 +70,7 @@ groupedWithin the configured time elapses since the last group has been **It is currently not possible to build custom timer driven stages** .. _detached-stages-overview: + Backpressure aware stages ^^^^^^^^^^^^^^^^^^^^^^^^^