Akka http 2

Preview:

Citation preview

AKKA HTTPA.K.A. SPRAY 2.0

Présenté par Jean Detoeuf / @thebignet

JEAN DETOEUFDÉVELOPPEUR

Passionné de nouvelles technologies

#jvm #docker #craftmanship #rpi #diy

AVERTISSEMENTJe ne suis pas un expert en Scala

Soyez sympas ^^

PROJET EN COURS DE MATURATIONversion lors de cette présentation2.0.1

mélange entre Spray et AkkaJ'ai eu l'idée de cette présentation à la version 1.0, il était temps !

AKKA STREAMSPrésenté au SLUG par en février 2015Frédéric Masion

Source ~> Flow ~> Sink

Source décrit une source de données

Flow représente une transformation de ces données

Sink une opération terminale

AKKA STREAMSSource ~> Flow1 ~> Flow2a ~> Sink

~> Flow2b

Fan-out / Fan-in

AKKA HTTPConstuit sur Akka Streams

Internet est un tuyaurempli de chatons

AKKA HTTP

Flow[HttpRequest, HttpResponse]

AKKA HTTPClient et serveur

Mettre des acteurs sur HTTP

MODULESakka-http-spray-json

akka-http-xml

akka-http-testkit

akka-http

akka-http-core

C'EST BON, MONTRE-MOI LE CODELes exemples sont pour la plupart tirés de la documentation

d'Akka

EXEMPLE SIMPLE

import akka.http.scaladsl.Http import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._ import akka.http.scaladsl.server.Directives._ import akka.stream.ActorMaterializer object Main extends App { implicit val system = ActorSystem("my-system") implicit val materializer = ActorMaterializer() implicit val ec = system.dispatcher val route = path("hello") { get { complete { <h1>Say hello to akka-http</h1> } } } val bindingFuture = Http().bindAndHandle(route, "localhost", 8080) println(s"Server online at http://localhost:8080/\nPress RETURN to stop...") Console.readLine() // for the future transformations bindingFuture .flatMap(_.unbind()) // trigger unbinding from the port .onComplete(_ ⇒ system.shutdown()) // and shutdown when done }

EXEMPLE SIMPLE

import akka.http.scaladsl.Http import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._ import akka.http.scaladsl.server.Directives._ import akka.stream.ActorMaterializer object Main extends App { implicit val system = ActorSystem("my-system") implicit val materializer = ActorMaterializer() implicit val ec = system.dispatcher val route = path("hello") { get { complete { <h1>Say hello to akka-http</h1> } } } val bindingFuture = Http().bindAndHandle(route, "localhost", 8080) println(s"Server online at http://localhost:8080/\nPress RETURN to stop...") Console.readLine() // for the future transformations bindingFuture .flatMap(_.unbind()) // trigger unbinding from the port .onComplete(_ ⇒ system.shutdown()) // and shutdown when done }

EXEMPLE SIMPLE

import akka.http.scaladsl.Http import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._ import akka.http.scaladsl.server.Directives._ import akka.stream.ActorMaterializer object Main extends App { implicit val system = ActorSystem("my-system") implicit val materializer = ActorMaterializer() implicit val ec = system.dispatcher val route = path("hello") { get { complete { <h1>Say hello to akka-http</h1> } } } val bindingFuture = Http().bindAndHandle(route, "localhost", 8080) println(s"Server online at http://localhost:8080/\nPress RETURN to stop...") Console.readLine() // for the future transformations bindingFuture .flatMap(_.unbind()) // trigger unbinding from the port .onComplete(_ ⇒ system.shutdown()) // and shutdown when done }

EXEMPLE SIMPLE

import akka.http.scaladsl.Http import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._ import akka.http.scaladsl.server.Directives._ import akka.stream.ActorMaterializer object Main extends App { implicit val system = ActorSystem("my-system") implicit val materializer = ActorMaterializer() implicit val ec = system.dispatcher val route = path("hello") { get { complete { <h1>Say hello to akka-http</h1> } } } val bindingFuture = Http().bindAndHandle(route, "localhost", 8080) println(s"Server online at http://localhost:8080/\nPress RETURN to stop...") Console.readLine() // for the future transformations bindingFuture .flatMap(_.unbind()) // trigger unbinding from the port .onComplete(_ ⇒ system.shutdown()) // and shutdown when done }

MARSHALLING/UNMARSHALLING

MARSHALLING/UNMARSHALLINGComment passer d'un flux HTTP à Scala et inversement ?

MARSHALLINGMarshallers prédéfinis

Array[Byte] ByteString Array[Char] String akka.http.scaladsl.model.FormData akka.http.scaladsl.model.MessageEntity T <: akka.http.scaladsl.model.Multipart T si ToEntityMarshaller[T] est présent

MARSHALLINGRésolution implicite

Si le type ToEntityMarshaller[T] est défini, il est utilisé

UNMARSHALLINGUnmarshallers prédéfinis

Byte Short Int Long Float Double Boolean Array[Byte] ByteString Array[Char] String akka.http.scaladsl.model.FormData

ROUTAGE

LOW-LEVELimport akka.http.scaladsl.Http import akka.http.scaladsl.model.HttpMethods._ import akka.http.scaladsl.model._ import akka.stream.ActorMaterializer implicit val system = ActorSystem() implicit val materializer = ActorMaterializer() val requestHandler: HttpRequest => HttpResponse = { case HttpRequest(GET, Uri.Path("/"), _, _, _) => HttpResponse(entity = HttpEntity(ContentTypes.text/html(UTF-8), "Hello world!")) case HttpRequest(GET, Uri.Path("/ping"), _, _, _) => HttpResponse(entity = "PONG!") case HttpRequest(GET, Uri.Path("/crash"), _, _, _) => sys.error("BOOM!") case _: HttpRequest => HttpResponse(404, entity = "Unknown resource!") } Http().bindAndHandleSync(requestHandler, "localhost", 8080)

HIGH-LEVELimport akka.http.scaladsl.Http import akka.http.scaladsl.marshallers.xml.ScalaXmlSupport._ import akka.http.scaladsl.server.Directives._ import akka.stream.ActorMaterializer implicit val system = ActorSystem() implicit val materializer = ActorMaterializer() val route = get { pathSingleSlash { complete { <html> <body>Hello world!</body> </html> } } ~ path("ping") { complete("PONG!") } ~ path("crash") { sys.error("BOOM!") } } // route will be implicitly converted to Flow using RouteResult

// route will be implicitly converted to Flow using RouteResult.route2HandlerFlow Http().bindAndHandle(route, "localhost", 8080)

DIRECTIVES

DIRECTIVESIntercepte la requête

Filtrage de la requête

Transformation de la requête ou réponse

Extraire des informations

EXEMPLEval route = path("order" / IntNumber) { id => (get | put) { extractMethod { m => complete(s"Received ${m.name} request for order $id") } } }

EXEMPLE 2val orderGetOrPutWithMethod = path("order" / IntNumber) & (get | put) & extractMethod val route = orderGetOrPutWithMethod { (id, m) => complete(s"Received ${m.name} request for order $id") }

et

PATHMATCHERval matcher: PathMatcher1[Option[Int]] = "foo" / "bar" / "X" ~ IntNumber.? / ("edit" | "create")

Intercepte les chemins suivants :foo/bar/X42/edit

foo/bar/X/create

EXTRACTION CASE CLASScase class Color(red: Int, green: Int, blue: Int) val route = path("color") { parameters('red.as[Int], 'green.as[Int], 'blue.as[Int]).as(Color) { color => // utiliser color } }

VALIDATION CASE CLASScase class Color(name: String, red: Int, green: Int, blue: Int) { require(!name.isEmpty, "color name must not be empty") require(0 <= red && red <= 255, "red color component must be between 0 and 255") require(0 <= green && green <= 255, "green color component must be between 0 and 255") require(0 <= blue && blue <= 255, "blue color component must be between 0 and 255") }

ValidationRejection si require ne passe pas

Par défaut : 400 Bad Request

TESTS

Pour la route suivanteval smallRoute = get { pathSingleSlash { complete { "Hello World !" } } ~ path("ping") { complete("PONG !") } }

Test"Hello World ! non renvoyé sur /" in { Get() ~> smallRoute ~> check { status === StatusCodes.OK responseAs[String] shouldEqual "Hello World !" } }

Pour la même route ...val smallRoute = get { pathSingleSlash { complete { "Hello World !" } } ~ path("ping") { complete("PONG !") } }

Test"GET sur chemin inconnu non pris en compte" in { Get("/pouet") ~> smallRoute ~> check { handled shouldBe false } }

VARIABLES UTILISABLES DANS LESTESTS

entityAs

handled

header

response

status

entre autres ...

CLIENTval responseFuture: Future[HttpResponse] = Http().singleRequest(HttpRequest(uri = "http://akka.io"))

QUESTIONS ?

MERCI POUR VOTRE ÉCOUTE

Cette présentation :

@thebignetthebignetthebignet

talk-akka-http