Parsing JSON with Circe
Tags: scala, beginners
Published: 2019-11-02 16:02:53

I received some very good feedback on my last post: Scala has some popular libraries that should be avoided. Not only that, I learned a few libraries I considered before required more investigation. Today I want to look at Circe. After working in Scala a bit, I understand the problems it wants to solve and why the project makes the choices it does.

# Cursors

Think about how you use JSON for a minute. Programs retrieve or assign to a single field at a time. Parsing the entire document when the program only needs one field wastes processing time and heap memory.

```javascript
car["age"] = 23
console.log(car["age"])
```

When I wrote more NodeJS I would not bat an eye at parsing one document entirely, but when working with many documents or a large document I would use [JSONStream](https://www.npmjs.com/package/JSONStream) to selectively parse items out of the document. This provides two benefits: it does not require storing the entire document into memory and only the pertinent fields parse.

Circe provides "cursors", an API to traverse raw JSON and project the values therein. Think about cursors the way you think about the blinking `|` cursor when writing an email or text. It keeps track of your place in the document, moves around the document to track the new current location, and even selects interesting text for modification.


# Example

I'm assuming some `sbt` knowledge. Here's the `build.sbt` I used to run this project.

```scala
name := "basic_json"

version := "0.1"

scalaVersion := "2.12.2"

lazy val circeVersion = "0.12.2"


libraryDependencies ++= Seq(
  "io.circe" %% "circe-parser" % circeVersion,
  "io.circe" %% "circe-core" % circeVersion,
  "io.circe" %% "circe-generic" % circeVersion
)
```
This example iterates through a JSON document via a cursor to select and present the car's age the document describes.


```scala
import io.circe.parser._
object Main extends App {
  val rawJson: String =
    """
      |{
      |  "hello": "world",
      |  "car": {
      |    "type": "honda",
      |    "age": 23,
      |    "color": "blue",
      |    "used": true,
      |    "owner": {
      |       "name": "darwin",
      |       "age": 43
      |    }
      |  }
      |}
      |""".stripMargin

  val parsed = parse(rawJson) match {
    case Left(s) => s
    case Right(r) => r.hcursor.downField("car").get[Int]("age") match {
      case Right(age) => age
      case Left(l) => l
    }
  }

  println(parsed)

}
```

A lot going on, but focusing on the critical area simplifies things:

```scala
  val parsed = parse(rawJson) match {
    case Left(s) => s
    case Right(r) => r.hcursor.downField("car").get[Int]("age") match {
      case Right(age) => age
      case Left(l) => l
    }
  }
```

Circe's [`parse`](https://circe.github.io/circe/api/io/circe/Parser.html) from `import io.circe.parser._` ingests the raw JSON document and returns an [`Either`](https://www.scala-lang.org/api/current/scala/util/Either.html). `Left` contains useful information about failures, while `Right` contains success values. I always return the unwrapped `Left` value since I just want to log results, but ideally `Lefts` would branch code into an error handling branch.

Finally, the important piece: actually retrieving the data.

```scala
r.hcursor.downField("car").get[Int]("age")
```

`r` represents the `Right` result of `parse` which contains an `hcursor` into the JSON document. [`HCursors`](https://circe.github.io/circe/api/io/circe/HCursor.html) maintain a cursor's history so relevant history may surface during an error indicating why the cursor operation failed.

`downField("x")` moves the cursor's position into the `JSON` object specified by `"x"`. Very similar to how JavaScript accesses object via `obj["x"]`. `get[Type]("field")` performs a `downField` to the `"field"` key, parses the `JSON` object at that point, and then casts it to the type specified. In my case I cast the `"age"` field to an `Int`. Casting tells Scala to take an object it thought was text and convert it into a Scala object like an `Int`.

# Conclusion

Scala definitely requires more thought when working with JSON. While Circe's techniques seem radically different from Javascript at first glance; these languages really have a lot in common. As an exercise try triggering different `Left` branches to see the messages they produce.