⇗ nescala 2015-01-30@boston
Mathias Doenitz
/
/
This presentation: http://spray.io/nescala2015/
"Build powerful
concurrent
concurrent
&
distributed
distributed
applications more easily"
def bind(endpoint: InetSocketAddress, ...): Http.ServerBinding
object Http {
trait ServerBinding {
def connections: Source[IncomingConnection]
def localAddress(mm: MaterializedMap): Future[InetSocketAddress]
def unbind(mm: MaterializedMap): Future[Unit]
/* ... plus `startHandlingWithXXX(...)` sugar ... */
}
}
object Http {
trait IncomingConnection {
def localAddress: InetSocketAddress
def remoteAddress: InetSocketAddress
def handleWith
(handler: Flow[HttpRequest, HttpResponse]): MaterializedMap
def handleWithSyncHandler
(handler: HttpRequest ⇒ HttpResponse): MaterializedMap
def handleWithAsyncHandler
(handler: HttpRequest ⇒ Future[HttpResponse]): MaterializedMap
}
}
/**
* Transforms a given HTTP-level server Flow
* into a lower-level TCP transport flow.
*/
def serverFlowToTransport(
serverFlow: Flow[HttpRequest, HttpResponse],
...): Flow[ByteString, ByteString]
val binding = Http().bind("localhost", 8080)
binding startHandlingWithSyncHandler {
case HttpRequest(GET, Uri.Path("/ping"), _, _, _) ⇒
HttpResponse(entity = "PONG!")
case _ ⇒ // catch all
HttpResponse(404, entity = "Unknown resource!")
}
def outgoingConnection(endpoint: InetSocketAddress, ...)
: Http.OutgoingConnection
object Http {
trait OutgoingConnection {
def remoteAddress: InetSocketAddress
def localAddress(mm: MaterializedMap): Future[InetSocketAddress]
def flow: Flow[HttpRequest, HttpResponse]
}
}
/**
* Transforms the given low-level TCP client transport
* Flow into a higher-level HTTP client flow.
*/
def transportToConnectionClientFlow(
transport: Flow[ByteString, ByteString],
...): Flow[HttpRequest, HttpResponse]
case class HttpRequest(
method: HttpMethod = HttpMethods.GET,
uri: Uri = Uri./,
headers: immutable.Seq[HttpHeader] = Nil,
entity: RequestEntity = HttpEntity.Empty,
protocol: HttpProtocol = HttpProtocols.`HTTP/1.1`
) extends HttpMessage
case class HttpResponse(
status: StatusCode = StatusCodes.OK,
headers: immutable.Seq[HttpHeader] = Nil,
entity: ResponseEntity = HttpEntity.Empty,
protocol: HttpProtocol = HttpProtocols.`HTTP/1.1`
) extends HttpMessage
case class Uri( // proper RFC 3986
scheme: String, // compliant,
authority: Authority, // immutable
path: Path, // URI model
query: Query, // with a fast,
fragment: Option[String]) // custom parser
sealed trait HttpEntity
sealed trait ResponseEntity extends HttpEntity
sealed trait RequestEntity extends ResponseEntity
// can be used for any message (request or response)
type MessageEntity = RequestEntity
sealed trait BodyPartEntity extends HttpEntity
// can be used for messages as well as bodyparts
sealed trait UniversalEntity extends MessageEntity
with BodyPartEntity
object HttpEntity {
case class Strict(contentType: ContentType,
data: ByteString) extends UniversalEntity
case class Default(contentType: ContentType, contentLength: Long,
data: Source[ByteString]) extends UniversalEntity
case class Chunked(contentType: ContentType,
chunks: Source[ChunkStreamPart]) extends MessageEntity
case class CloseDelimited(contentType: ContentType,
data: Source[ByteString]) extends ResponseEntity
case class IndefiniteLength(contentType: ContentType,
data: Source[ByteString]) extends BodyPartEntity
}
case class `Accept-Charset`(charsetRanges: immutable.Seq[HttpCharsetRange])
extends HttpHeader
case class `Cache-Control`(directives: immutable.Seq[CacheDirective])
extends HttpHeader
case class `Set-Cookie`(cookie: HttpCookie)
extends HttpHeader
case class RawHeader(name: String, value: String)
extends HttpHeader