En todos los sistemas informáticos es necesario el intercambio información mediante unas estructuras de datos. Una de las opciones de intercambio, es la utilización de ficheros; estos ficheros, pueden estár definidos mediante estructuras de datos tipo XML o JSON. En esta entrada, no voy a describir las ventajas de cada uno, ni en qué circunstancias hay que utilizar cada una de ellas; sólamente, me centrará en la librería Circe la cual es una librería de manipulación de estructuras de tipo JSON.
El sketchnote de la presente entrada, queda descrito en la siguiente imagen:
JSON es una acrónimo de JavaScript Object Notation. Es un formato ligero para el intercambio de datos y, debido a su amplio uso, es una alternativa a XML, considerándose como un lenguaje independiente. Un ejemplo de estructura en JSON es el siguiente:
{ "foo": "bar", "baz": 123, "list": [ 4, 5, 6 ] }
El ejemplo anterior, está compuesto de una estructura formada por tres datos: foo, de tipo String; baz, de tipo entero; y, list, estructura de tipo lista de enteros.
Circe
Para la manipulación de estructuras JSON en lenguaje Scala y en Scala.js, se puede utilizar la librería Circe. La librería Circe es un fork de la librería Argonaut.
La presente entrada, Circe I: introducción y parseadores, es una introducción a la librería y una descripción de cómo se parsea una estructura JSON. En las siguientes entradas, describiré el resto de elementos de Circe.
Actualmente, Circe está en la versión 0.9.1 y tiene dependencia con Scalaz y Cats. La definición de las dependencias en sbt se realiza de la siguiente forma:
libraryDependencies += "io.circe" %% "circe-core" % "0.9.1", libraryDependencies += "io.circe" %% "circe-generic" % "0.9.1", libraryDependencies += "io.circe" %% "circe-parser" % "0.9.1", libraryDependencies += "io.circe" %% "circe-optics" % "0.9.1"
Si se emplea la versión de Scala 2.10, es necesario la utilización de plugin «Paradise». La definición del plugin se realiza como sigue:
addCompilerPlugin("org.scalamacros" % "paradise" % "2.0.1" cross CrossVersion.full)
Circe no provee ni usa lentes. Si se desea la utilización de lentes es necesario utilizar la librería Monocle. Para el lector interesado en Monocle, puede consultar las entradas que he realizado de la librería cuya primera entrada es Monocle I: introducción y lente Iso
Paseadores de JSON
Los parseadores de JSON son aquellos elementos que determinan si una entrada cumple con las reglas JSON, o bien, mostrar un mensaje informativo.
Las elementos necesarios para operar con los parseadores se encuentran en los siguientes paquetes de Circe:
import io.circe._ import io.circe.parser._
El juego de pruebas para los ejemplos son los siguientes:
val rawJson: String = """ { "foo": "bar", "baz": 123, "list of stuff": [ 4, 5, 6 ] } """ val badJson: String = "lol"
Para ejecutar los ejemplos, es necesario utilizar la función parse y, unos ejemplos de uso, son los siguientes:
val parseResult = parse(rawJson) println(s"[1] Parser Json puro=${parseResult}") println // Retorno un Either: Left, con el error. val parseBadJson = parse(badJson) println(s"[2] Parse Json erróneo=${parseBadJson}") println
La salida por consola es la siguiente:
[1] Parser Json puro=Right({ "foo" : "bar", "baz" : 123, "list of stuff" : [ 4, 5, 6 ] }) [2] Parse Json erróneo=Left(io.circe.ParsingFailure: expected json value got l (line 1, column 1))
Los ejemplos anteriores, se pueden tratar como Pattern Matching de la siguiente forma:
parse(rawJson) match { case Right(json) => println(s"[3] JSON válido: ${json}") case Left(failure) => println(s"[3] JSON no válido") } println parse(badJson) match { case Right(json) => println(s"[4] JSON válido: ${json}") case Left(failure) => println(s"[4] JSON no válido") } println
La salida por consola es la siguiente:
[3] JSON válido: { "foo" : "bar", "baz" : 123, "list of stuff" : [ 4, 5, 6 ] } [4] JSON no válido
Para controlar los valores null, utilizamos la función getOrElse de la librería cats.syntax.either de la sigueinte forma:
import cats.syntax.either._ val json: Json = parse(rawJson).getOrElse(Json.Null) println(s"[5] Ejemplo getOrElse=${json}") println val json2: Json = parse(badJson).getOrElse(Json.Null) println(s"[6] Ejemplo getOrElse=${json2}") println
La salida por consola es la sigueinte:
[5] Ejemplo getOrElse={ "foo" : "bar", "baz" : 123, "list of stuff" : [ 4, 5, 6 ] } [6] Ejemplo getOrElse=null
En la siguiente entrada, Circe II: manipulación y modificación de JSON, realizaré una descripción de cómo manipular las estructuras JSON con Circe.