akka http 2
TRANSCRIPT
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