=doc a first set of new and imported documentation for akka-http
This commit is contained in:
parent
6f11735765
commit
af14fd8243
81 changed files with 3674 additions and 54 deletions
109
akka-docs-dev/_sphinx/exts/includecode2.py
Normal file
109
akka-docs-dev/_sphinx/exts/includecode2.py
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
import os
|
||||
import codecs
|
||||
import re
|
||||
from os import path
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
|
||||
class IncludeCode2(Directive):
|
||||
"""
|
||||
Include a code example from a file with sections delimited with special comments.
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
'snippet': directives.unchanged_required
|
||||
}
|
||||
|
||||
def run(self):
|
||||
document = self.state.document
|
||||
arg0 = self.arguments[0]
|
||||
(filename, sep, section) = arg0.partition('#')
|
||||
|
||||
if not document.settings.file_insertion_enabled:
|
||||
return [document.reporter.warning('File insertion disabled', line=self.lineno)]
|
||||
env = document.settings.env
|
||||
if filename.startswith('/') or filename.startswith(os.sep):
|
||||
rel_fn = filename[1:]
|
||||
else:
|
||||
docdir = path.dirname(env.doc2path(env.docname, base=None))
|
||||
rel_fn = path.join(docdir, filename)
|
||||
try:
|
||||
fn = path.join(env.srcdir, rel_fn)
|
||||
except UnicodeDecodeError:
|
||||
# the source directory is a bytestring with non-ASCII characters;
|
||||
# let's try to encode the rel_fn in the file system encoding
|
||||
rel_fn = rel_fn.encode(sys.getfilesystemencoding())
|
||||
fn = path.join(env.srcdir, rel_fn)
|
||||
|
||||
encoding = self.options.get('encoding', env.config.source_encoding)
|
||||
codec_info = codecs.lookup(encoding)
|
||||
try:
|
||||
f = codecs.StreamReaderWriter(open(fn, 'U'),
|
||||
codec_info[2], codec_info[3], 'strict')
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
except (IOError, OSError):
|
||||
return [document.reporter.warning(
|
||||
'Include file %r not found or reading it failed' % fn,
|
||||
line=self.lineno)]
|
||||
except UnicodeError:
|
||||
return [document.reporter.warning(
|
||||
'Encoding %r used for reading included file %r seems to '
|
||||
'be wrong, try giving an :encoding: option' %
|
||||
(encoding, fn))]
|
||||
|
||||
snippet = self.options.get('snippet')
|
||||
current_snippets = ""
|
||||
res = []
|
||||
for line in lines:
|
||||
comment = line.rstrip().split("//", 1)[1] if line.find("//") >= 0 else ""
|
||||
if comment.startswith("#") and len(comment) > 1:
|
||||
current_snippets = comment
|
||||
indent = line.find("//")
|
||||
elif len(line) > 2 and line[2] == '"' and not current_snippets.startswith("#"):
|
||||
current_snippets = line[2:]
|
||||
indent = 4
|
||||
elif comment == "#" and current_snippets.startswith("#"):
|
||||
current_snippets = ""
|
||||
elif len(line) > 2 and line[2] == '}' and not current_snippets.startswith("#"):
|
||||
current_snippets = ""
|
||||
elif current_snippets.find(snippet) >= 0 and comment.find("hide") == -1:
|
||||
res.append(line[indent:].rstrip() + '\n')
|
||||
elif comment.find(snippet) >= 0:
|
||||
array = line.split("//", 1)
|
||||
l = array[0].rstrip() if array[1].startswith("/") > 0 else array[0].strip()
|
||||
res.append(l + '\n')
|
||||
elif re.search("(def|val) "+re.escape(snippet)+"(?=[:(\[])", line):
|
||||
# match signature line from `def <snippet>` but without trailing `=`
|
||||
start = line.find("def")
|
||||
if start == -1: start = line.find("val")
|
||||
|
||||
# include `implicit` if definition is prefixed with it
|
||||
implicitstart = line.find("implicit")
|
||||
if implicitstart != -1 and implicitstart < start: start = implicitstart
|
||||
|
||||
end = line.rfind("=")
|
||||
if end == -1: current_snippets = "matching_signature"
|
||||
res.append(line[start:end] + '\n')
|
||||
elif current_snippets == "matching_signature":
|
||||
end = line.rfind("=")
|
||||
if end != -1: current_snippets = ""
|
||||
res.append(line[start:end] + '\n')
|
||||
|
||||
text = ''.join(res)
|
||||
|
||||
if text == "":
|
||||
return [document.reporter.warning('Snippet "' + snippet + '" not found!', line=self.lineno)]
|
||||
|
||||
retnode = nodes.literal_block(text, text, source=fn)
|
||||
document.settings.env.note_dependency(rel_fn)
|
||||
return [retnode]
|
||||
|
||||
def setup(app):
|
||||
app.require_sphinx('1.0')
|
||||
app.add_directive('includecode2', IncludeCode2)
|
||||
|
|
@ -8,7 +8,7 @@ import sys, os
|
|||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
sys.path.append(os.path.abspath('../_sphinx/exts'))
|
||||
extensions = ['sphinx.ext.todo', 'includecode']
|
||||
extensions = ['sphinx.ext.todo', 'includecode', 'includecode2']
|
||||
|
||||
templates_path = ['_templates']
|
||||
source_suffix = '.rst'
|
||||
|
|
|
|||
|
|
@ -22,9 +22,8 @@ class HttpServerExampleSpec
|
|||
implicit val materializer = FlowMaterializer()
|
||||
|
||||
val serverBinding = Http(system).bind(interface = "localhost", port = 8080)
|
||||
for (connection <- serverBinding.connections) {
|
||||
serverBinding.connections.foreach { connection ⇒ // foreach materializes the source
|
||||
println("Accepted new connection from " + connection.remoteAddress)
|
||||
// handle connection here
|
||||
}
|
||||
//#bind-example
|
||||
}
|
||||
|
|
@ -56,7 +55,9 @@ class HttpServerExampleSpec
|
|||
serverBinding.connections foreach { connection =>
|
||||
println("Accepted new connection from " + connection.remoteAddress)
|
||||
|
||||
connection handleWith { Flow[HttpRequest] map requestHandler }
|
||||
connection handleWithSyncHandler requestHandler
|
||||
// this is equivalent to
|
||||
// connection handleWith { Flow[HttpRequest] map requestHandler }
|
||||
}
|
||||
//#full-server-example
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.server
|
||||
|
||||
import akka.http.server._
|
||||
import Directives._
|
||||
import akka.http.testkit.ScalatestRouteTest
|
||||
import org.scalatest._
|
||||
|
||||
class DirectiveExamplesSpec extends RoutingSpec {
|
||||
|
||||
"example-1, example-2" in {
|
||||
val route: Route =
|
||||
path("order" / IntNumber) { id =>
|
||||
get {
|
||||
complete {
|
||||
"Received GET request for order " + id
|
||||
}
|
||||
} ~
|
||||
put {
|
||||
complete {
|
||||
"Received PUT request for order " + id
|
||||
}
|
||||
}
|
||||
}
|
||||
verify(route) // hide
|
||||
}
|
||||
|
||||
"example-3" in {
|
||||
def innerRoute(id: Int): Route =
|
||||
get {
|
||||
complete {
|
||||
"Received GET 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-4" in {
|
||||
val route =
|
||||
path("order" / IntNumber) { id =>
|
||||
(get | put) { ctx =>
|
||||
ctx.complete("Received " + ctx.request.method.name + " request for order " + id)
|
||||
}
|
||||
}
|
||||
verify(route) // hide
|
||||
}
|
||||
|
||||
"example-5" in {
|
||||
val getOrPut = get | put
|
||||
val route =
|
||||
path("order" / IntNumber) { id =>
|
||||
getOrPut { ctx =>
|
||||
ctx.complete("Received " + ctx.request.method.name + " request for order " + id)
|
||||
}
|
||||
}
|
||||
verify(route) // hide
|
||||
}
|
||||
|
||||
"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)
|
||||
}
|
||||
verify(route) // hide
|
||||
}
|
||||
|
||||
"example-7" in {
|
||||
val orderGetOrPut = path("order" / IntNumber) & (get | put)
|
||||
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)
|
||||
}
|
||||
verify(route) // hide
|
||||
}
|
||||
|
||||
def verify(route: Route) = {
|
||||
Get("/order/42") ~> route ~> check { responseAs[String] shouldEqual "Received GET request for order 42" }
|
||||
Put("/order/42") ~> route ~> check { responseAs[String] shouldEqual "Received PUT request for order 42" }
|
||||
Get("/") ~> route ~> check { handled shouldEqual false }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.server
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.http.server.Route
|
||||
import akka.stream.FlowMaterializer
|
||||
|
||||
object MyHandler {
|
||||
//# example-1
|
||||
import akka.http.model.HttpResponse
|
||||
import akka.http.model.StatusCodes._
|
||||
import akka.http.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 = FlowMaterializer()
|
||||
|
||||
def handler = Route.handlerFlow(`<my-route-definition>`)
|
||||
}
|
||||
//#
|
||||
|
||||
def `<my-route-definition>`: 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!!!"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.server
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.stream.FlowMaterializer
|
||||
|
||||
import akka.http.server.{ Route, MissingCookieRejection }
|
||||
|
||||
import scala.concurrent.ExecutionContext
|
||||
|
||||
object MyRejectionHandler {
|
||||
//# example-1
|
||||
import akka.http.model._
|
||||
import akka.http.server._
|
||||
import StatusCodes._
|
||||
import Directives._
|
||||
|
||||
implicit val myRejectionHandler = RejectionHandler {
|
||||
case MissingCookieRejection(cookieName) :: _ =>
|
||||
complete(HttpResponse(BadRequest, entity = "No cookies, no service!!!"))
|
||||
}
|
||||
|
||||
object MyApp {
|
||||
implicit val system = ActorSystem()
|
||||
import system.dispatcher
|
||||
implicit val materializer = FlowMaterializer()
|
||||
|
||||
def handler = Route.handlerFlow(`<my-route-definition>`)
|
||||
}
|
||||
//#
|
||||
|
||||
def `<my-route-definition>`: 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.coding.Gzip
|
||||
|
||||
val route =
|
||||
path("order") {
|
||||
get {
|
||||
complete("Received GET")
|
||||
} ~
|
||||
post {
|
||||
decodeRequest(Gzip) {
|
||||
complete("Received POST")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.server
|
||||
|
||||
import akka.http.server.Directives
|
||||
import akka.http.testkit.ScalatestRouteTest
|
||||
import org.scalatest.{ Matchers, WordSpec }
|
||||
|
||||
abstract class RoutingSpec extends WordSpec with Matchers with Directives with ScalatestRouteTest
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.server
|
||||
package directives
|
||||
|
||||
import akka.http.model.headers.RawHeader
|
||||
import akka.http.server.RouteResult.Rejected
|
||||
import akka.http.server._
|
||||
import akka.util.ByteString
|
||||
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
import akka.http.model._
|
||||
|
||||
class BasicDirectivesExamplesSpec extends RoutingSpec {
|
||||
"0extract" in {
|
||||
val uriLength = extract(_.request.uri.toString.length)
|
||||
val route =
|
||||
uriLength { len =>
|
||||
complete(s"The length of the request URI is $len")
|
||||
}
|
||||
|
||||
Get("/abcdef") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The length of the request URI is 25"
|
||||
}
|
||||
}
|
||||
"textract" in {
|
||||
val pathAndQuery = textract { ctx =>
|
||||
val uri = ctx.request.uri
|
||||
(uri.path, uri.query)
|
||||
}
|
||||
val route =
|
||||
pathAndQuery { (p, query) =>
|
||||
complete(s"The path is $p and the query is $query")
|
||||
}
|
||||
|
||||
Get("/abcdef?ghi=12") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The path is /abcdef and the query is ghi=12"
|
||||
}
|
||||
}
|
||||
"tprovide" in {
|
||||
def provideStringAndLength(value: String) = tprovide((value, value.length))
|
||||
val route =
|
||||
provideStringAndLength("test") { (value, len) =>
|
||||
complete(s"Value is $value and its length is $len")
|
||||
}
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "Value is test and its length is 4"
|
||||
}
|
||||
}
|
||||
"0mapResponse" in {
|
||||
def overwriteResultStatus(response: HttpResponse): HttpResponse =
|
||||
response.copy(status = StatusCodes.BadGateway)
|
||||
val route = mapResponse(overwriteResultStatus)(complete("abc"))
|
||||
|
||||
Get("/abcdef?ghi=12") ~> route ~> check {
|
||||
status shouldEqual StatusCodes.BadGateway
|
||||
}
|
||||
}
|
||||
"mapResponseEntity" in {
|
||||
def prefixEntity(entity: ResponseEntity): ResponseEntity = entity match {
|
||||
case HttpEntity.Strict(contentType, data) =>
|
||||
HttpEntity.Strict(contentType, ByteString("test") ++ data)
|
||||
case _ => throw new IllegalStateException("Unexpected entity type")
|
||||
}
|
||||
|
||||
val prefixWithTest: Directive0 = mapResponseEntity(prefixEntity)
|
||||
val route = prefixWithTest(complete("abc"))
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "testabc"
|
||||
}
|
||||
}
|
||||
"mapResponseHeaders" in {
|
||||
// adds all request headers to the response
|
||||
val echoRequestHeaders = extract(_.request.headers).flatMap(respondWithHeaders)
|
||||
|
||||
val removeIdHeader = mapResponseHeaders(_.filterNot(_.lowercaseName == "id"))
|
||||
val route =
|
||||
removeIdHeader {
|
||||
echoRequestHeaders {
|
||||
complete("test")
|
||||
}
|
||||
}
|
||||
|
||||
Get("/") ~> RawHeader("id", "12345") ~> RawHeader("id2", "67890") ~> route ~> check {
|
||||
header("id") shouldEqual None
|
||||
header("id2").get.value shouldEqual "67890"
|
||||
}
|
||||
}
|
||||
"mapInnerRoute" in {
|
||||
val completeWithInnerException =
|
||||
mapInnerRoute { route =>
|
||||
ctx =>
|
||||
try {
|
||||
route(ctx)
|
||||
} catch {
|
||||
case NonFatal(e) => ctx.complete(s"Got ${e.getClass.getSimpleName} '${e.getMessage}'")
|
||||
}
|
||||
}
|
||||
|
||||
val route =
|
||||
completeWithInnerException {
|
||||
complete(throw new IllegalArgumentException("BLIP! BLOP! Everything broke"))
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "Got IllegalArgumentException 'BLIP! BLOP! Everything broke'"
|
||||
}
|
||||
}
|
||||
"mapRejections" in {
|
||||
// ignore any rejections and replace them by AuthorizationFailedRejection
|
||||
val replaceByAuthorizationFailed = mapRejections(_ => List(AuthorizationFailedRejection))
|
||||
val route =
|
||||
replaceByAuthorizationFailed {
|
||||
path("abc")(complete("abc"))
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
rejection shouldEqual AuthorizationFailedRejection
|
||||
}
|
||||
}
|
||||
"0mapRequest" in {
|
||||
def transformToPostRequest(req: HttpRequest): HttpRequest = req.copy(method = HttpMethods.POST)
|
||||
val route =
|
||||
mapRequest(transformToPostRequest) {
|
||||
extractRequest { req =>
|
||||
complete(s"The request method was ${req.method.name}")
|
||||
}
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The request method was POST"
|
||||
}
|
||||
}
|
||||
"mapRequestContext" in {
|
||||
val replaceRequest =
|
||||
mapRequestContext(_.withRequest(HttpRequest(HttpMethods.POST)))
|
||||
|
||||
val route =
|
||||
replaceRequest {
|
||||
extractRequest { req =>
|
||||
complete(req.method.value)
|
||||
}
|
||||
}
|
||||
|
||||
Get("/abc/def/ghi") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "POST"
|
||||
}
|
||||
}
|
||||
"0mapRouteResponse" in {
|
||||
val rejectAll = // not particularly useful directive
|
||||
mapRouteResult {
|
||||
case _ => Rejected(List(AuthorizationFailedRejection))
|
||||
}
|
||||
val route =
|
||||
rejectAll {
|
||||
complete("abc")
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
rejections.nonEmpty shouldEqual true
|
||||
}
|
||||
}
|
||||
"mapRouteResponsePF" in {
|
||||
case object MyCustomRejection extends Rejection
|
||||
val rejectRejections = // not particularly useful directive
|
||||
mapRouteResultPF {
|
||||
case Rejected(_) => Rejected(List(AuthorizationFailedRejection))
|
||||
}
|
||||
val route =
|
||||
rejectRejections {
|
||||
reject(MyCustomRejection)
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
rejection shouldEqual AuthorizationFailedRejection
|
||||
}
|
||||
}
|
||||
"pass" in {
|
||||
Get("/") ~> pass(complete("abc")) ~> check {
|
||||
responseAs[String] shouldEqual "abc"
|
||||
}
|
||||
}
|
||||
"0provide" in {
|
||||
def providePrefixedString(value: String): Directive1[String] = provide("prefix:" + value)
|
||||
val route =
|
||||
providePrefixedString("test") { value =>
|
||||
complete(value)
|
||||
}
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "prefix:test"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.server
|
||||
package directives
|
||||
|
||||
import akka.http.coding._
|
||||
import akka.http.model.{ HttpResponse, StatusCodes }
|
||||
import akka.http.model.headers.{ HttpEncodings, HttpEncoding, `Accept-Encoding`, `Content-Encoding` }
|
||||
import akka.http.model.headers.HttpEncodings._
|
||||
import akka.http.server._
|
||||
import akka.util.ByteString
|
||||
import org.scalatest.matchers.Matcher
|
||||
|
||||
class CodingDirectivesExamplesSpec extends RoutingSpec {
|
||||
"compressResponse-0" in {
|
||||
val route = compressResponse() { complete("content") }
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
response should haveContentEncoding(gzip)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(gzip, deflate) ~> route ~> check {
|
||||
response should haveContentEncoding(gzip)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(deflate) ~> route ~> check {
|
||||
response should haveContentEncoding(deflate)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(identity) ~> route ~> check {
|
||||
status shouldEqual StatusCodes.OK
|
||||
response should haveContentEncoding(identity)
|
||||
responseAs[String] shouldEqual "content"
|
||||
}
|
||||
}
|
||||
"compressResponse-1" in {
|
||||
val route = compressResponse(Gzip) { complete("content") }
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
response should haveContentEncoding(gzip)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(gzip, deflate) ~> route ~> check {
|
||||
response should haveContentEncoding(gzip)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(deflate) ~> route ~> check {
|
||||
rejection shouldEqual UnacceptedResponseEncodingRejection(gzip)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(identity) ~> route ~> check {
|
||||
rejection shouldEqual UnacceptedResponseEncodingRejection(gzip)
|
||||
}
|
||||
}
|
||||
"compressResponseIfRequested" in {
|
||||
val route = compressResponseIfRequested() { complete("content") }
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
response should haveContentEncoding(identity)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(gzip, deflate) ~> route ~> check {
|
||||
response should haveContentEncoding(gzip)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(deflate) ~> route ~> check {
|
||||
response should haveContentEncoding(deflate)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(identity) ~> route ~> check {
|
||||
response should haveContentEncoding(identity)
|
||||
}
|
||||
}
|
||||
"encodeResponse" in {
|
||||
val route = encodeResponse(Gzip) { complete("content") }
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
response should haveContentEncoding(gzip)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(gzip, deflate) ~> route ~> check {
|
||||
response should haveContentEncoding(gzip)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(deflate) ~> route ~> check {
|
||||
rejection shouldEqual UnacceptedResponseEncodingRejection(gzip)
|
||||
}
|
||||
Get("/") ~> `Accept-Encoding`(identity) ~> route ~> check {
|
||||
rejection shouldEqual UnacceptedResponseEncodingRejection(gzip)
|
||||
}
|
||||
}
|
||||
|
||||
val helloGzipped = compress("Hello", Gzip)
|
||||
val helloDeflated = compress("Hello", Deflate)
|
||||
"decodeRequest" in {
|
||||
val route =
|
||||
decodeRequest(Gzip) {
|
||||
entity(as[String]) { content: String =>
|
||||
complete(s"Request content: '$content'")
|
||||
}
|
||||
}
|
||||
|
||||
Post("/", helloGzipped) ~> `Content-Encoding`(gzip) ~> route ~> check {
|
||||
responseAs[String] shouldEqual "Request content: 'Hello'"
|
||||
}
|
||||
Post("/", helloDeflated) ~> `Content-Encoding`(deflate) ~> route ~> check {
|
||||
rejection shouldEqual UnsupportedRequestEncodingRejection(gzip)
|
||||
}
|
||||
Post("/", "hello") ~> `Content-Encoding`(identity) ~> route ~> check {
|
||||
rejection shouldEqual UnsupportedRequestEncodingRejection(gzip)
|
||||
}
|
||||
}
|
||||
"decompressRequest-0" in {
|
||||
val route =
|
||||
decompressRequest() {
|
||||
entity(as[String]) { content: String =>
|
||||
complete(s"Request content: '$content'")
|
||||
}
|
||||
}
|
||||
|
||||
Post("/", helloGzipped) ~> `Content-Encoding`(gzip) ~> route ~> check {
|
||||
responseAs[String] shouldEqual "Request content: 'Hello'"
|
||||
}
|
||||
Post("/", helloDeflated) ~> `Content-Encoding`(deflate) ~> route ~> check {
|
||||
responseAs[String] shouldEqual "Request content: 'Hello'"
|
||||
}
|
||||
Post("/", "hello uncompressed") ~> `Content-Encoding`(identity) ~> route ~> check {
|
||||
responseAs[String] shouldEqual "Request content: 'hello uncompressed'"
|
||||
}
|
||||
}
|
||||
"decompressRequest-1" in {
|
||||
val route =
|
||||
decompressRequest(Gzip, NoCoding) {
|
||||
entity(as[String]) { content: String =>
|
||||
complete(s"Request content: '$content'")
|
||||
}
|
||||
}
|
||||
|
||||
Post("/", helloGzipped) ~> `Content-Encoding`(gzip) ~> route ~> check {
|
||||
responseAs[String] shouldEqual "Request content: 'Hello'"
|
||||
}
|
||||
Post("/", helloDeflated) ~> `Content-Encoding`(deflate) ~> route ~> check {
|
||||
rejections shouldEqual List(UnsupportedRequestEncodingRejection(gzip), UnsupportedRequestEncodingRejection(identity))
|
||||
}
|
||||
Post("/", "hello uncompressed") ~> `Content-Encoding`(identity) ~> route ~> check {
|
||||
responseAs[String] shouldEqual "Request content: 'hello uncompressed'"
|
||||
}
|
||||
}
|
||||
|
||||
def haveContentEncoding(encoding: HttpEncoding): Matcher[HttpResponse] =
|
||||
be(encoding) compose { (_: HttpResponse).header[`Content-Encoding`].map(_.encodings.head).getOrElse(HttpEncodings.identity) }
|
||||
|
||||
def compress(input: String, encoder: Encoder): ByteString = encoder.encode(ByteString(input))
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.server
|
||||
package directives
|
||||
|
||||
import akka.http.server._
|
||||
import akka.http.model.headers.{ HttpCookie, Cookie, `Set-Cookie` }
|
||||
import akka.http.util.DateTime
|
||||
|
||||
class CookieDirectivesExamplesSpec extends RoutingSpec {
|
||||
"cookie" in {
|
||||
val route =
|
||||
cookie("userName") { nameCookie =>
|
||||
complete(s"The logged in user is '${nameCookie.content}'")
|
||||
}
|
||||
|
||||
Get("/") ~> Cookie(HttpCookie("userName", "paul")) ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The logged in user is 'paul'"
|
||||
}
|
||||
// missing cookie
|
||||
Get("/") ~> route ~> check {
|
||||
rejection shouldEqual MissingCookieRejection("userName")
|
||||
}
|
||||
Get("/") ~> Route.seal(route) ~> check {
|
||||
responseAs[String] shouldEqual "Request is missing required cookie 'userName'"
|
||||
}
|
||||
}
|
||||
"optionalCookie" in {
|
||||
val route =
|
||||
optionalCookie("userName") {
|
||||
case Some(nameCookie) => complete(s"The logged in user is '${nameCookie.content}'")
|
||||
case None => complete("No user logged in")
|
||||
}
|
||||
|
||||
Get("/") ~> Cookie(HttpCookie("userName", "paul")) ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The logged in user is 'paul'"
|
||||
}
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "No user logged in"
|
||||
}
|
||||
}
|
||||
"deleteCookie" in {
|
||||
val route =
|
||||
deleteCookie("userName") {
|
||||
complete("The user was logged out")
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The user was logged out"
|
||||
header[`Set-Cookie`] shouldEqual Some(`Set-Cookie`(HttpCookie("userName", content = "deleted", expires = Some(DateTime.MinValue))))
|
||||
}
|
||||
}
|
||||
"setCookie" in {
|
||||
val route =
|
||||
setCookie(HttpCookie("userName", content = "paul")) {
|
||||
complete("The user was logged in")
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The user was logged in"
|
||||
header[`Set-Cookie`] shouldEqual Some(`Set-Cookie`(HttpCookie("userName", content = "paul")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.server
|
||||
package directives
|
||||
|
||||
import akka.http.model.{ HttpResponse, HttpRequest }
|
||||
import akka.http.server._
|
||||
|
||||
import akka.event.Logging
|
||||
import akka.http.server.directives.{ LoggingMagnet, LogEntry, DebuggingDirectives }
|
||||
|
||||
class DebuggingDirectivesExamplesSpec extends RoutingSpec {
|
||||
"logRequest-0" in {
|
||||
// different possibilities of using logRequest
|
||||
|
||||
// The first alternatives use an implicitly available LoggingContext for logging
|
||||
// marks with "get-user", log with debug level, HttpRequest.toString
|
||||
DebuggingDirectives.logRequest("get-user")
|
||||
|
||||
// marks with "get-user", log with info level, HttpRequest.toString
|
||||
DebuggingDirectives.logRequest("get-user", Logging.InfoLevel)
|
||||
|
||||
// logs just the request method at debug level
|
||||
def requestMethod(req: HttpRequest): String = req.method.toString
|
||||
DebuggingDirectives.logRequest(requestMethod _)
|
||||
|
||||
// logs just the request method at info level
|
||||
def requestMethodAsInfo(req: HttpRequest): LogEntry = LogEntry(req.method.toString, Logging.InfoLevel)
|
||||
DebuggingDirectives.logRequest(requestMethodAsInfo _)
|
||||
|
||||
// This one doesn't use the implicit LoggingContext but uses `println` for logging
|
||||
def printRequestMethod(req: HttpRequest): Unit = println(req.method)
|
||||
val logRequestPrintln = DebuggingDirectives.logRequest(LoggingMagnet(_ => printRequestMethod))
|
||||
|
||||
Get("/") ~> logRequestPrintln(complete("logged")) ~> check {
|
||||
responseAs[String] shouldEqual "logged"
|
||||
}
|
||||
}
|
||||
"logRequestResult" in {
|
||||
// different possibilities of using logRequestResponse
|
||||
|
||||
// The first alternatives use an implicitly available LoggingContext for logging
|
||||
// marks with "get-user", log with debug level, HttpRequest.toString, HttpResponse.toString
|
||||
DebuggingDirectives.logRequestResult("get-user")
|
||||
|
||||
// marks with "get-user", log with info level, HttpRequest.toString, HttpResponse.toString
|
||||
DebuggingDirectives.logRequestResult("get-user", Logging.InfoLevel)
|
||||
|
||||
// logs just the request method and response status at info level
|
||||
def requestMethodAndResponseStatusAsInfo(req: HttpRequest): Any => Option[LogEntry] = {
|
||||
case res: HttpResponse => Some(LogEntry(req.method + ":" + res.status, Logging.InfoLevel))
|
||||
case _ => None // other kind of responses
|
||||
}
|
||||
DebuggingDirectives.logRequestResult(requestMethodAndResponseStatusAsInfo _)
|
||||
|
||||
// This one doesn't use the implicit LoggingContext but uses `println` for logging
|
||||
def printRequestMethodAndResponseStatus(req: HttpRequest)(res: Any): Unit =
|
||||
println(requestMethodAndResponseStatusAsInfo(req)(res).map(_.obj.toString).getOrElse(""))
|
||||
val logRequestResultPrintln = DebuggingDirectives.logRequestResult(LoggingMagnet(_ => printRequestMethodAndResponseStatus))
|
||||
|
||||
Get("/") ~> logRequestResultPrintln(complete("logged")) ~> check {
|
||||
responseAs[String] shouldEqual "logged"
|
||||
}
|
||||
}
|
||||
"logResult" in {
|
||||
// different possibilities of using logResponse
|
||||
|
||||
// The first alternatives use an implicitly available LoggingContext for logging
|
||||
// marks with "get-user", log with debug level, HttpResponse.toString
|
||||
DebuggingDirectives.logResult("get-user")
|
||||
|
||||
// marks with "get-user", log with info level, HttpResponse.toString
|
||||
DebuggingDirectives.logResult("get-user", Logging.InfoLevel)
|
||||
|
||||
// logs just the response status at debug level
|
||||
def responseStatus(res: Any): String = res match {
|
||||
case x: HttpResponse => x.status.toString
|
||||
case _ => "unknown response part"
|
||||
}
|
||||
DebuggingDirectives.logResult(responseStatus _)
|
||||
|
||||
// logs just the response status at info level
|
||||
def responseStatusAsInfo(res: Any): LogEntry = LogEntry(responseStatus(res), Logging.InfoLevel)
|
||||
DebuggingDirectives.logResult(responseStatusAsInfo _)
|
||||
|
||||
// This one doesn't use the implicit LoggingContext but uses `println` for logging
|
||||
def printResponseStatus(res: Any): Unit = println(responseStatus(res))
|
||||
val logResultPrintln = DebuggingDirectives.logResult(LoggingMagnet(_ => printResponseStatus))
|
||||
|
||||
Get("/") ~> logResultPrintln(complete("logged")) ~> check {
|
||||
responseAs[String] shouldEqual "logged"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.server
|
||||
package directives
|
||||
|
||||
import akka.http.model.StatusCodes
|
||||
import akka.http.server._
|
||||
|
||||
class ExecutionDirectivesExamplesSpec extends RoutingSpec {
|
||||
"handleExceptions" in {
|
||||
val divByZeroHandler = ExceptionHandler {
|
||||
case _: ArithmeticException => complete(StatusCodes.BadRequest, "You've got your arithmetic wrong, fool!")
|
||||
}
|
||||
val route =
|
||||
path("divide" / IntNumber / IntNumber) { (a, b) =>
|
||||
handleExceptions(divByZeroHandler) {
|
||||
complete(s"The result is ${a / b}")
|
||||
}
|
||||
}
|
||||
|
||||
Get("/divide/10/5") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "The result is 2"
|
||||
}
|
||||
Get("/divide/10/0") ~> route ~> check {
|
||||
status shouldEqual StatusCodes.BadRequest
|
||||
responseAs[String] shouldEqual "You've got your arithmetic wrong, fool!"
|
||||
}
|
||||
}
|
||||
"handleRejections" in {
|
||||
val totallyMissingHandler = RejectionHandler {
|
||||
case Nil /* secret code for path not found */ =>
|
||||
complete(StatusCodes.NotFound, "Oh man, what you are looking for is long gone.")
|
||||
}
|
||||
val route =
|
||||
pathPrefix("handled") {
|
||||
handleRejections(totallyMissingHandler) {
|
||||
path("existing")(complete("This path exists"))
|
||||
}
|
||||
}
|
||||
|
||||
Get("/handled/existing") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "This path exists"
|
||||
}
|
||||
Get("/missing") ~> Route.seal(route) /* applies default handler */ ~> check {
|
||||
status shouldEqual StatusCodes.NotFound
|
||||
responseAs[String] shouldEqual "The requested resource could not be found."
|
||||
}
|
||||
Get("/handled/missing") ~> route ~> check {
|
||||
status shouldEqual StatusCodes.NotFound
|
||||
responseAs[String] shouldEqual "Oh man, what you are looking for is long gone."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.http.server
|
||||
package directives
|
||||
|
||||
import akka.http.server._
|
||||
|
||||
class PathDirectivesExamplesSpec extends RoutingSpec {
|
||||
|
||||
//# path-matcher
|
||||
val matcher: PathMatcher1[Option[Int]] =
|
||||
"foo" / "bar" / "X" ~ IntNumber.? / ("edit" | "create")
|
||||
//#
|
||||
|
||||
//# path-dsl
|
||||
// matches /foo/
|
||||
path("foo" /)
|
||||
|
||||
// matches e.g. /foo/123 and extracts "123" as a String
|
||||
path("foo" / """\d+""".r)
|
||||
|
||||
// matches e.g. /foo/bar123 and extracts "123" as a String
|
||||
path("foo" / """bar(\d+)""".r)
|
||||
|
||||
// similar to `path(Segments)`
|
||||
path(Segment.repeat(10, separator = Slash))
|
||||
|
||||
// matches e.g. /i42 or /hCAFE and extracts an Int
|
||||
path("i" ~ IntNumber | "h" ~ HexIntNumber)
|
||||
|
||||
// identical to path("foo" ~ (PathEnd | Slash))
|
||||
path("foo" ~ Slash.?)
|
||||
|
||||
// matches /red or /green or /blue and extracts 1, 2 or 3 respectively
|
||||
path(Map("red" -> 1, "green" -> 2, "blue" -> 3))
|
||||
|
||||
// matches anything starting with "/foo" except for /foobar
|
||||
pathPrefix("foo" ~ !"bar")
|
||||
//#
|
||||
|
||||
//# pathPrefixTest-, rawPathPrefix-, rawPathPrefixTest-, pathSuffix-, pathSuffixTest-
|
||||
val completeWithUnmatchedPath =
|
||||
extractUnmatchedPath { p =>
|
||||
complete(p.toString)
|
||||
}
|
||||
|
||||
//#
|
||||
|
||||
"path-example" in {
|
||||
val route =
|
||||
path("foo") {
|
||||
complete("/foo")
|
||||
} ~
|
||||
path("foo" / "bar") {
|
||||
complete("/foo/bar")
|
||||
} ~
|
||||
pathPrefix("ball") {
|
||||
pathEnd {
|
||||
complete("/ball")
|
||||
} ~
|
||||
path(IntNumber) { int =>
|
||||
complete(if (int % 2 == 0) "even ball" else "odd ball")
|
||||
}
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
handled shouldEqual false
|
||||
}
|
||||
|
||||
Get("/foo") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/foo"
|
||||
}
|
||||
|
||||
Get("/foo/bar") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/foo/bar"
|
||||
}
|
||||
|
||||
Get("/ball/1337") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "odd ball"
|
||||
}
|
||||
}
|
||||
|
||||
"pathEnd-" in {
|
||||
val route =
|
||||
pathPrefix("foo") {
|
||||
pathEnd {
|
||||
complete("/foo")
|
||||
} ~
|
||||
path("bar") {
|
||||
complete("/foo/bar")
|
||||
}
|
||||
}
|
||||
|
||||
Get("/foo") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/foo"
|
||||
}
|
||||
|
||||
Get("/foo/") ~> route ~> check {
|
||||
handled shouldEqual false
|
||||
}
|
||||
|
||||
Get("/foo/bar") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/foo/bar"
|
||||
}
|
||||
}
|
||||
|
||||
"pathEndOrSingleSlash-" in {
|
||||
val route =
|
||||
pathPrefix("foo") {
|
||||
pathEndOrSingleSlash {
|
||||
complete("/foo")
|
||||
} ~
|
||||
path("bar") {
|
||||
complete("/foo/bar")
|
||||
}
|
||||
}
|
||||
|
||||
Get("/foo") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/foo"
|
||||
}
|
||||
|
||||
Get("/foo/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/foo"
|
||||
}
|
||||
|
||||
Get("/foo/bar") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/foo/bar"
|
||||
}
|
||||
}
|
||||
|
||||
"pathPrefix-" in {
|
||||
val route =
|
||||
pathPrefix("ball") {
|
||||
pathEnd {
|
||||
complete("/ball")
|
||||
} ~
|
||||
path(IntNumber) { int =>
|
||||
complete(if (int % 2 == 0) "even ball" else "odd ball")
|
||||
}
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
handled shouldEqual false
|
||||
}
|
||||
|
||||
Get("/ball") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/ball"
|
||||
}
|
||||
|
||||
Get("/ball/1337") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "odd ball"
|
||||
}
|
||||
}
|
||||
|
||||
"pathPrefixTest-" in {
|
||||
val route =
|
||||
pathPrefixTest("foo" | "bar") {
|
||||
pathPrefix("foo") { completeWithUnmatchedPath } ~
|
||||
pathPrefix("bar") { completeWithUnmatchedPath }
|
||||
}
|
||||
|
||||
Get("/foo/doo") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/doo"
|
||||
}
|
||||
|
||||
Get("/bar/yes") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/yes"
|
||||
}
|
||||
}
|
||||
|
||||
"pathSingleSlash-" in {
|
||||
val route =
|
||||
pathSingleSlash {
|
||||
complete("root")
|
||||
} ~
|
||||
pathPrefix("ball") {
|
||||
pathSingleSlash {
|
||||
complete("/ball/")
|
||||
} ~
|
||||
path(IntNumber) { int =>
|
||||
complete(if (int % 2 == 0) "even ball" else "odd ball")
|
||||
}
|
||||
}
|
||||
|
||||
Get("/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "root"
|
||||
}
|
||||
|
||||
Get("/ball") ~> route ~> check {
|
||||
handled shouldEqual false
|
||||
}
|
||||
|
||||
Get("/ball/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/ball/"
|
||||
}
|
||||
|
||||
Get("/ball/1337") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "odd ball"
|
||||
}
|
||||
}
|
||||
|
||||
"pathSuffix-" in {
|
||||
val route =
|
||||
pathPrefix("start") {
|
||||
pathSuffix("end") {
|
||||
completeWithUnmatchedPath
|
||||
} ~
|
||||
pathSuffix("foo" / "bar" ~ "baz") {
|
||||
completeWithUnmatchedPath
|
||||
}
|
||||
}
|
||||
|
||||
Get("/start/middle/end") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/middle/"
|
||||
}
|
||||
|
||||
Get("/start/something/barbaz/foo") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/something/"
|
||||
}
|
||||
}
|
||||
|
||||
"pathSuffixTest-" in {
|
||||
val route =
|
||||
pathSuffixTest(Slash) {
|
||||
complete("slashed")
|
||||
} ~
|
||||
complete("unslashed")
|
||||
|
||||
Get("/foo/") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "slashed"
|
||||
}
|
||||
Get("/foo") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "unslashed"
|
||||
}
|
||||
}
|
||||
|
||||
"rawPathPrefix-" in {
|
||||
val route =
|
||||
pathPrefix("foo") {
|
||||
rawPathPrefix("bar") { completeWithUnmatchedPath } ~
|
||||
rawPathPrefix("doo") { completeWithUnmatchedPath }
|
||||
}
|
||||
|
||||
Get("/foobar/baz") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/baz"
|
||||
}
|
||||
|
||||
Get("/foodoo/baz") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "/baz"
|
||||
}
|
||||
}
|
||||
|
||||
"rawPathPrefixTest-" in {
|
||||
val route =
|
||||
pathPrefix("foo") {
|
||||
rawPathPrefixTest("bar") {
|
||||
completeWithUnmatchedPath
|
||||
}
|
||||
}
|
||||
|
||||
Get("/foobar") ~> route ~> check {
|
||||
responseAs[String] shouldEqual "bar"
|
||||
}
|
||||
|
||||
Get("/foobaz") ~> route ~> check {
|
||||
handled shouldEqual false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
HTTPS
|
||||
=====
|
||||
|
||||
Is not yet supported.
|
||||
|
||||
(todo)
|
||||
|
|
@ -108,6 +108,9 @@ 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.
|
||||
|
||||
|
|
@ -130,7 +133,9 @@ which allows access to the data of an entity regardless of its concrete 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 as an alternative to Chunked e.g. if chunked transfer encoding isn't supported by a peer.
|
||||
- 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
|
||||
------------
|
||||
|
|
|
|||
|
|
@ -8,11 +8,9 @@ HTTP/1.1 server implemented on top of `Akka Streams`_. (todo: fix link)
|
|||
|
||||
It sports the following features:
|
||||
|
||||
- Low per-connection overhead for supporting many thousand concurrent connections
|
||||
- Efficient message parsing and processing logic for high throughput applications
|
||||
- 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
|
||||
- Full support for asynchronous HTTP streaming including "chunked" transfer encoding accessible through an idiomatic
|
||||
reactive streams API
|
||||
- Optional SSL/TLS encryption
|
||||
|
||||
|
|
@ -27,7 +25,7 @@ Design Philosophy
|
|||
Akka HTTP server is scoped with a clear focus on the essential functionality of an HTTP/1.1 server:
|
||||
|
||||
- Connection management
|
||||
- Message parsing and header separation
|
||||
- Parsing messages and headers
|
||||
- Timeout management (for requests and connections)
|
||||
- Response ordering (for transparent pipelining support)
|
||||
|
||||
|
|
@ -44,8 +42,8 @@ Akka HTTP server is implemented on top of Akka streams and makes heavy use of th
|
|||
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. Each connection itself is composed of an input stream of requests and
|
||||
an output consumer of responses. The application has to provide the handler to "translate" requests into responses.
|
||||
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.
|
||||
|
|
@ -54,26 +52,27 @@ subclasses provide support for fixed or streamed message entities.
|
|||
Starting and Stopping
|
||||
---------------------
|
||||
|
||||
An Akka HTTP server is started by sending an ``Http.Bind`` command to the `akka.http.Http`_ extension:
|
||||
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
|
||||
|
||||
With the ``Http.Bind`` command you specify the interface and port to bind to and register interest in handling incoming
|
||||
HTTP connections. Additionally the ``Http.Bind`` command also allows you to define socket options as well as a larger number
|
||||
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 sender of the ``Http.Bind`` command (e.g. an actor you have written) will receive an ``Http.ServerBinding`` reply
|
||||
after the HTTP layer has successfully started the server at the respective endpoint. In case the bind fails (e.g.
|
||||
because the port is already busy) a ``Failure`` message is dispatched instead. As shown in the above example this works
|
||||
well with the ask pattern and Future operations.
|
||||
The result of the ``bind`` method is a ``Http.ServerBinding`` which is immediately returned. The ``ServerBinding.connections``
|
||||
returns 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 ``IncomingConnection`` stream.
|
||||
|
||||
The ``Http.ServerBinding`` informs the binder of the actual local address of the bound socket and it contains a
|
||||
stream of incoming connections of type ``Producer[Http.IncomingConnection]``. Connections are handled by subscribing
|
||||
to the connection stream and handling the incoming connections.
|
||||
After materialization ``ServerBinding.localAddress`` returns the actual local address of the bound socket.
|
||||
|
||||
The binding is released and the underlying listening socket is closed when all subscribers of the
|
||||
``Http.ServerBinding.connectionStream`` have cancelled their subscriptions.
|
||||
Connections are handled by materializing a pipeline which uses the ``Source[IncomingConnection]`` returned by
|
||||
``ServerBinding.connections``. The binding is released and the underlying listening socket is closed when all
|
||||
subscribers of the ``connections`` source have cancelled their subscription.
|
||||
|
||||
(todo: explain even lower level serverFlowToTransport API)
|
||||
|
||||
.. _akka.http.Http: @github@/akka-http-core/src/main/scala/akka/http/Http.scala
|
||||
|
||||
|
|
@ -81,23 +80,28 @@ The binding is released and the underlying listening socket is closed when all s
|
|||
Request-Response Cycle
|
||||
----------------------
|
||||
|
||||
When a new connection has been accepted it will be published by the ``Http.ServerBinding.connectionStream`` as an
|
||||
``Http.IncomingConnection`` which consists of the remote address, a ``requestProducer``, and a ``responseConsumer``.
|
||||
When a new connection has been accepted it will be published by by the ``ServerBinding.connections`` source 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.
|
||||
|
||||
Handling requests in this model means connecting the ``requestProducer`` stream with an application-defined component that
|
||||
maps requests to responses which then feeds into the ``responseConsumer``:
|
||||
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 Akka stream's ``map`` operator. Depending on the use case, arbitrary other ways of connecting are conceivable using
|
||||
Akka stream's operators (e.g using ``mapFuture`` to allow parallel processing of several requests when HTTP pipelining is
|
||||
enabled).
|
||||
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.
|
||||
|
||||
It's the application's responsibility to feed responses into the ``responseConsumer`` in the same order as the respective
|
||||
requests have come in. Also, each request must result in exactly one response. Using stream operators like ``map`` or
|
||||
``mapFuture`` will automatically fulfill this requirement.
|
||||
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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -112,8 +116,8 @@ a description of the alternatives.
|
|||
Closing a connection
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The HTTP connection will be closed when the ``responseConsumer`` gets completed or when the ``requestProducer``'s
|
||||
subscription was cancelled and no more responses are pending.
|
||||
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.
|
||||
|
|
@ -139,7 +143,7 @@ field of an HTTP message:
|
|||
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 will be ignored if supplied manually.
|
||||
- ``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
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
Custom Directives
|
||||
=================
|
||||
|
||||
(todo)
|
||||
138
akka-docs-dev/rst/scala/http/directives.rst
Normal file
138
akka-docs-dev/rst/scala/http/directives.rst
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
.. _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`.
|
||||
161
akka-docs-dev/rst/scala/http/directives/alphabetically.rst
Normal file
161
akka-docs-dev/rst/scala/http/directives/alphabetically.rst
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
.. _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.
|
||||
====================================== =================================================================================
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
.. _-extract-:
|
||||
|
||||
extract
|
||||
=======
|
||||
|
||||
Calculates a value from the request context and provides the value to the inner route.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala
|
||||
:snippet: extract
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``extract`` directive is used as a building block for :ref:`Custom Directives` to extract data from the
|
||||
``RequestContext`` and provide it to the inner route. It is a special case for extracting one value of the more
|
||||
general :ref:`-textract-` directive that can be used to extract more than one value.
|
||||
|
||||
See :ref:`ProvideDirectives` for an overview of similar directives.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: 0extract
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
.. _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
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.. _-mapInnerRoute-:
|
||||
|
||||
mapInnerRoute
|
||||
=============
|
||||
|
||||
Changes the execution model of the inner route by wrapping it with arbitrary logic.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala
|
||||
:snippet: mapInnerRoute
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``mapInnerRoute`` directive is used as a building block for :ref:`Custom Directives` to replace the inner route
|
||||
with any other route. Usually, the returned route wraps the original one with custom execution logic.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: mapInnerRoute
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
.. _-mapRejections-:
|
||||
|
||||
mapRejections
|
||||
=============
|
||||
|
||||
Transforms the list of rejections the inner route produced.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala
|
||||
:snippet: mapRejections
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``mapRejections`` directive is used as a building block for :ref:`Custom Directives` to transform a list
|
||||
of rejections from the inner route to a new list of rejections.
|
||||
|
||||
See :ref:`Response Transforming Directives` for similar directives.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: mapRejections
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
.. _-mapRequest-:
|
||||
|
||||
mapRequest
|
||||
==========
|
||||
|
||||
Transforms the request before it is handled by the inner route.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala
|
||||
:snippet: mapRequest
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``mapRequest`` directive is used as a building block for :ref:`Custom Directives` to transform a request before it
|
||||
is handled by the inner route. Changing the ``request.uri`` parameter has no effect on path matching in the inner route
|
||||
because the unmatched path is a separate field of the ``RequestContext`` value which is passed into routes. To change
|
||||
the unmatched path or other fields of the ``RequestContext`` use the :ref:`-mapRequestContext-` directive.
|
||||
|
||||
See :ref:`Request Transforming Directives` for an overview of similar directives.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: 0mapRequest
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
.. _-mapRequestContext-:
|
||||
|
||||
mapRequestContext
|
||||
=================
|
||||
|
||||
Transforms the ``RequestContext`` before it is passed to the inner route.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala
|
||||
:snippet: mapRequestContext
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``mapRequestContext`` directive is used as a building block for :ref:`Custom Directives` to transform
|
||||
the request context before it is passed to the inner route. To change only the request value itself the
|
||||
:ref:`-mapRequest-` directive can be used instead.
|
||||
|
||||
See :ref:`Request Transforming Directives` for an overview of similar directives.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: mapRequestContext
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
.. _-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
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
.. _-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
|
||||
:snippet: mapResponseEntity
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``mapResponseEntity`` directive is used as a building block for :ref:`Custom Directives` to transform a
|
||||
response entity that was generated by the inner route.
|
||||
|
||||
See :ref:`Response Transforming Directives` for similar directives.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: mapResponseEntity
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
.. _-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
|
||||
:snippet: mapResponseHeaders
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``mapResponseHeaders`` directive is used as a building block for :ref:`Custom Directives` to transform the list of
|
||||
response headers that was generated by the inner route.
|
||||
|
||||
See :ref:`Response Transforming Directives` for similar directives.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: mapResponseHeaders
|
||||
|
|
@ -0,0 +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
|
||||
: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`).
|
||||
|
||||
See :ref:`Result Transformation Directives` for similar directives.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: 0mapRouteResult
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
.. _-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
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
.. _-pass-:
|
||||
|
||||
pass
|
||||
====
|
||||
|
||||
A directive that passes the request unchanged to its inner route.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala
|
||||
:snippet: pass
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The directive is usually used as a "neutral element" when combining directives generically.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: pass
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
.. _-provide-:
|
||||
|
||||
provide
|
||||
=======
|
||||
|
||||
Provides a constant value to the inner route.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala
|
||||
:snippet: provide
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The `provide` directive is used as a building block for :ref:`Custom Directives` to provide a single value to the
|
||||
inner route. To provide several values use the :ref:`-tprovide-` directive.
|
||||
|
||||
See :ref:`ProvideDirectives` for an overview of similar directives.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: 0provide
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
.. _-textract-:
|
||||
|
||||
textract
|
||||
========
|
||||
|
||||
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
|
||||
:snippet: textract
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``textract`` directive is used as a building block for :ref:`Custom Directives` to extract data from the
|
||||
``RequestContext`` and provide it to the inner route. To extract just one value use the :ref:`-extract-` directive. To
|
||||
provide a constant value independent of the ``RequestContext`` use the :ref:`-tprovide-` directive instead.
|
||||
|
||||
See :ref:`ProvideDirectives` for an overview of similar directives.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: textract
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
.. _-tprovide-:
|
||||
|
||||
tprovide
|
||||
========
|
||||
|
||||
Provides an HList of values to the inner route.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/BasicDirectives.scala
|
||||
:snippet: tprovide
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``tprovide`` directive is used as a building block for :ref:`Custom Directives` to provide data to the inner route.
|
||||
To provide just one value use the :ref:`-provide-` directive. If you want to provide values calculated from the
|
||||
``RequestContext`` use the :ref:`-textract-` directive instead.
|
||||
|
||||
See :ref:`ProvideDirectives` for an overview of similar directives.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/BasicDirectivesExamplesSpec.scala
|
||||
:snippet: tprovide
|
||||
106
akka-docs-dev/rst/scala/http/directives/by-trait.rst
Normal file
106
akka-docs-dev/rst/scala/http/directives/by-trait.rst
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
Predefined Directives (by trait)
|
||||
================================
|
||||
|
||||
All predefined directives are organized into traits that form one part of the overarching ``Directives`` trait.
|
||||
|
||||
.. _Request Directives:
|
||||
|
||||
Directives filtering or extracting from the request
|
||||
---------------------------------------------------
|
||||
|
||||
:ref:`MethodDirectives`
|
||||
Filter and extract based on the request method.
|
||||
|
||||
:ref:`HeaderDirectives`
|
||||
Filter and extract based on request headers.
|
||||
|
||||
:ref:`PathDirectives`
|
||||
Filter and extract from the request URI path.
|
||||
|
||||
:ref:`HostDirectives`
|
||||
Filter and extract based on the target host.
|
||||
|
||||
:ref:`ParameterDirectives`, :ref:`FormFieldDirectives`
|
||||
Filter and extract based on query parameters or form fields.
|
||||
|
||||
:ref:`CodingDirectives`
|
||||
Filter and decode compressed request content.
|
||||
|
||||
:ref:`MarshallingDirectives`
|
||||
Extract the request entity.
|
||||
|
||||
:ref:`SchemeDirectives`
|
||||
Filter and extract based on the request scheme.
|
||||
|
||||
:ref:`SecurityDirectives`
|
||||
Handle authentication data from the request.
|
||||
|
||||
:ref:`CookieDirectives`
|
||||
Filter and extract cookies.
|
||||
|
||||
:ref:`BasicDirectives` and :ref:`MiscDirectives`
|
||||
Directives handling request properties.
|
||||
|
||||
|
||||
.. _Response Directives:
|
||||
|
||||
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.
|
||||
|
||||
:ref:`CodingDirectives`
|
||||
Compress responses.
|
||||
|
||||
:ref:`FileAndResourceDirectives`
|
||||
Deliver responses from files and resources.
|
||||
|
||||
:ref:`RangeDirectives`
|
||||
Support for range requests (``206 Partial Content`` responses).
|
||||
|
||||
:ref:`RespondWithDirectives`
|
||||
Change response properties.
|
||||
|
||||
:ref:`RouteDirectives`
|
||||
Complete or reject a request with a response.
|
||||
|
||||
:ref:`BasicDirectives` and :ref:`MiscDirectives`
|
||||
Directives handling or transforming response properties.
|
||||
|
||||
|
||||
List of predefined directives by trait
|
||||
--------------------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
basic-directives/index
|
||||
cache-condition-directives/index
|
||||
caching-directives/index
|
||||
chunking-directives/index
|
||||
coding-directives/index
|
||||
cookie-directives/index
|
||||
debugging-directives/index
|
||||
execution-directives/index
|
||||
file-and-resource-directives/index
|
||||
form-field-directives/index
|
||||
future-directives/index
|
||||
header-directives/index
|
||||
host-directives/index
|
||||
marshalling-directives/index
|
||||
method-directives/index
|
||||
misc-directives/index
|
||||
parameter-directives/index
|
||||
path-directives/index
|
||||
range-directives/index
|
||||
respond-with-directives/index
|
||||
route-directives/index
|
||||
scheme-directives/index
|
||||
security-directives/index
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
.. _-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
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
.. _-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
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
.. _-decodeRequest-:
|
||||
|
||||
decodeRequest
|
||||
=============
|
||||
|
||||
Tries to decode the request with the specified ``Decoder`` or rejects the request with an
|
||||
``UnacceptedRequestEncodingRejection(supportedEncoding)``.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala
|
||||
:snippet: decodeRequest
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``decodeRequest`` directive is the building block for the ``decompressRequest`` directive.
|
||||
|
||||
``decodeRequest`` and ``decompressRequest`` are related like this::
|
||||
|
||||
decompressRequest(Gzip) = decodeRequest(Gzip)
|
||||
decompressRequest(a, b, c) = decodeRequest(a) | decodeRequest(b) | decodeRequest(c)
|
||||
decompressRequest() = decodeRequest(Gzip) | decodeRequest(Deflate) | decodeRequest(NoEncoding)
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala
|
||||
:snippet: decodeRequest
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
.. _-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
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
.. _-encodeResponse-:
|
||||
|
||||
encodeResponse
|
||||
==============
|
||||
|
||||
Tries to encode the response with the specified ``Encoder`` or rejects the request with an
|
||||
``UnacceptedResponseEncodingRejection(supportedEncodings)``.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala
|
||||
:snippet: encodeResponse
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The directive automatically applies the ``autoChunkFileBytes`` directive as well to avoid having to load
|
||||
an entire file into JVM heap.
|
||||
|
||||
The parameter to the directive is either just an ``Encoder`` or all of an ``Encoder``, a threshold, and a
|
||||
chunk size to configure the automatically applied ``autoChunkFileBytes`` directive.
|
||||
|
||||
The ``encodeResponse`` directive is the building block for the ``compressResponse`` and
|
||||
``compressResponseIfRequested`` directives.
|
||||
|
||||
``encodeResponse``, ``compressResponse``, and ``compressResponseIfRequested`` are related like this::
|
||||
|
||||
compressResponse(Gzip) = encodeResponse(Gzip)
|
||||
compressResponse(a, b, c) = encodeResponse(a) | encodeResponse(b) | encodeResponse(c)
|
||||
compressResponse() = encodeResponse(Gzip) | encodeResponse(Deflate) | encodeResponse(NoEncoding)
|
||||
compressResponseIfRequested() = encodeResponse(NoEncoding) | encodeResponse(Gzip) | encodeResponse(Deflate)
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/CodingDirectivesExamplesSpec.scala
|
||||
:snippet: encodeResponse
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
.. _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
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
.. _-requestEncodedWith-:
|
||||
|
||||
requestEncodedWith
|
||||
==================
|
||||
|
||||
Passes the request to the inner route if the request is encoded with the argument encoding. Otherwise,
|
||||
rejects the request with an ``UnacceptedRequestEncodingRejection(encoding)``.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala
|
||||
:snippet: requestEncodedWith
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive is the building block for ``decodeRequest`` to reject unsupported encodings.
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
.. _-responseEncodingAccepted-:
|
||||
|
||||
responseEncodingAccepted
|
||||
========================
|
||||
|
||||
Passes the request to the inner route if the request accepts the argument encoding. Otherwise,
|
||||
rejects the request with an ``UnacceptedResponseEncodingRejection(encoding)``.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CodingDirectives.scala
|
||||
:snippet: responseEncodingAccepted
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive is the building block for ``encodeResponse`` to reject unsupported encodings.
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
.. _-cookie-:
|
||||
|
||||
cookie
|
||||
======
|
||||
|
||||
Extracts a cookie with a given name from a request or otherwise rejects the request with a ``MissingCookieRejection`` if
|
||||
the cookie is missing.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CookieDirectives.scala
|
||||
:snippet: cookie
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Use the :ref:`-optionalCookie-` directive instead if you want to support missing cookies in your inner route.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala
|
||||
:snippet: cookie
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
.. _-deleteCookie-:
|
||||
|
||||
deleteCookie
|
||||
============
|
||||
|
||||
Adds a header to the response to request the removal of the cookie with the given name on the client.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CookieDirectives.scala
|
||||
:snippet: deleteCookie
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Use the :ref:`-setCookie-` directive to update a cookie.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala
|
||||
:snippet: deleteCookie
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
.. _CookieDirectives:
|
||||
|
||||
CookieDirectives
|
||||
================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
cookie
|
||||
deleteCookie
|
||||
optionalCookie
|
||||
setCookie
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.. _-optionalCookie-:
|
||||
|
||||
optionalCookie
|
||||
==============
|
||||
|
||||
Extracts an optional cookie with a given name from a request.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CookieDirectives.scala
|
||||
:snippet: optionalCookie
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Use the :ref:`-cookie-` directive instead if the inner route does not handle a missing cookie.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala
|
||||
:snippet: optionalCookie
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.. _-setCookie-:
|
||||
|
||||
setCookie
|
||||
=========
|
||||
|
||||
Adds a header to the response to request the update of the cookie with the given name on the client.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/CookieDirectives.scala
|
||||
:snippet: setCookie
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Use the :ref:`-deleteCookie-` directive to delete a cookie.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/CookieDirectivesExamplesSpec.scala
|
||||
:snippet: setCookie
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
.. _DebuggingDirectives:
|
||||
|
||||
DebuggingDirectives
|
||||
===================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
logRequest
|
||||
logRequestResult
|
||||
logResult
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
.. _-logRequest-:
|
||||
|
||||
logRequest
|
||||
==========
|
||||
|
||||
Logs the request.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
::
|
||||
|
||||
def logRequest(marker: String)(implicit log: LoggingContext): Directive0
|
||||
def logRequest(marker: String, level: LogLevel)(implicit log: LoggingContext): Directive0
|
||||
def logRequest(show: HttpRequest => String)(implicit log: LoggingContext): Directive0
|
||||
def logRequest(show: HttpRequest => LogEntry)(implicit log: LoggingContext): Directive0
|
||||
def logRequest(magnet: LoggingMagnet[HttpRequest => Unit])(implicit log: LoggingContext): Directive0
|
||||
|
||||
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
|
||||
-----------
|
||||
|
||||
Logs the request using the supplied ``LoggingMagnet[HttpRequest => Unit]``. This ``LoggingMagnet`` is a wrapped
|
||||
function ``HttpRequest => Unit`` that can be implicitly created from the different constructors shown above. These
|
||||
constructors build a ``LoggingMagnet`` from these components:
|
||||
|
||||
* A marker to prefix each log message with.
|
||||
* A log level.
|
||||
* A ``show`` function that calculates a string representation for a request.
|
||||
* An implicit ``LoggingContext`` that is used to emit the log message.
|
||||
* A function that creates a ``LogEntry`` which is a combination of the elements above.
|
||||
|
||||
It is also possible to use any other function ``HttpRequest => Unit`` for logging by wrapping it with ``LoggingMagnet``.
|
||||
See the examples for ways to use the ``logRequest`` directive.
|
||||
|
||||
Use ``logResult`` for logging the response, or ``logRequestResult`` for logging both.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/DebuggingDirectivesExamplesSpec.scala
|
||||
:snippet: logRequest-0
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
.. _-logRequestResult-:
|
||||
|
||||
logRequestResult
|
||||
==================
|
||||
|
||||
Logs request and response.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
::
|
||||
|
||||
def logRequestResult(marker: String)(implicit log: LoggingContext): Directive0
|
||||
def logRequestResult(marker: String, level: LogLevel)(implicit log: LoggingContext): Directive0
|
||||
def logRequestResult(show: HttpRequest ⇒ HttpResponsePart ⇒ Option[LogEntry])
|
||||
(implicit log: LoggingContext): Directive0
|
||||
def logRequestResult(show: HttpRequest ⇒ Any ⇒ Option[LogEntry])(implicit log: LoggingContext): Directive0
|
||||
|
||||
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
|
||||
-----------
|
||||
|
||||
This directive is a combination of ``logRequest`` and ``logResult``. See ``logRequest`` for the general description
|
||||
how these directives work.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/DebuggingDirectivesExamplesSpec.scala
|
||||
:snippet: logRequestResult
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
.. _-logResult-:
|
||||
|
||||
logResult
|
||||
===========
|
||||
|
||||
Logs the response.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
::
|
||||
|
||||
def logResult(marker: String)(implicit log: LoggingContext): Directive0
|
||||
def logResult(marker: String, level: LogLevel)(implicit log: LoggingContext): Directive0
|
||||
def logResult(show: Any => String)(implicit log: LoggingContext): Directive0
|
||||
def logResult(show: Any => LogEntry)(implicit log: LoggingContext): Directive0
|
||||
def logResult(magnet: LoggingMagnet[Any => Unit])(implicit log: LoggingContext): Directive0
|
||||
|
||||
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
|
||||
-----------
|
||||
|
||||
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).
|
||||
|
||||
Use ``logRequest`` for logging the request, or ``logRequestResult`` for logging both.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/DebuggingDirectivesExamplesSpec.scala
|
||||
:snippet: logResult
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
.. _-handleExceptions-:
|
||||
|
||||
handleExceptions
|
||||
================
|
||||
|
||||
Catches exceptions thrown by the inner route and handles them using the specified ``ExceptionHandler``.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/ExecutionDirectives.scala
|
||||
:snippet: handleExceptions
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Using this directive is an alternative to using a global implicitly defined ``ExceptionHandler`` that
|
||||
applies to the complete route.
|
||||
|
||||
See :ref:`Exception Handling` for general information about options for handling exceptions.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/ExecutionDirectivesExamplesSpec.scala
|
||||
:snippet: handleExceptions
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
.. _-handleRejections-:
|
||||
|
||||
handleRejections
|
||||
================
|
||||
|
||||
Handles rejections produced by the inner route and handles them using the specified ``RejectionHandler``.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/ExecutionDirectives.scala
|
||||
:snippet: handleRejections
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
Using this directive is an alternative to using a global implicitly defined ``RejectionHandler`` that
|
||||
applies to the complete route.
|
||||
|
||||
See :ref:`Rejections` for general information about options for handling rejections.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/ExecutionDirectivesExamplesSpec.scala
|
||||
:snippet: handleRejections
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
.. _ExecutionDirectives:
|
||||
|
||||
ExecutionDirectives
|
||||
===================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
handleExceptions
|
||||
handleRejections
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
.. _-getFromBrowseableDirectories-:
|
||||
|
||||
getFromBrowseableDirectories
|
||||
============================
|
||||
|
||||
Serves the content of the given directories as a file system browser, i.e. files are sent and directories
|
||||
served as browsable listings.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala
|
||||
:snippet: getFromBrowseableDirectories
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``getFromBrowseableDirectories`` is a combination of serving files from the specified directories (like
|
||||
``getFromDirectory``) and listing a browseable directory with ``listDirectoryContents``. Nesting this directive beneath
|
||||
``get`` is not necessary as this directive will only respond to ``GET`` requests.
|
||||
|
||||
Use ``getFromBrowseableDirectory`` to serve only one directory. Use ``getFromDirectory`` if directory browsing isn't
|
||||
required.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
.. _-getFromBrowseableDirectory-:
|
||||
|
||||
getFromBrowseableDirectory
|
||||
==========================
|
||||
|
||||
The single-directory variant of :ref:`-getFromBrowseableDirectories-`.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala
|
||||
:snippet: getFromBrowseableDirectory
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
.. _-getFromDirectory-:
|
||||
|
||||
getFromDirectory
|
||||
================
|
||||
|
||||
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
|
||||
:snippet: getFromDirectory
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``unmatchedPath`` of the ``RequestContext`` is first transformed by the given ``pathRewriter`` function before being
|
||||
appended to the given directory name to build the final file name.
|
||||
|
||||
The actual I/O operation is running detached in a `Future`, so it doesn't block the current thread. If the file cannot
|
||||
be read the route rejects the request.
|
||||
|
||||
To serve a single file use ``getFromFile``. To serve browsable directory listings use ``getFromBrowseableDirectories``.
|
||||
To serve files from a classpath directory use ``getFromResourceDirectory`` instead.
|
||||
|
||||
Note that it's not required to wrap this directive with ``get`` as this directive will only respond to ``GET`` requests.
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
.. _-getFromFile-:
|
||||
|
||||
getFromFile
|
||||
===========
|
||||
|
||||
Completes GET requests with the content of the given file.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala
|
||||
:snippet: getFromFile
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The actual I/O operation is running detached in a `Future`, so it doesn't block the current thread (but potentially
|
||||
some other thread !). If the file cannot be found or read the request is rejected.
|
||||
|
||||
To serve files from a directory use ``getFromDirectory``, instead. To serve a file from a classpath resource
|
||||
use ``getFromResource`` instead.
|
||||
|
||||
Note that it's not required to wrap this directive with ``get`` as this directive will only respond to ``GET`` requests.
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
.. _-getFromResource-:
|
||||
|
||||
getFromResource
|
||||
===============
|
||||
|
||||
Completes GET requests with the content of the given classpath resource.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala
|
||||
:snippet: getFromResource
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The actual I/O operation is running detached in a `Future`, so it doesn't block the current thread (but potentially
|
||||
some other thread !). If the file cannot be found or read the request is rejected.
|
||||
|
||||
To serve files from a classpath directory use ``getFromResourceDirectory`` instead. To serve files from a filesystem
|
||||
directory use ``getFromDirectory``, instead.
|
||||
|
||||
Note that it's not required to wrap this directive with ``get`` as this directive will only respond to ``GET`` requests.
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
.. _-getFromResourceDirectory-:
|
||||
|
||||
getFromResourceDirectory
|
||||
========================
|
||||
|
||||
Completes GET requests with the content of the given classpath resource directory.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala
|
||||
:snippet: getFromResourceDirectory
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The actual I/O operation is running detached in a `Future`, so it doesn't block the current thread (but potentially
|
||||
some other thread !). If the file cannot be found or read the request is rejected.
|
||||
|
||||
To serve a single resource use ``getFromResource``, instead. To server files from a filesystem directory use
|
||||
``getFromDirectory`` instead.
|
||||
|
||||
Note that it's not required to wrap this directive with ``get`` as this directive will only respond to ``GET`` requests.
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.. _FileAndResourceDirectives:
|
||||
|
||||
FileAndResourceDirectives
|
||||
=========================
|
||||
|
||||
Like the :ref:`RouteDirectives` the ``FileAndResourceDirectives`` are somewhat special in spray's routing DSL.
|
||||
Contrary to all other directives they do not produce instances of type ``Directive[L <: HList]`` but rather "plain"
|
||||
routes of type ``Route``.
|
||||
The reason is that they 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 actual route structure **leaves**.
|
||||
|
||||
So in most cases the inner-most element of a route structure branch is one of the :ref:`RouteDirectives` or
|
||||
``FileAndResourceDirectives``.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
getFromBrowseableDirectories
|
||||
getFromBrowseableDirectory
|
||||
getFromDirectory
|
||||
getFromFile
|
||||
getFromResource
|
||||
getFromResourceDirectory
|
||||
listDirectoryContents
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.. _-listDirectoryContents-:
|
||||
|
||||
listDirectoryContents
|
||||
=====================
|
||||
|
||||
Completes GET requests with a unified listing of the contents of all given directories. The actual rendering of the
|
||||
directory contents is performed by the in-scope `Marshaller[DirectoryListing]`.
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/FileAndResourceDirectives.scala
|
||||
:snippet: listDirectoryContents
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ``listDirectoryContents`` directive renders a response only for directories. To just serve files use
|
||||
``getFromDirectory``. To serve files and provide a browseable directory listing use ``getFromBrowsableDirectories``
|
||||
instead.
|
||||
|
||||
The rendering can be overridden by providing a custom ``Marshaller[DirectoryListing]``.
|
||||
|
||||
Note that it's not required to wrap this directive with ``get`` as this directive will only respond to ``GET`` requests.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
.. _PathDirectives:
|
||||
|
||||
PathDirectives
|
||||
==============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
path
|
||||
pathEnd
|
||||
pathEndOrSingleSlash
|
||||
pathPrefix
|
||||
pathPrefixTest
|
||||
pathSingleSlash
|
||||
pathSuffix
|
||||
pathSuffixTest
|
||||
rawPathPrefix
|
||||
rawPathPrefixTest
|
||||
|
||||
../../path-matchers
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
.. _-path-:
|
||||
|
||||
path
|
||||
====
|
||||
|
||||
Matches the complete unmatched path of the ``RequestContext`` against the given ``PathMatcher``, potentially extracts
|
||||
one or more values (depending on the type of the argument).
|
||||
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala
|
||||
:snippet: path
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive filters incoming requests based on the part of their URI that hasn't been matched yet by other
|
||||
potentially existing :ref:`-pathPrefix-` directives on higher levels of the routing structure.
|
||||
Its one parameter is usually an expression evaluating to a ``PathMatcher`` instance (see also: :ref:`pathmatcher-dsl`).
|
||||
|
||||
As opposed to the :ref:`-rawPathPrefix-` or :ref:`-rawPathPrefixTest-` directives ``path`` automatically adds a leading
|
||||
slash to its ``PathMatcher`` argument, you therefore don't have to start your matching expression with an explicit slash.
|
||||
|
||||
The ``path`` directive attempts to match the **complete** remaining path, not just a prefix. If you only want to match
|
||||
a path prefix and then delegate further filtering to a lower level in your routing structure use the :ref:`-pathPrefix-`
|
||||
directive instead. As a consequence it doesn't make sense to nest a ``path`` or :ref:`-pathPrefix-` directive
|
||||
underneath another ``path`` directive, as there is no way that they will ever match (since the unmatched path underneath
|
||||
a ``path`` directive will always be empty).
|
||||
|
||||
Depending on the type of its ``PathMatcher`` argument the ``path`` directive extracts zero or more values from the URI.
|
||||
If the match fails the request is rejected with an :ref:`empty rejection set <empty rejections>`.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: path-example
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
.. _-pathEnd-:
|
||||
|
||||
pathEnd
|
||||
=======
|
||||
|
||||
Only passes the request to its inner route if the unmatched path of the ``RequestContext`` is empty, i.e. the request
|
||||
path has been fully matched by a higher-level :ref:`-path-` or :ref:`-pathPrefix-` directive.
|
||||
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala
|
||||
:snippet: pathEnd
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive is a simple alias for ``rawPathPrefix(PathEnd)`` and is mostly used on an
|
||||
inner-level to discriminate "path already fully matched" from other alternatives (see the example below).
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: pathEnd-
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
.. _-pathEndOrSingleSlash-:
|
||||
|
||||
pathEndOrSingleSlash
|
||||
====================
|
||||
|
||||
Only passes the request to its inner route if the unmatched path of the ``RequestContext`` is either empty
|
||||
or contains only one single slash.
|
||||
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala
|
||||
:snippet: pathEndOrSingleSlash
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive is a simple alias for ``rawPathPrefix(Slash.? ~ PathEnd)`` and is mostly used on an inner-level to
|
||||
discriminate "path already fully matched" from other alternatives (see the example below).
|
||||
|
||||
It is equivalent to ``pathEnd | pathSingleSlash`` but slightly more efficient.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: pathEndOrSingleSlash-
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
.. _-pathPrefix-:
|
||||
|
||||
pathPrefix
|
||||
==========
|
||||
|
||||
Matches and consumes a prefix of the unmatched path of the ``RequestContext`` against the given ``PathMatcher``,
|
||||
potentially extracts one or more values (depending on the type of the argument).
|
||||
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala
|
||||
:snippet: pathPrefix
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive filters incoming requests based on the part of their URI that hasn't been matched yet by other
|
||||
potentially existing ``pathPrefix`` or :ref:`-rawPathPrefix-` directives on higher levels of the routing structure.
|
||||
Its one parameter is usually an expression evaluating to a ``PathMatcher`` instance (see also: :ref:`pathmatcher-dsl`).
|
||||
|
||||
As opposed to its :ref:`-rawPathPrefix-` counterpart ``pathPrefix`` automatically adds a leading slash to its
|
||||
``PathMatcher`` argument, you therefore don't have to start your matching expression with an explicit slash.
|
||||
|
||||
Depending on the type of its ``PathMatcher`` argument the ``pathPrefix`` directive extracts zero or more values from
|
||||
the URI. If the match fails the request is rejected with an :ref:`empty rejection set <empty rejections>`.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: pathPrefix-
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
.. _-pathPrefixTest-:
|
||||
|
||||
pathPrefixTest
|
||||
==============
|
||||
|
||||
Checks whether the unmatched path of the ``RequestContext`` has a prefix matched by the given ``PathMatcher``.
|
||||
Potentially extracts one or more values (depending on the type of the argument) but doesn't consume its match from
|
||||
the unmatched path.
|
||||
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala
|
||||
:snippet: pathPrefixTest
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive is very similar to the :ref:`-pathPrefix-` directive with the one difference that the path prefix
|
||||
it matched (if it matched) is *not* consumed. The unmatched path of the ``RequestContext`` is therefore left as
|
||||
is even in the case that the directive successfully matched and the request is passed on to its inner route.
|
||||
|
||||
For more info on how to create a ``PathMatcher`` see :ref:`pathmatcher-dsl`.
|
||||
|
||||
As opposed to its :ref:`-rawPathPrefixTest-` counterpart ``pathPrefixTest`` automatically adds a leading slash to its
|
||||
``PathMatcher`` argument, you therefore don't have to start your matching expression with an explicit slash.
|
||||
|
||||
Depending on the type of its ``PathMatcher`` argument the ``pathPrefixTest`` directive extracts zero or more values from
|
||||
the URI. If the match fails the request is rejected with an :ref:`empty rejection set <empty rejections>`.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: pathPrefixTest-
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
.. _-pathSingleSlash-:
|
||||
|
||||
pathSingleSlash
|
||||
===============
|
||||
|
||||
Only passes the request to its inner route if the unmatched path of the ``RequestContext``
|
||||
contains exactly one single slash.
|
||||
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala
|
||||
:snippet: pathSingleSlash
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive is a simple alias for ``pathPrefix(PathEnd)`` and is mostly used for matching requests to the root URI
|
||||
(``/``) on an inner-level to discriminate "all path segments matched" from other alternatives (see the example below).
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: pathSingleSlash-
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
.. _-pathSuffix-:
|
||||
|
||||
pathSuffix
|
||||
==========
|
||||
|
||||
Matches and consumes a suffix of the unmatched path of the ``RequestContext`` against the given ``PathMatcher``,
|
||||
potentially extracts one or more values (depending on the type of the argument).
|
||||
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala
|
||||
:snippet: pathSuffix
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive filters incoming requests based on the part of their URI that hasn't been matched yet by other
|
||||
potentially existing path matching directives on higher levels of the routing structure.
|
||||
Its one parameter is usually an expression evaluating to a ``PathMatcher`` instance (see also: :ref:`pathmatcher-dsl`).
|
||||
|
||||
As opposed to :ref:`-pathPrefix-` this directive matches and consumes the unmatched path from the right, i.e. the end.
|
||||
|
||||
.. caution:: For efficiency reasons, the given ``PathMatcher`` must match the desired suffix in reversed-segment
|
||||
order, i.e. ``pathSuffix("baz" / "bar")`` would match ``/foo/bar/baz``! The order within a segment match is
|
||||
not reversed.
|
||||
|
||||
Depending on the type of its ``PathMatcher`` argument the ``pathPrefix`` directive extracts zero or more values from
|
||||
the URI. If the match fails the request is rejected with an :ref:`empty rejection set <empty rejections>`.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: pathSuffix-
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
.. _-pathSuffixTest-:
|
||||
|
||||
pathSuffixTest
|
||||
==============
|
||||
|
||||
Checks whether the unmatched path of the ``RequestContext`` has a suffix matched by the given ``PathMatcher``.
|
||||
Potentially extracts one or more values (depending on the type of the argument) but doesn't consume its match from
|
||||
the unmatched path.
|
||||
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala
|
||||
:snippet: pathSuffixTest
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive is very similar to the :ref:`-pathSuffix-` directive with the one difference that the path suffix
|
||||
it matched (if it matched) is *not* consumed. The unmatched path of the ``RequestContext`` is therefore left as
|
||||
is even in the case that the directive successfully matched and the request is passed on to its inner route.
|
||||
|
||||
As opposed to :ref:`-pathPrefixTest-` this directive matches and consumes the unmatched path from the right, i.e. the end.
|
||||
|
||||
.. caution:: For efficiency reasons, the given ``PathMatcher`` must match the desired suffix in reversed-segment
|
||||
order, i.e. ``pathSuffixTest("baz" / "bar")`` would match ``/foo/bar/baz``! The order within a segment match is
|
||||
not reversed.
|
||||
|
||||
Depending on the type of its ``PathMatcher`` argument the ``pathSuffixTest`` directive extracts zero or more values from
|
||||
the URI. If the match fails the request is rejected with an :ref:`empty rejection set <empty rejections>`.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: pathSuffixTest-
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
.. _-rawPathPrefix-:
|
||||
|
||||
rawPathPrefix
|
||||
=============
|
||||
|
||||
Matches and consumes a prefix of the unmatched path of the ``RequestContext`` against the given ``PathMatcher``,
|
||||
potentially extracts one or more values (depending on the type of the argument).
|
||||
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala
|
||||
:snippet: rawPathPrefix
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive filters incoming requests based on the part of their URI that hasn't been matched yet by other
|
||||
potentially existing ``rawPathPrefix`` or :ref:`-pathPrefix-` directives on higher levels of the routing structure.
|
||||
Its one parameter is usually an expression evaluating to a ``PathMatcher`` instance (see also: :ref:`pathmatcher-dsl`).
|
||||
|
||||
As opposed to its :ref:`-pathPrefix-` counterpart ``rawPathPrefix`` does *not* automatically add a leading slash to its
|
||||
``PathMatcher`` argument. Rather its ``PathMatcher`` argument is applied to the unmatched path as is.
|
||||
|
||||
Depending on the type of its ``PathMatcher`` argument the ``rawPathPrefix`` directive extracts zero or more values from
|
||||
the URI. If the match fails the request is rejected with an :ref:`empty rejection set <empty rejections>`.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: rawPathPrefix-
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
.. _-rawPathPrefixTest-:
|
||||
|
||||
rawPathPrefixTest
|
||||
=================
|
||||
|
||||
Checks whether the unmatched path of the ``RequestContext`` has a prefix matched by the given ``PathMatcher``.
|
||||
Potentially extracts one or more values (depending on the type of the argument) but doesn't consume its match from
|
||||
the unmatched path.
|
||||
|
||||
|
||||
Signature
|
||||
---------
|
||||
|
||||
.. includecode2:: /../../akka-http/src/main/scala/akka/http/server/directives/PathDirectives.scala
|
||||
:snippet: rawPathPrefixTest
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This directive is very similar to the :ref:`-pathPrefix-` directive with the one difference that the path prefix
|
||||
it matched (if it matched) is *not* consumed. The unmatched path of the ``RequestContext`` is therefore left as
|
||||
is even in the case that the directive successfully matched and the request is passed on to its inner route.
|
||||
|
||||
For more info on how to create a ``PathMatcher`` see :ref:`pathmatcher-dsl`.
|
||||
|
||||
As opposed to its :ref:`-pathPrefixTest-` counterpart ``rawPathPrefixTest`` does *not* automatically add a leading slash
|
||||
to its ``PathMatcher`` argument. Rather its ``PathMatcher`` argument is applied to the unmatched path as is.
|
||||
|
||||
Depending on the type of its ``PathMatcher`` argument the ``rawPathPrefixTest`` directive extracts zero or more values
|
||||
from the URI. If the match fails the request is rejected with an :ref:`empty rejection set <empty rejections>`.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. includecode2:: ../../../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: rawPathPrefixTest-
|
||||
31
akka-docs-dev/rst/scala/http/exception-handling.rst
Normal file
31
akka-docs-dev/rst/scala/http/exception-handling.rst
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
.. _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
|
||||
|
|
@ -6,9 +6,12 @@ High-level HTTP API
|
|||
|
||||
quick-start
|
||||
routing
|
||||
directives
|
||||
rejections
|
||||
exception-handling
|
||||
path-matchers
|
||||
marshalling
|
||||
custom-directives
|
||||
predefined-directives-alphabetically
|
||||
predefined-directives-by-trait
|
||||
directives/alphabetically
|
||||
directives/by-trait
|
||||
|
||||
|
||||
|
|
|
|||
200
akka-docs-dev/rst/scala/http/path-matchers.rst
Normal file
200
akka-docs-dev/rst/scala/http/path-matchers.rst
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
.. _pathmatcher-dsl:
|
||||
|
||||
The PathMatcher DSL
|
||||
===================
|
||||
|
||||
For being able to work with the :ref:`PathDirectives` effectively you should have some understanding of the
|
||||
``PathMatcher`` mini-DSL that Akka HTTP provides for elegantly defining URI matching behavior.
|
||||
|
||||
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.
|
||||
|
||||
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::
|
||||
|
||||
trait PathMatcher[L: Tuple]
|
||||
type PathMatcher0 = PathMatcher[Unit]
|
||||
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).
|
||||
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
|
||||
:snippet: path-matcher
|
||||
|
||||
This will match paths like ``foo/bar/X42/edit`` or ``foo/bar/X/create``.
|
||||
|
||||
.. note:: The path matching DSL describes what paths to accept **after** URL decoding. This is why the path-separating
|
||||
slashes have special status and cannot simply be specified as part of a string! The string "foo/bar" would match
|
||||
the raw URI path "foo%2Fbar", which is most likely not what you want!
|
||||
|
||||
|
||||
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``
|
||||
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``
|
||||
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]``
|
||||
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``
|
||||
Matches exactly one path-separating slash (``/``) character and extracts nothing.
|
||||
|
||||
``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``
|
||||
Matches the very end of the path, similar to ``$`` in regular expressions and extracts nothing.
|
||||
|
||||
``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]``
|
||||
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``.
|
||||
|
||||
``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``.
|
||||
|
||||
``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]``
|
||||
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]``
|
||||
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]``
|
||||
Matches and extracts a ``java.util.UUID`` instance.
|
||||
|
||||
``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]]``
|
||||
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``
|
||||
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]``
|
||||
Always matches, consumes nothing and extracts the given ``TupleX`` of values.
|
||||
|
||||
``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.
|
||||
|
||||
|
||||
Combinators
|
||||
-----------
|
||||
|
||||
Path matchers can be combined with these combinators to form higher-level constructs:
|
||||
|
||||
Tilde Operator (``~``)
|
||||
The tilde is the most basic combinator. It simply concatenates two matchers into one, i.e if the first one matched
|
||||
(and consumed) the second one is tried. The extractions of both matchers are combined type-safely.
|
||||
For example: ``"foo" ~ "bar"`` yields a matcher that is identical to ``"foobar"``.
|
||||
|
||||
Slash Operator (``/``)
|
||||
This operator concatenates two matchers and inserts a ``Slash`` matcher in between them.
|
||||
For example: ``"foo" / "bar"`` is identical to ``"foo" ~ Slash ~ "bar"``.
|
||||
|
||||
Pipe Operator (``|``)
|
||||
This operator combines two matcher alternatives in that the second one is only tried if the first one did *not* match.
|
||||
The two sub-matchers must have compatible types.
|
||||
For example: ``"foo" | "bar"`` will match either "foo" *or* "bar".
|
||||
|
||||
|
||||
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
|
||||
=========================== =============================
|
||||
``PathMatcher0`` ``PathMatcher0``
|
||||
``PathMatcher1[T]`` ``PathMatcher1[Option[T]``
|
||||
``PathMatcher[L: Tuple]`` ``PathMatcher[Option[L]]``
|
||||
=========================== =============================
|
||||
|
||||
|
||||
``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
|
||||
=========================== =======================================
|
||||
``PathMatcher0`` ``PathMatcher0``
|
||||
``PathMatcher1[T]`` ``PathMatcher1[List[T]``
|
||||
``PathMatcher[L: Tuple]`` ``PathMatcher[List[L]]``
|
||||
=========================== =======================================
|
||||
|
||||
|
||||
``unary_!``
|
||||
By prefixing a matcher with ``!`` it can be turned into a ``PathMatcher0`` that only matches if the underlying matcher
|
||||
does *not* match and vice versa.
|
||||
|
||||
|
||||
``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
|
||||
how to use them.
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. includecode2:: ../code/docs/http/server/directives/PathDirectivesExamplesSpec.scala
|
||||
:snippet: path-dsl
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
Predefined Directives (alphabetically)
|
||||
======================================
|
||||
|
||||
(todo)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
Predefined Directives (by trait)
|
||||
================================
|
||||
|
||||
(todo)
|
||||
100
akka-docs-dev/rst/scala/http/rejections.rst
Normal file
100
akka-docs-dev/rst/scala/http/rejections.rst
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
.. _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 <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.
|
||||
|
|
@ -1,6 +1,105 @@
|
|||
.. _http-routing-scala:
|
||||
|
||||
Routing DSL
|
||||
===========
|
||||
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::
|
||||
|
||||
type Route = RequestContext ⇒ Future[RouteResult]
|
||||
|
||||
It's a simple alias for a function taking a ``RequestContext`` as parameter and returning 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(...)``
|
||||
- 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
|
||||
|
||||
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 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.
|
||||
|
||||
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 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.
|
||||
:ref:`Directives` deliver most of Akka HTTP's power and flexibility.
|
||||
|
||||
.. _The Routing Tree:
|
||||
|
||||
The Routing Tree
|
||||
----------------
|
||||
|
||||
Essentially, when you combine directives and custom routes via nesting and the ``~`` operator, you build a routing
|
||||
structure that forms a tree. When a request comes in it is injected into this tree at the root and flows down through
|
||||
all the branches in a depth-first manner until either some node completes it or it is fully rejected.
|
||||
|
||||
Consider this schematic example::
|
||||
|
||||
val route =
|
||||
a {
|
||||
b {
|
||||
c {
|
||||
... // route 1
|
||||
} ~
|
||||
d {
|
||||
... // route 2
|
||||
} ~
|
||||
... // route 3
|
||||
} ~
|
||||
e {
|
||||
... // route 4
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
(todo)
|
||||
Loading…
Add table
Add a link
Reference in a new issue