26 oct 2020

¿Y el servidor en Scala? Akka está.

 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
  )
)

Según entiendo esta es la mínima configuración y dependencias necesarias para crear el más básico de los ejemplos de un servidor Akka

Ahora voy a crear la ruta normal de los archivos de Scala: src/main/scala y dentro de esta voy a crear un archivo main.Scala.


Dentro de este archivo voy a escribir el código necesario para crear una ruta llamada “Hi” que representa la llamada get y cuando esta llamada se complete, vamos a devolver el texto plano “Hi, Foy Akka server es running!”:
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

Podemos compilar nuestro código y  asegurarnos que todo esté bien ejecutamos el comando “compile” (dentro del server no hace escribir sbt antes). Y finalmente usamos el comando “run” para iniciar nuestro servidor Akka:


Como podemos observar, debido al log que pusimos en nuestro código, nos indica que nuestro servidor está corriendo, además de en cual ip y en cual puerto.  Ahora probemos nuestro endpoint “Hi”, como es un endpoint get podemos usar un Browser para acceder a la ruta http://localhost:8080/Hi la cual nos muestra el mensaje que especificamos en la resolución de la ruta:
O lo podemos hacer con cliente REST cualquiera

!Y ya tenemos un servidor corriendo! 

Tratemos de entender un poco el código: El objeto simpleRouter establece una variable inmutable de tipo Route en la cual establecemos el path “Hi”, definimos que este cuando se invoque con el verbo get y que cuando se complete devolveremos un objeto de tipo httpEntity (el response según yo entiendo) que simplemente contendrá el texto que queremos. En el objeto App tenemos la función startHttpServer que inicia propiamente el objeto Http que representa nuestro servidor, el cual al iniciarlo le pasamos la ruta (o ip) y el puerto, por el cual responderá y además le pasamos, por medio del método bind, el ruteo que manejará. 

Hasta aquí está todo relativamente normal. Pero entonces ¿Qué esto esto de Actors y Behaviors? En nuestro ejemplo actual si lo notan no estamos usando nada de eso, cuando nos piden el parámetro ActorSystem le estamos pasando Nothing y como behavior estamos usando Empty. Sin embargo, los Actores, como se señaló al inicio del post, son el corazón de Akka y el siguiente post voy a tratar de explicarme de que va este asunto.

Antes de cerrar el post voy a refactorizar un poco, voy crear un archivo que se llame SimpleRouter.Scala para poner ahí el objeto que devuelve la ruta. Queda más o menos así:









18 oct 2020

Scala: Configurando ambiente de desarrollo

Retomando del post anterior. Los programas más complejos en Scala requieren de un configurar o contar con un ambiente de desarrollo más elaborado que únicamente el REPL Ammonite. Scala se puede programar utilizando Eclipse, IntelliJ Idea, VIM o inclusive Visual Studio Code (en realidad con cualquier editor de texto es posible). Viniendo de territorios Microsoft prefiero utilizar este último editor con el cual estoy familiarizado.

Para utilizar Scala con Visual Studio Code se recomienda utilizar una extensión llamado “Metals” que es una especie de “language server” que nos añade una serie de convenientes características a VS Code para programar en Scala.

Comencemos pues abriendo VS Code y buscando e instalando la extensión de Metals y aprovechamos e instalamos la versión oficial de la extensión para sintaxis del lenguaje:


Una vez con Metals instalado nos aparecerá un icono con el tab que contiene el set de herramientas correspondientes:


Para comenzar a utilizar Scala desde VS Code necesitamos abrir un folder y una vez con el folder abierto nos vamos al tab de Metals y hacemos clic en el botón New Scala Project. Una vez hecho esto la extensión comenzará a descargar lo necesario para crear una aplicación Scala, lo cual puede tardar un poco al tratarse de la primera vez y seguidamente nos solicitará un template para el proyecto. En mi caso, como buen “newbie” que soy, seleccionaré la plantilla para el famoso “Hello, Word”.

Seguidamente nos preguntara que si usamos el folder actual (o seleccionamos uno diferente) y el nombre del proyecto. Se nos indicará también que se detectó un workspace de Scala y que si queremos lanzar el editor de Scala y, finalmente, que si queremos exportar el build a lo cual responderemos afirmativamente (estos últimos mensajes aparecen en la esquina inferior derecha de Visual Studio). Al final terminaremos con algo similar a esto:

Si desde este nuevo editor abrimos la extensión de Metals vamos a ver que en la primera sección se encuentra el proyecto que acabamos de crear, así como sus dependencias:

Si volvemos al tab del Explorer es importante notar el archivo build.sbt

Este archivo es muy importante ya que que en él se definen algunas propiedades, como la veersón de Scala que estamos usando y las dependencias de terceros necesarias para compilar y ejecutar un programa por medio de la herramienta de build de Scala (sbt= Scala build Tool)

Ahora volvamos la mirada a nuestro flamante código fuente y procedamos a abrir el archivo Main.Scala que se encuentra en src/Main/Scala. Aquí veremos que nuestro código actual es un simple println con la poderosa frase “Hello, World”.


Vamos a probar la escritura de código en Scala dentro de Visual Studio con las extensiones que le instalamos, principalmente el autocompletado y las sugerencias al escribir código. Vamos a crear una variable inmutable de tipo string para guardar un nombre y vamos a cambiar la salida para mostrar el Hello y el nombre almacenado en la variable:


Son ejemplos muy básicos, pero sirven para mostrar las bondades de escribir código Scala en este editor con las extensiones adecuadas. Al final terminamos con algo similar a esto:

Ahora finalmente, ¿Cómo ejecutamos este código? Primero nos aseguramos que nuestro archivo esta guardado con los últimos cambios y luego tenemos dos posibilidades: usar el tab de ejecución y debugging de VSCode o bien usar la consola y utilizar el comando sbt run.

Si usamos el botón “Run and Debug” se levantará la maquina virtual de java y se nos solicitarán algunos permisos de acceso como este, a los que contestaremos afirmativamente:

Para finalmente ver el resultado en la consola de debgug:


Y se utilizamos la terminal y el comando sbt run veremos la compilación del proyecto y el resultado de la ejecución en la misma terminal:


También se puede utilizar el comando sbt compile para únicamente compilar el código sin necesidad de ejecutarlo.

Es muy muy importante señalar que al utilizar el botón de “Run and Debug” realmente nos permite depurar. Por ejemplo, añadiendo un breakpoint la ejecución se detendrá y podemos recorrerlo paso a paso:


Hasta aquí esta entrada del paseo que estoy intentando hacer en Scala.


11 oct 2020

Scala... "pasos chiquitos"

Siempre mi "fuerte" han sido las tecnologías Microsoft. Pero hace rato que quería intentar algo diferente. Hace poco me topé con el nombre de Scala, me interesé y pensé ¿Por qué no echarle un ojo para ver de que se trata..?

Scala es un lenguaje de programación basado en Java. Es multi paradigma lo que quiere decir que soporta tanto programación orientada a objetos, estructurada y programación funcional.

Siendo un lenguaje de alto nivel con las características propias de uno,  tiene algunas particulares muy interesantes como por ejemplo tipado estático fuerte, inferencia de tipos, variables mutables e inmutables.

¿Cómo instalar Scala? 

Para instalar Scala en Windows necesitamos descargar el Instalador de Scala para Windows de la siguiente dirección Getting Started | Scala Documentation (scala-lang.org). Abrimos el archivo y corremos el ejecutable, éste instalará Scala junto con otras utilidades como el REPL mejorado Ammonite o inclusive la máquina virtual de Java si es que aun no la tenemos instalada.

Una vez ejecutado este instalador pues si nos vamos a una terminal de sistema (PowerShell) y digitamos scalac (el compilador de Scala) deberíamos recibir una respuesta como esta:

 


Indicándonos que ya podemos empezar a jugar con Scala

Empezando a jugar con Scala.

La forma más fácil de empezar con Scala, antes de empezar con archivos, scritps y compilación, es familiarizarse con su sintaxis a través del REPL (Read Eval Print Loop) que es un interprete de Scala que nos permite escribir sintaxis de Scala y obtener el resultado de su ejecución. En este caso vamos usar Ammonite digitando “amm” en una ventana de comandos

 


Aquí podemos escribir código en cada línea y a dar enter nos dará el resultado de la evaluación de la misma. Por ejemplo

 


Aquí hemos sumados un par de números en la primera línea y concatenado 3 strings en la siguiente, y concatenado el resultado de la primera línea con el resultado de la segunda. Como podemos notar Scala infiere el tipo de cada resultado.

Podemos hacer cosas un poco más complejas y usar por ejemplo tipos de Scala como las colecciones iterables tipo seq:

 


Hagamos un pequeño ejercicio

Definamos una variable inmutable de tipo secuencia de enteros, una función que reciba como parámetro la secuencia de enteros y devuelva la suma de los mismos. Veamos:

 


Analicemos lo anterior:

Definimos la variable inmutable llamada “numeros” usando la para reservada val. Como vemos no hace falta definir su tipo ya que se infiere de la asignación que realizamos inmediatamente después de su declaración, en este caso, una secuencia de enteros. Sin embargo es importante señalar que el tipo se puede establecer utilizando dos puntos y el tipo (val numeros: Seq[Int] por ejemplo). 

Seguidamente definimos la función “suma” utilizando la palabra reservada def. Esta función recibe un parámetro llamado lista, aquí sí es obligatorio definir el tipo de los parámetros, para que el compilador sepa cual es el tipo esperado por la función, y definimos el tipo que devolverá función (Int), esto último no es obligatorio ya que el compilador puede inferirlo del valor que devuelve la función pero es una buena practica establecerlo sobre todo en funciones públicas. Luego de la función colocamos un “=” y la expresión que ejecutará la función (podemos usar {} para definir un conjunto de instrucciones). En este caso usamos la función fold del tipo secuencia para realizar la suma de todos los números (la función fold recibe un valor inicial, cero este caso, luego itera sobre los elementos de la secuencia utilizando la función entre paréntesis,_ +_ aquí, donde los parámetros son el ultimo resultado de la misma función o el valor inicial y el valor actual del item de la secuencia en cada iteración). 

Finalmente llamamos a la función “suma” usando la variable “numeros" como parámetro y obtenemos el resultado. 

Como podemos notar el utilizar el REPL es muy practico para comenzar a practicar con las instrucciones de Scala.

Un último apunte en esta entrada del blog: para salir de Ammonite usamos el comando exit.