Continuando con esta seguidilla de posts sobre Scala y retomando desde el post anterior Ahora vamos a a hacer un experimento un poquito más avanzado: vamos a intentar crear un servidor web con Scala.
Akka es aparentemente el servidor http mas famoso del ecosistema de Scala. Según lo que se puede leer en el sitio de Akka.io, “Akka es un conjunto de herramientas para crear aplicaciones basadas en mensajes altamente concurrentes, distribuidas y resilientes para Java y Scala.” Este incluye tanto un servidor http que implementa el patrón Actor Model como un cliente para hacer llamadas http.
En este post mi plan es tratar de hacer un pequeño proyecto en Scala utilizando Visual Studio Code, que implemente un servidor que pueda responder a un request GET, con un “Hi, Akka server is running” o algo por el estilo.
Primero voy a abrir VS Code en una carpeta vacía y crearé un archivo build.sbt con las siguientes entradas:
lazy val akkaHttpVersion = "10.2.9"
lazy val akkaVersion = "2.6.18"
lazy val root = (project in file(".")).
settings(
inThisBuild(List(
organization := "com.foy",
scalaVersion := "2.13.8"
)),
name := "AkkaTest",
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-http" % akkaHttpVersion,
"com.typesafe.akka" %% "akka-actor-typed" % akkaVersion,
"com.typesafe.akka" %% "akka-stream" % akkaVersion,
"ch.qos.logback" % "logback-classic" % "1.2.3",
"org.scalatest" %% "scalatest" % "3.1.4" % Test
)
)
package com.foy.scala.AkkaTest
import akka.http.scaladsl.model.{ContentTypes, HttpEntity}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
object SimpleRouter {
val route: Route = path("Hi") {
get {
complete(HttpEntity(ContentTypes.`text/plain(UTF-8)`, "Hi, Foy Akka server is running!"))
}
}
}
Ahora añadiré el objeto principal que llamaré App que contendrá el método main que es el responsable de levantar el servidor. El código completo de archivo main.Scala quedaría algo así:package com.foy.scala.AkkaTest
import akka.http.scaladsl.model.{ContentTypes, HttpEntity}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.actor.typed.ActorSystem
import akka.actor.typed.scaladsl.Behaviors
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpRequest
import scala.concurrent.duration._
import scala.concurrent.{Await, ExecutionContextExecutor}
import scala.util.Failure
import scala.util.Success
object SimpleRouter {
val route: Route = path("Hi") {
get {
complete(HttpEntity(ContentTypes.`text/plain(UTF-8)`, "Hi, Foy Akka server is running!"))
}
}
}
object App {
//Function to start the httpServer
private def startHttpServer(routes: Route)(implicit system: ActorSystem[_]): Unit = {
import system.executionContext
val serverBinding = Http().newServerAt("localhost", 8080).bind(routes)
serverBinding.onComplete {
case Success(binding) =>
val address = binding.localAddress
system.log.info("Foy Akka Server online at http://{}:{}/", address.getHostString, address.getPort)
case Failure(ex) =>
system.log.error("Foy Akka Server Failed to bind HTTP endpoint, terminating system", ex)
system.terminate()
}
}
def main(args: Array[String]): Unit = {
val rootBehavior = Behaviors.setup[Nothing] { context =>
startHttpServer(SimpleRouter.route)(context.system)
Behaviors.empty
}
val system = ActorSystem[Nothing](rootBehavior, "akkaServerTest")
}
}
Abrimos una terminal y arrancamos el servidor sbt