Professional Documents
Culture Documents
INTRO
val requestHandler: HttpRequest => HttpResponse = { val asyncRequestHandler: HttpRequest => Future[HttpResponse] ={
case HttpRequest(_, _, _, _, _) => case HttpRequest(_, _, _, _, _) =>
HttpResponse() Future(HttpResponse())
} }
Http().bindAndHandleSync(requestHandler, "localhost", 8080) Http().bindAndHandleAsync(asyncRequestHandler, "localhost",
equivalent to 8080) equivalent to
• Converting higher level(object structure to and from wire format (Json, XML, YAML etc.)
• Marshaller[A, B] structure A=> Future[List[Marshalling[B]]]
• Marshaller instances need to be available implicitly for the conversion
• Unmarshaller[A, B] implements A=> Future[B]
• Spray-json support
trait CustomJsonProtocol extends DefaultJsonProtocol {
// jsonFormat based on number of parameters
implicit val orderFormat = jsonFormat3(Order)
}
• Extend the CustomJsonProtocol & SprayJsonSupport for implicit conversions incase of High-level APIs
• Use orders.toJson.prettyPrint, ordersJson.parseJson.converTo[Order] for manual conversion
HTTP SERVER API (HIGH LEVEL)
val chainedRoute: Route =
path("myEndpoint") {
get {
complete(StatusCodes.OK)
} ~ // equivalent to concat(get{}, post{})
post {
complete(StatusCodes.Forbidden)
}
}~
path("home") {
complete(
HttpEntity(ContentTypes.`text/html(UTF-8)`,
"""
|<h1>Sample html</h1>
""".stripMargin))
} // Routing tree
val routeWithDirectives =
get {
complete("Received GET")
}~
complete("Received something else")
WHAT DIRECTIVES CAN DO
val simpleRouteWithHandlers =
handleRejections(badRequestHandler) {
(path("api" / "myEndpoint") & get) {
complete(StatusCodes.OK)
}
}
EXCEPTIONS
oneOffRequest(HttpRequest()).onComplete {
case Success(response) => println(s"Got successful response: $response")
case Failure(ex) => println(s"Sending the request failed: $ex")
}
• Even if the connectionFlow was instantiated only once above, a new connection is opened every single
time, runWith is called. Materialization and opening up a new connection is slow.
• The `outgoingConnection` API is very low-level. Use it only if you already have a Source[HttpRequest, _]
(other than Source.single) available that you want to use to run requests on a single persistent HTTP
connection.
HOST-LEVEL API
• Frees from managing individual connections autonomously manages a configurable pool of
connections to one particular target endpoint (i.e. host/port combination).
• Ability to attach data(generally to uniquely identify requests) to requests aside from payloads
• Best for high volume, low latency requests
val poolFlow: Flow[(HttpRequest, Int), (Try[HttpResponse], Int), Http.HostConnectionPool]
= Http().cachedHostConnectionPool[Int]("www.google.com")
Source(1 to 10)
.map(i => (HttpRequest(), i))
.via(poolFlow)
.map {
case (Success(response), value) =>
// VERY IMPORTANT
response.discardEntityBytes()
s"Request $value has received response: $response"
case (Failure(ex), value) =>
s"Request $value has failed: $ex"
} .runWith(Sink.foreach[String](println))
HOST-LEVEL API
Source(serverHttpRequests)
.mapAsync (10)(request => Http().singleRequest(request))
.runForeach(println)
THANK YOU