Introduction to Akka HTTP Building scalable rest service in Scala https://github.com/shashankgowdal/introduction-to-akkahttp
● Shashank L ● Senior Software engineer at Tellius ● Part time big data consultant and trainer at datamantra.io ● www.shashankgowda.com
Agenda ● Motivation ● Akka, Reactive streams ● Akka Http ● Akka Http High level API ● Testing ● Additional functionality ● Working with files ● Websockets ● Akka Http with Spark
Scala frameworks to build REST API ● Play/Lift ○ Full stack web framework ● Scalatra ○ Lightweight but requires a application container for deployment ● Spray ○ Lightweight and robust as it's asynchronous and built on top of Actors ● Akka HTTP ○ Next version of Spray framework
Why Akka HTTP ● Its 2.0 version of Spray.io ● Internals of Spray have been rewritten to use Reactive streams ● Reactive streams idea gel well with earlier ideas of Spray ● Multiple level API
Akka ● Toolkit and runtime for building highly concurrent, distributed, and fault tolerant applications on the JVM ● Uses message passing based concurrency model ● Written in Scala ● Scale up or out ● Program at higher level ● Distributable by design ● Message passing is built on top of AkkaActor model
Akka actor ● Receives message and takes action to handle them ● Consists of ○ Behaviour ○ State ○ Mailbox
Reactive streams ● Asynchronous ● Stream processing ● Back-pressured ● Interoperability ● Few Implementations ○ Akka Streams ○ RxJava ○ Play ○ Kafka ● Spark streaming with Kafka receiver
Akka streams ● Akka’s implementation of Reactive streams ● DSL for building a complete stream ● Higher level abstraction over the actor model ● Stream inputs and outputs are typesafe ● Internally uses Actor to implement Reactive stream properties
Source, Flow and Sink
Source, Flow and Sink com.shashank.akkahttp.IntroductionToStream implicit val sys = ActorSystem("IntroductionToStream") implicit val mat:Materializer = ActorMaterializer() val source = Source(List(1, 2, 3)) val flow = Flow[Int].map(_.toString) val sink = Sink.foreach(println) val runnableGraph = source via flow to sink runnableGraph.run()
HTTP server with Akka streams HTTPServer as a: Flow[HttpRequest, HttpResponse] Socket input Bytes ⇒ HttpRequest HttpRequest ⇒ HttpResponse HttpResponse ⇒ Bytes Socket Sink
Akka Http server using Flow implicit val sys = ActorSystem("IntroductionToAkkaHttp") implicit val mat:Materializer = ActorMaterializer() val requestResponseFlow = Flow.fromFunction[HttpRequest, HttpResponse]( request => { println(request.toString) HttpResponse(StatusCodes.OK, entity = "Hello!") }) Http().bindAndHandle(requestResponseFlow, "localhost", 8080) com.shashank.akkahttp.basic.serving.StreamsServing
Akka HTTP ● Part of Akka project ● HTTP toolkit (Client and Server) ● On top of akka-actor and akka-streams ● Multiple levels of abstraction - Open API ● Scalable, Max throughput, acceptable latency ● APIs in both Scala and Java
Akka HTTP - Implementation ● Fully asynchronous and nonblocking ● Focused on higher level API ● Lightweight ● Modular ● Testable ● Based on spray.io ● Better streaming REST functionality support
Akka HTTP stack
Akka HTTP structure Akka HTTP module akka-http akka-http-core akka-http-testkit akka-http- spray-json akka-http-xml
Akka HTTP - Parts ● akka-http-core ○ low-level server & client side HTTP implementation ● akka-http ○ high-level API : DSL, (un)marshalling, (de)compression ● akka-http-testkit ○ Utilities for testing server-side implementation ● akka-http-spray-json ○ (de)serialization from/to JSON with spray-json ● akka-http-xml ○ (de)serialization from/to XML with scala-xml
HTTP model ● Fully immutable, case-class based ● Abstraction for most HTTP things (Types!) ● Little logic inside ● Lots of predefined types - media type, status code, encodings etc ● Efficient parsing and rendering ● Clients/Connected services should obey the standard
HTTP model - Examples 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`) case class HttpResponse(status: StatusCode = StatusCodes.OK, headers: immutable.Seq[HttpHeader] = Nil, entity: ResponseEntity = HttpEntity.Empty, protocol: HttpProtocol = HttpProtocols.`HTTP/1.1`) case class Uri(scheme: String, authority: Authority, path: Path, rawQueryString: Option[String], fragment: Option[String])
HTTP model - Examples object ContentTypes { val `application/json` = ContentType(MediaTypes.`application/json`) val `application/octet-stream` = ContentType(MediaTypes.`application/octet-stream`) val `text/plain(UTF-8)` = MediaTypes.`text/plain` withCharset HttpCharsets.`UTF-8` val `text/html(UTF-8)` = MediaTypes.`text/html` withCharset HttpCharsets.`UTF-8` val `text/xml(UTF-8)` = MediaTypes.`text/xml` withCharset HttpCharsets.`UTF-8` val `text/csv(UTF-8)` = MediaTypes.`text/csv` withCharset HttpCharsets.`UTF-8` val NoContentType = ContentType(MediaTypes.NoMediaType) } val `US-ASCII` = register("US-ASCII")("iso-ir-6", "ANSI_X3.4-1968", "ANSI_X3.4-1986", "ISO_646.irv:1991", "ASCII", "ISO646-US", "us", "IBM367", "cp367", "csASCII") val `ISO-8859-1` = register("ISO-8859-1")("iso-ir-100", "ISO_8859-1", "latin1", "l1", "IBM819", "CP819", "csISOLatin1") val `UTF-8` = register("UTF-8")("UTF8") val `UTF-16` = register("UTF-16")("UTF16") val `UTF-16BE` = register("UTF-16BE")() val `UTF-16LE` = register("UTF-16LE")()
HTTP server functional way ● Low level HTTP API ● Provided by akka-http-core-module implicit val sys = ActorSystem("IntroductionToAkkaHttp") implicit val mat:Materializer = ActorMaterializer() val handler :(HttpRequest => HttpResponse) = { case HttpRequest(HttpMethods.GET, Uri.Path("/ping"), _, _, _) => HttpResponse(StatusCodes.OK, entity = "pong!") case r => HttpResponse(status = StatusCodes.BadRequest) } Http().bindAndHandleSync(handler, "localhost", 8080) com.shashank.akkahttp.basic.serving.FunctionalServing
Akka Http high level API
HTTP Server Nice way! ● Low level API becomes uneasy to handle when we need large number of routes ● For this we should use higher level API by akka-http ● Route using Routing DSL implicit val sys = ActorSystem("IntroductionToAkkaHttp") implicit val mat:Materializer = ActorMaterializer() val routes: Route = ??? Http(sys).bindAndHandle(route, "localhost", 8090)
Routing DSL ● Internal domain specific language for routing ● How most services are actually written ● Layer to the application ● Type safe but flexible ● Not just routing - behaviour definition ● Very composable ● Fun, powerful and looks clean
Routing DSL - Example val route = path("welcome"){ get{ complete { "welcome to rest service" } } } ~ path("demo"){ get{ complete { "welcome to demonstration" } } } Http().bindAndHandle(route, "localhost", 8090) com.shashank.akkahttp.basic.routing.RoutingDSL
Directives ● A Directive is a small building block used for creating routes. ● There are some predefined directives( get, post, complete etc.) ● We can also define our custom directives. ● Roles: extracting, transforming request or response, filtering, side-effecting ● ~136 predefined directives
Rejections ● Produced by directives ● Travel down the routing structure ● EmptyRejection is thrown when no route completes ● Can be extended ● Can be cancelled ● Handling rejection = transforming it to response ● Ex. MethodRejection, AuthorizationFailedRejection, MissingCookieRejection, MissingQueryParamRejection
Rejections ● ~ operator connects two routes in a way that allows a second route to get a go at a request if the first route "rejected" it. path("order") { get { complete("Received GET") } ~ post { complete("Received POST") } } com.shashank.akkahttp.basic.routing.Rejection
Failures ● Are triggered by exceptions ● Travel up the routing structure ● Can be handled by handleExceptions directive or top-level ExceptionHandler ● Can be used to simplify the flow for validation purpose com.shashank.akkahttp.basic.routing.Failure
Testing Akka Http
● Simple and straightforward ● Allows to assert responses returned for given requests ● Integrates well with Scalatest Get("/ping") ~> route ~> check{ status === OK entity.as[String] === "It Works!" } com.shashank.akkahttp.basic.routing.TestKit Testkit
Additional Rest functionalities in Akka Http
Query parameters def parameters(param: <ParamDef[T]>): Directive1[T] ● Mandatory parameters ● Optional parameters ● Parameters with required value ● Deserialized parameter ● Repeated parameter ● Deserialized parameter into Case class
(Un)Marshalling ● Marshalling - high level → low (wire) level ● Unmarshalling - low (wire) level → high level ● Many predefined (un) marshallers are available ● Extensible ● JSON and XML supported ● Type-class approach - Implicit resolution
Custom Http entity data ● Akka Http JSON support ● Support conversion to and from JVM objects to wire representation like JSON, XML etc ● SprayJsonSupport provides a FromEntityUnmarshaller[T] and ToEntityMarshaller[T] for every type T with Spray Json Reader/Writer com.shashank.akkahttp.basic.routing.CustomEntityWithJson
Custom directive ● Configuration labelling ● Transforming existing directives ● Directive0, Directive1 ● Authorization ● Authentication com.shashank.akkahttp.basic.routing.CustomDirective
Working with Files
File upload def uploadedFile(fieldName: String): Directive1[(FileInfo, File)] ● Streams the contents of a file uploaded as a multipart form into a temporary file on disk ● Cannot start processing the file unless it written completely to temporary file com.shashank.akkahttp.basic.routing.FileUpload
File upload stream def fileUpload(fieldName: String): Directive1[(FileInfo, Source[ByteString, Any])] ● Simple access to the stream of bytes for a file uploaded as a multipart form together with metadata about the upload as extracted value. com.shashank.akkahttp.basic.routing.FileUploadStream
Websockets
Websocket ● WebSocket is a protocol that provides a bi-directional channel between browser and webserver ● Data is exchanged in messages whereby a message can either be binary data or unicode text
Server side websocket in AkkaHttp ● Akka HTTP provides a stream-based implementation of the WebSocket protocol ● basic unit of data exchange in the WebSocket is a message i.e TextMessage or BinaryMessage ● Websocket handshake is managed and hidden from application layer ● A message handler is expected to be implemented as a Flow[Message, Message, Any] ● Testing Websocket using WSProbe com.shashank.akkahttp.basic.routing.Websocket
Akka HTTP with Spark Spark Cluster Akka Http Rest server Client HDFS
Pros and Cons ● Pros ○ Backed by Lightbend(Typesafe) ○ Integration layers ○ Microservices ○ Pure REST APIs ● Cons ○ Full fledged web applications (server side template generation) ○ Not mature enough ○ Easy to start, hard to master
References ● Akka HTTP - A reactive web toolkit ● Akka HTTP - What, Why and How ● Introduction to Akka HTTP ● Akka HTTP documentation http://doc.akka.io/docs/akka/2.4.2/scala/http/ ● http://blog.madhukaraphatak.com/categories/akka-http/

Building scalable rest service using Akka HTTP

  • 1.
    Introduction to AkkaHTTP Building scalable rest service in Scala https://github.com/shashankgowdal/introduction-to-akkahttp
  • 2.
    ● Shashank L ●Senior Software engineer at Tellius ● Part time big data consultant and trainer at datamantra.io ● www.shashankgowda.com
  • 3.
    Agenda ● Motivation ● Akka,Reactive streams ● Akka Http ● Akka Http High level API ● Testing ● Additional functionality ● Working with files ● Websockets ● Akka Http with Spark
  • 4.
    Scala frameworks tobuild REST API ● Play/Lift ○ Full stack web framework ● Scalatra ○ Lightweight but requires a application container for deployment ● Spray ○ Lightweight and robust as it's asynchronous and built on top of Actors ● Akka HTTP ○ Next version of Spray framework
  • 5.
    Why Akka HTTP ●Its 2.0 version of Spray.io ● Internals of Spray have been rewritten to use Reactive streams ● Reactive streams idea gel well with earlier ideas of Spray ● Multiple level API
  • 6.
    Akka ● Toolkit andruntime for building highly concurrent, distributed, and fault tolerant applications on the JVM ● Uses message passing based concurrency model ● Written in Scala ● Scale up or out ● Program at higher level ● Distributable by design ● Message passing is built on top of AkkaActor model
  • 7.
    Akka actor ● Receivesmessage and takes action to handle them ● Consists of ○ Behaviour ○ State ○ Mailbox
  • 8.
    Reactive streams ● Asynchronous ●Stream processing ● Back-pressured ● Interoperability ● Few Implementations ○ Akka Streams ○ RxJava ○ Play ○ Kafka ● Spark streaming with Kafka receiver
  • 9.
    Akka streams ● Akka’simplementation of Reactive streams ● DSL for building a complete stream ● Higher level abstraction over the actor model ● Stream inputs and outputs are typesafe ● Internally uses Actor to implement Reactive stream properties
  • 10.
  • 11.
    Source, Flow andSink com.shashank.akkahttp.IntroductionToStream implicit val sys = ActorSystem("IntroductionToStream") implicit val mat:Materializer = ActorMaterializer() val source = Source(List(1, 2, 3)) val flow = Flow[Int].map(_.toString) val sink = Sink.foreach(println) val runnableGraph = source via flow to sink runnableGraph.run()
  • 12.
    HTTP server withAkka streams HTTPServer as a: Flow[HttpRequest, HttpResponse] Socket input Bytes ⇒ HttpRequest HttpRequest ⇒ HttpResponse HttpResponse ⇒ Bytes Socket Sink
  • 13.
    Akka Http serverusing Flow implicit val sys = ActorSystem("IntroductionToAkkaHttp") implicit val mat:Materializer = ActorMaterializer() val requestResponseFlow = Flow.fromFunction[HttpRequest, HttpResponse]( request => { println(request.toString) HttpResponse(StatusCodes.OK, entity = "Hello!") }) Http().bindAndHandle(requestResponseFlow, "localhost", 8080) com.shashank.akkahttp.basic.serving.StreamsServing
  • 14.
    Akka HTTP ● Partof Akka project ● HTTP toolkit (Client and Server) ● On top of akka-actor and akka-streams ● Multiple levels of abstraction - Open API ● Scalable, Max throughput, acceptable latency ● APIs in both Scala and Java
  • 15.
    Akka HTTP -Implementation ● Fully asynchronous and nonblocking ● Focused on higher level API ● Lightweight ● Modular ● Testable ● Based on spray.io ● Better streaming REST functionality support
  • 16.
  • 17.
    Akka HTTP structure AkkaHTTP module akka-http akka-http-core akka-http-testkit akka-http- spray-json akka-http-xml
  • 18.
    Akka HTTP -Parts ● akka-http-core ○ low-level server & client side HTTP implementation ● akka-http ○ high-level API : DSL, (un)marshalling, (de)compression ● akka-http-testkit ○ Utilities for testing server-side implementation ● akka-http-spray-json ○ (de)serialization from/to JSON with spray-json ● akka-http-xml ○ (de)serialization from/to XML with scala-xml
  • 19.
    HTTP model ● Fullyimmutable, case-class based ● Abstraction for most HTTP things (Types!) ● Little logic inside ● Lots of predefined types - media type, status code, encodings etc ● Efficient parsing and rendering ● Clients/Connected services should obey the standard
  • 20.
    HTTP model -Examples 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`) case class HttpResponse(status: StatusCode = StatusCodes.OK, headers: immutable.Seq[HttpHeader] = Nil, entity: ResponseEntity = HttpEntity.Empty, protocol: HttpProtocol = HttpProtocols.`HTTP/1.1`) case class Uri(scheme: String, authority: Authority, path: Path, rawQueryString: Option[String], fragment: Option[String])
  • 21.
    HTTP model -Examples object ContentTypes { val `application/json` = ContentType(MediaTypes.`application/json`) val `application/octet-stream` = ContentType(MediaTypes.`application/octet-stream`) val `text/plain(UTF-8)` = MediaTypes.`text/plain` withCharset HttpCharsets.`UTF-8` val `text/html(UTF-8)` = MediaTypes.`text/html` withCharset HttpCharsets.`UTF-8` val `text/xml(UTF-8)` = MediaTypes.`text/xml` withCharset HttpCharsets.`UTF-8` val `text/csv(UTF-8)` = MediaTypes.`text/csv` withCharset HttpCharsets.`UTF-8` val NoContentType = ContentType(MediaTypes.NoMediaType) } val `US-ASCII` = register("US-ASCII")("iso-ir-6", "ANSI_X3.4-1968", "ANSI_X3.4-1986", "ISO_646.irv:1991", "ASCII", "ISO646-US", "us", "IBM367", "cp367", "csASCII") val `ISO-8859-1` = register("ISO-8859-1")("iso-ir-100", "ISO_8859-1", "latin1", "l1", "IBM819", "CP819", "csISOLatin1") val `UTF-8` = register("UTF-8")("UTF8") val `UTF-16` = register("UTF-16")("UTF16") val `UTF-16BE` = register("UTF-16BE")() val `UTF-16LE` = register("UTF-16LE")()
  • 22.
    HTTP server functionalway ● Low level HTTP API ● Provided by akka-http-core-module implicit val sys = ActorSystem("IntroductionToAkkaHttp") implicit val mat:Materializer = ActorMaterializer() val handler :(HttpRequest => HttpResponse) = { case HttpRequest(HttpMethods.GET, Uri.Path("/ping"), _, _, _) => HttpResponse(StatusCodes.OK, entity = "pong!") case r => HttpResponse(status = StatusCodes.BadRequest) } Http().bindAndHandleSync(handler, "localhost", 8080) com.shashank.akkahttp.basic.serving.FunctionalServing
  • 23.
    Akka Http highlevel API
  • 24.
    HTTP Server Niceway! ● Low level API becomes uneasy to handle when we need large number of routes ● For this we should use higher level API by akka-http ● Route using Routing DSL implicit val sys = ActorSystem("IntroductionToAkkaHttp") implicit val mat:Materializer = ActorMaterializer() val routes: Route = ??? Http(sys).bindAndHandle(route, "localhost", 8090)
  • 25.
    Routing DSL ● Internaldomain specific language for routing ● How most services are actually written ● Layer to the application ● Type safe but flexible ● Not just routing - behaviour definition ● Very composable ● Fun, powerful and looks clean
  • 26.
    Routing DSL -Example val route = path("welcome"){ get{ complete { "welcome to rest service" } } } ~ path("demo"){ get{ complete { "welcome to demonstration" } } } Http().bindAndHandle(route, "localhost", 8090) com.shashank.akkahttp.basic.routing.RoutingDSL
  • 27.
    Directives ● A Directiveis a small building block used for creating routes. ● There are some predefined directives( get, post, complete etc.) ● We can also define our custom directives. ● Roles: extracting, transforming request or response, filtering, side-effecting ● ~136 predefined directives
  • 28.
    Rejections ● Produced bydirectives ● Travel down the routing structure ● EmptyRejection is thrown when no route completes ● Can be extended ● Can be cancelled ● Handling rejection = transforming it to response ● Ex. MethodRejection, AuthorizationFailedRejection, MissingCookieRejection, MissingQueryParamRejection
  • 29.
    Rejections ● ~ operatorconnects two routes in a way that allows a second route to get a go at a request if the first route "rejected" it. path("order") { get { complete("Received GET") } ~ post { complete("Received POST") } } com.shashank.akkahttp.basic.routing.Rejection
  • 30.
    Failures ● Are triggeredby exceptions ● Travel up the routing structure ● Can be handled by handleExceptions directive or top-level ExceptionHandler ● Can be used to simplify the flow for validation purpose com.shashank.akkahttp.basic.routing.Failure
  • 31.
  • 32.
    ● Simple andstraightforward ● Allows to assert responses returned for given requests ● Integrates well with Scalatest Get("/ping") ~> route ~> check{ status === OK entity.as[String] === "It Works!" } com.shashank.akkahttp.basic.routing.TestKit Testkit
  • 33.
  • 34.
    Query parameters def parameters(param:<ParamDef[T]>): Directive1[T] ● Mandatory parameters ● Optional parameters ● Parameters with required value ● Deserialized parameter ● Repeated parameter ● Deserialized parameter into Case class
  • 35.
    (Un)Marshalling ● Marshalling -high level → low (wire) level ● Unmarshalling - low (wire) level → high level ● Many predefined (un) marshallers are available ● Extensible ● JSON and XML supported ● Type-class approach - Implicit resolution
  • 36.
    Custom Http entitydata ● Akka Http JSON support ● Support conversion to and from JVM objects to wire representation like JSON, XML etc ● SprayJsonSupport provides a FromEntityUnmarshaller[T] and ToEntityMarshaller[T] for every type T with Spray Json Reader/Writer com.shashank.akkahttp.basic.routing.CustomEntityWithJson
  • 37.
    Custom directive ● Configurationlabelling ● Transforming existing directives ● Directive0, Directive1 ● Authorization ● Authentication com.shashank.akkahttp.basic.routing.CustomDirective
  • 38.
  • 39.
    File upload def uploadedFile(fieldName:String): Directive1[(FileInfo, File)] ● Streams the contents of a file uploaded as a multipart form into a temporary file on disk ● Cannot start processing the file unless it written completely to temporary file com.shashank.akkahttp.basic.routing.FileUpload
  • 40.
    File upload stream deffileUpload(fieldName: String): Directive1[(FileInfo, Source[ByteString, Any])] ● Simple access to the stream of bytes for a file uploaded as a multipart form together with metadata about the upload as extracted value. com.shashank.akkahttp.basic.routing.FileUploadStream
  • 41.
  • 42.
    Websocket ● WebSocket isa protocol that provides a bi-directional channel between browser and webserver ● Data is exchanged in messages whereby a message can either be binary data or unicode text
  • 43.
    Server side websocketin AkkaHttp ● Akka HTTP provides a stream-based implementation of the WebSocket protocol ● basic unit of data exchange in the WebSocket is a message i.e TextMessage or BinaryMessage ● Websocket handshake is managed and hidden from application layer ● A message handler is expected to be implemented as a Flow[Message, Message, Any] ● Testing Websocket using WSProbe com.shashank.akkahttp.basic.routing.Websocket
  • 44.
    Akka HTTP withSpark Spark Cluster Akka Http Rest server Client HDFS
  • 45.
    Pros and Cons ●Pros ○ Backed by Lightbend(Typesafe) ○ Integration layers ○ Microservices ○ Pure REST APIs ● Cons ○ Full fledged web applications (server side template generation) ○ Not mature enough ○ Easy to start, hard to master
  • 46.
    References ● Akka HTTP- A reactive web toolkit ● Akka HTTP - What, Why and How ● Introduction to Akka HTTP ● Akka HTTP documentation http://doc.akka.io/docs/akka/2.4.2/scala/http/ ● http://blog.madhukaraphatak.com/categories/akka-http/